summaryrefslogtreecommitdiff
path: root/chromium/net/third_party/quiche/src/quic/core
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/net/third_party/quiche/src/quic/core')
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/chlo_extractor_test.cc135
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.cc33
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.cc37
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.h22
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_bw.cc30
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_sender.cc33
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_sender.h6
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_simulator_test.cc23
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_startup.cc4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_startup.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.cc54
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.h4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender_test.cc5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.cc25
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.h21
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm_test.cc25
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/loss_detection_interface.h24
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/pacing_sender.h8
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/pacing_sender_test.cc88
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/rtt_stats.h4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.cc7
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.h3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/tcp_cubic_sender_bytes.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm.cc33
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm.h22
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm_test.cc32
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view.cc267
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view.h53
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view_der_fuzzer.cc15
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view_pem_fuzzer.cc18
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view_test.cc192
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.cc12
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h24
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/crypto_server_test.cc4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/curve25519_key_exchange.cc1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/p256_key_exchange.cc1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/proof_source.h51
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/proof_source_x509.cc135
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/proof_source_x509.h76
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/proof_source_x509_test.cc136
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/proof_verifier.h1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.h25
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.cc39
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h7
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config_test.cc4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/tls_connection.cc14
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/tls_server_connection.cc56
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/tls_server_connection.h66
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.cc350
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.h26
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters_test.cc363
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frame.cc7
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frame.h10
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_blocked_frame.cc4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_blocked_frame.h9
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_connection_close_frame.cc31
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_connection_close_frame.h44
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_crypto_frame.cc5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_crypto_frame.h10
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_frames_test.cc18
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_goaway_frame.cc6
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_goaway_frame.h9
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_handshake_done_frame.cc3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_handshake_done_frame.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_max_streams_frame.cc5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_max_streams_frame.h6
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_message_frame.cc3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_message_frame.h8
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_new_connection_id_frame.cc6
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_new_connection_id_frame.h10
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_new_token_frame.cc4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_new_token_frame.h5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_padding_frame.h6
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_path_challenge_frame.cc4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_path_challenge_frame.h8
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_path_response_frame.cc4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_path_response_frame.h8
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_ping_frame.cc3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_ping_frame.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_retire_connection_id_frame.cc4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_retire_connection_id_frame.h7
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_rst_stream_frame.cc17
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_rst_stream_frame.h31
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_stop_sending_frame.cc6
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_stop_sending_frame.h9
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_stream_frame.cc3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_stream_frame.h12
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_streams_blocked_frame.cc4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_streams_blocked_frame.h4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_window_update_frame.cc4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_window_update_frame.h5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/end_to_end_test.cc569
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/http_constants.h3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/http_decoder.cc45
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/http_decoder.h7
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/http_decoder_test.cc146
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_client_promised_info_test.cc20
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_client_push_promise_index_test.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_header_list.cc4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_headers_stream_test.cc136
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream.cc12
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base.cc13
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base_test.cc40
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session.cc15
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.cc27
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.h11
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_test.cc226
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream_test.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_server_stream_base_test.cc3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.cc87
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.h21
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session_test.cc125
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.cc37
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.h4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_test.cc210
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager.cc40
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager.h28
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager_test.cc16
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator.cc9
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator_test.cc13
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_receiver_test.cc14
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.cc18
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_receiver_test.cc26
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.cc6
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.h6
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender_test.cc54
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test.cc43
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table_test.cc4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder_test.cc10
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_alarm_test.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_arena_scoped_ptr_test.cc6
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_buffered_packet_store.cc52
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_buffered_packet_store.h26
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_buffered_packet_store_test.cc59
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_circular_deque.h11
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_coalesced_packet.cc3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_coalesced_packet.h6
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_config.cc621
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_config.h297
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_config_test.cc222
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_connection.cc447
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_connection.h98
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.h3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_connection_test.cc1110
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_constants.h9
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager.cc3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.h8
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker_test.cc20
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.cc20
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h29
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream_test.cc91
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.cc8
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_base.cc4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_test.cc84
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.cc108
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.h11
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream_test.cc43
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.cc147
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.h28
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_dispatcher_test.cc540
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_error_codes.cc540
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_error_codes.h144
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_error_codes_test.cc73
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_flow_controller.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_flow_controller_test.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_framer.cc121
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_framer.h17
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_framer_test.cc141
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_idle_network_detector_test.cc4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_network_blackhole_detector_test.cc4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_one_block_arena.h5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_one_block_arena_test.cc10
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.cc78
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.h28
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_packet_creator_test.cc269
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_packet_writer.h4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_packets.cc75
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_packets.h38
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_packets_test.cc4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.cc103
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h11
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager_test.cc319
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_session.cc397
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_session.h113
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_session_test.cc122
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_stream.cc156
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_stream.h41
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager.cc96
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager.h85
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager_test.cc80
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer.h1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_buffer.h5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_test.cc15
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_stream_test.cc64
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_time.h4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.cc22
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.h4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager_test.cc46
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_types.cc516
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_types.h138
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_types_test.cc61
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_version_manager.cc30
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_version_manager.h18
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_version_manager_test.cc45
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_versions.cc43
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_versions.h30
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_versions_test.cc101
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list.h7
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_chlo_extractor.cc395
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_chlo_extractor.h238
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_chlo_extractor_test.cc157
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.cc197
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.h30
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker_test.cc455
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_handshaker_test.cc290
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.cc169
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.h43
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker_test.cc467
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.cc11
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.h3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager_test.cc25
223 files changed, 10835 insertions, 5015 deletions
diff --git a/chromium/net/third_party/quiche/src/quic/core/chlo_extractor_test.cc b/chromium/net/third_party/quiche/src/quic/core/chlo_extractor_test.cc
index e293902faad..1b6a6164234 100644
--- a/chromium/net/third_party/quiche/src/quic/core/chlo_extractor_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/chlo_extractor_test.cc
@@ -12,6 +12,7 @@
#include "net/third_party/quiche/src/quic/core/quic_utils.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/first_flight.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_arraysize.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
@@ -32,50 +33,54 @@ class TestDelegate : public ChloExtractor::Delegate {
version_ = version;
connection_id_ = connection_id;
chlo_ = chlo.DebugString();
+ quiche::QuicheStringPiece alpn_value;
+ if (chlo.GetStringPiece(kALPN, &alpn_value)) {
+ alpn_ = std::string(alpn_value);
+ }
}
QuicConnectionId connection_id() const { return connection_id_; }
QuicTransportVersion transport_version() const { return version_; }
const std::string& chlo() const { return chlo_; }
+ const std::string& alpn() const { return alpn_; }
private:
QuicConnectionId connection_id_;
QuicTransportVersion version_;
std::string chlo_;
+ std::string alpn_;
};
-class ChloExtractorTest : public QuicTest {
+class ChloExtractorTest : public QuicTestWithParam<ParsedQuicVersion> {
public:
- ChloExtractorTest() {
- header_.destination_connection_id = TestConnectionId();
- header_.destination_connection_id_included = CONNECTION_ID_PRESENT;
- header_.version_flag = true;
- header_.version = AllSupportedVersions().front();
- header_.reset_flag = false;
- header_.packet_number_length = PACKET_4BYTE_PACKET_NUMBER;
- header_.packet_number = QuicPacketNumber(1);
- if (QuicVersionHasLongHeaderLengths(header_.version.transport_version)) {
- header_.retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_1;
- header_.length_length = VARIABLE_LENGTH_INTEGER_LENGTH_2;
- }
- }
+ ChloExtractorTest() : version_(GetParam()) {}
- void MakePacket(ParsedQuicVersion version,
- quiche::QuicheStringPiece data,
+ void MakePacket(quiche::QuicheStringPiece data,
bool munge_offset,
bool munge_stream_id) {
+ QuicPacketHeader header;
+ header.destination_connection_id = TestConnectionId();
+ header.destination_connection_id_included = CONNECTION_ID_PRESENT;
+ header.version_flag = true;
+ header.version = version_;
+ header.reset_flag = false;
+ header.packet_number_length = PACKET_4BYTE_PACKET_NUMBER;
+ header.packet_number = QuicPacketNumber(1);
+ if (version_.HasLongHeaderLengths()) {
+ header.retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_1;
+ header.length_length = VARIABLE_LENGTH_INTEGER_LENGTH_2;
+ }
QuicFrames frames;
size_t offset = 0;
if (munge_offset) {
offset++;
}
- QuicFramer framer(SupportedVersions(header_.version), QuicTime::Zero(),
+ QuicFramer framer(SupportedVersions(version_), QuicTime::Zero(),
Perspective::IS_CLIENT, kQuicDefaultConnectionIdLength);
framer.SetInitialObfuscators(TestConnectionId());
- if (!QuicVersionUsesCryptoFrames(version.transport_version) ||
- munge_stream_id) {
+ if (!version_.UsesCryptoFrames() || munge_stream_id) {
QuicStreamId stream_id =
- QuicUtils::GetCryptoStreamId(version.transport_version);
+ QuicUtils::GetCryptoStreamId(version_.transport_version);
if (munge_stream_id) {
stream_id++;
}
@@ -86,11 +91,11 @@ class ChloExtractorTest : public QuicTest {
QuicFrame(new QuicCryptoFrame(ENCRYPTION_INITIAL, offset, data)));
}
std::unique_ptr<QuicPacket> packet(
- BuildUnsizedDataPacket(&framer, header_, frames));
+ BuildUnsizedDataPacket(&framer, header, frames));
EXPECT_TRUE(packet != nullptr);
size_t encrypted_length =
- framer.EncryptPayload(ENCRYPTION_INITIAL, header_.packet_number,
- *packet, buffer_, QUICHE_ARRAYSIZE(buffer_));
+ framer.EncryptPayload(ENCRYPTION_INITIAL, header.packet_number, *packet,
+ buffer_, QUICHE_ARRAYSIZE(buffer_));
ASSERT_NE(0u, encrypted_length);
packet_ = std::make_unique<QuicEncryptedPacket>(buffer_, encrypted_length);
EXPECT_TRUE(packet_ != nullptr);
@@ -98,79 +103,77 @@ class ChloExtractorTest : public QuicTest {
}
protected:
+ ParsedQuicVersion version_;
TestDelegate delegate_;
- QuicPacketHeader header_;
std::unique_ptr<QuicEncryptedPacket> packet_;
char buffer_[kMaxOutgoingPacketSize];
};
-TEST_F(ChloExtractorTest, FindsValidChlo) {
+INSTANTIATE_TEST_SUITE_P(
+ ChloExtractorTests,
+ ChloExtractorTest,
+ ::testing::ValuesIn(AllSupportedVersionsWithQuicCrypto()),
+ ::testing::PrintToStringParamName());
+
+TEST_P(ChloExtractorTest, FindsValidChlo) {
CryptoHandshakeMessage client_hello;
client_hello.set_tag(kCHLO);
std::string client_hello_str(client_hello.GetSerialized().AsStringPiece());
- // Construct a CHLO with each supported version
- for (ParsedQuicVersion version : AllSupportedVersions()) {
- SCOPED_TRACE(version);
- header_.version = version;
- if (QuicVersionHasLongHeaderLengths(version.transport_version) &&
- header_.version_flag) {
- header_.retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_1;
- header_.length_length = VARIABLE_LENGTH_INTEGER_LENGTH_2;
- } else {
- header_.retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_0;
- header_.length_length = VARIABLE_LENGTH_INTEGER_LENGTH_0;
- }
- MakePacket(version, client_hello_str, /*munge_offset*/ false,
- /*munge_stream_id*/ false);
- EXPECT_TRUE(ChloExtractor::Extract(*packet_, version, {}, &delegate_,
- kQuicDefaultConnectionIdLength))
- << ParsedQuicVersionToString(version);
- EXPECT_EQ(version.transport_version, delegate_.transport_version());
- EXPECT_EQ(header_.destination_connection_id, delegate_.connection_id());
- EXPECT_EQ(client_hello.DebugString(), delegate_.chlo())
- << ParsedQuicVersionToString(version);
- }
+
+ MakePacket(client_hello_str, /*munge_offset=*/false,
+ /*munge_stream_id=*/false);
+ EXPECT_TRUE(ChloExtractor::Extract(*packet_, version_, {}, &delegate_,
+ kQuicDefaultConnectionIdLength));
+ EXPECT_EQ(version_.transport_version, delegate_.transport_version());
+ EXPECT_EQ(TestConnectionId(), delegate_.connection_id());
+ EXPECT_EQ(client_hello.DebugString(), delegate_.chlo());
}
-TEST_F(ChloExtractorTest, DoesNotFindValidChloOnWrongStream) {
- ParsedQuicVersion version = AllSupportedVersions()[0];
- if (QuicVersionUsesCryptoFrames(version.transport_version)) {
+TEST_P(ChloExtractorTest, DoesNotFindValidChloOnWrongStream) {
+ if (version_.UsesCryptoFrames()) {
+ // When crypto frames are in use we do not use stream frames.
return;
}
CryptoHandshakeMessage client_hello;
client_hello.set_tag(kCHLO);
std::string client_hello_str(client_hello.GetSerialized().AsStringPiece());
- MakePacket(version, client_hello_str,
- /*munge_offset*/ false, /*munge_stream_id*/ true);
- EXPECT_FALSE(ChloExtractor::Extract(*packet_, version, {}, &delegate_,
+ MakePacket(client_hello_str,
+ /*munge_offset=*/false, /*munge_stream_id=*/true);
+ EXPECT_FALSE(ChloExtractor::Extract(*packet_, version_, {}, &delegate_,
kQuicDefaultConnectionIdLength));
}
-TEST_F(ChloExtractorTest, DoesNotFindValidChloOnWrongOffset) {
- ParsedQuicVersion version = AllSupportedVersions()[0];
+TEST_P(ChloExtractorTest, DoesNotFindValidChloOnWrongOffset) {
CryptoHandshakeMessage client_hello;
client_hello.set_tag(kCHLO);
std::string client_hello_str(client_hello.GetSerialized().AsStringPiece());
- MakePacket(version, client_hello_str, /*munge_offset*/ true,
- /*munge_stream_id*/ false);
- EXPECT_FALSE(ChloExtractor::Extract(*packet_, version, {}, &delegate_,
+ MakePacket(client_hello_str, /*munge_offset=*/true,
+ /*munge_stream_id=*/false);
+ EXPECT_FALSE(ChloExtractor::Extract(*packet_, version_, {}, &delegate_,
kQuicDefaultConnectionIdLength));
}
-TEST_F(ChloExtractorTest, DoesNotFindInvalidChlo) {
- ParsedQuicVersion version = AllSupportedVersions()[0];
- if (QuicVersionUsesCryptoFrames(version.transport_version)) {
- return;
- }
- MakePacket(version, "foo", /*munge_offset*/ false,
- /*munge_stream_id*/ true);
- EXPECT_FALSE(ChloExtractor::Extract(*packet_, version, {}, &delegate_,
+TEST_P(ChloExtractorTest, DoesNotFindInvalidChlo) {
+ MakePacket("foo", /*munge_offset=*/false,
+ /*munge_stream_id=*/false);
+ EXPECT_FALSE(ChloExtractor::Extract(*packet_, version_, {}, &delegate_,
kQuicDefaultConnectionIdLength));
}
+TEST_P(ChloExtractorTest, FirstFlight) {
+ std::vector<std::unique_ptr<QuicReceivedPacket>> packets =
+ GetFirstFlightOfPackets(version_);
+ ASSERT_EQ(packets.size(), 1u);
+ EXPECT_TRUE(ChloExtractor::Extract(*packets[0], version_, {}, &delegate_,
+ kQuicDefaultConnectionIdLength));
+ EXPECT_EQ(version_.transport_version, delegate_.transport_version());
+ EXPECT_EQ(TestConnectionId(), delegate_.connection_id());
+ EXPECT_EQ(AlpnForVersion(version_), delegate_.alpn());
+}
+
} // namespace
} // namespace test
} // namespace quic
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 c929e8b55cc..f885c94794c 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
@@ -382,14 +382,15 @@ BandwidthSample BandwidthSampler::OnPacketAcknowledgedInner(
} else {
QUIC_CODE_COUNT_N(quic_prev_ack_time_larger_than_current_ack_time, 2, 2);
}
- QUIC_BUG << "Time of the previously acked packet:"
- << a0.ack_time.ToDebuggingValue()
- << " is larger than the ack time of the current packet:"
- << ack_time.ToDebuggingValue()
- << ". acked packet number:" << packet_number
- << ", total_bytes_acked_:" << total_bytes_acked_
- << ", overestimate_avoidance_:" << overestimate_avoidance_
- << ", sent_packet:" << sent_packet;
+ QUIC_LOG_EVERY_N_SEC(ERROR, 60)
+ << "Time of the previously acked packet:"
+ << a0.ack_time.ToDebuggingValue()
+ << " is larger than the ack time of the current packet:"
+ << ack_time.ToDebuggingValue()
+ << ". acked packet number:" << packet_number
+ << ", total_bytes_acked_:" << total_bytes_acked_
+ << ", overestimate_avoidance_:" << overestimate_avoidance_
+ << ", sent_packet:" << sent_packet;
return BandwidthSample();
}
QuicBandwidth ack_rate = QuicBandwidth::FromBytesAndTimeDelta(
@@ -403,13 +404,15 @@ BandwidthSample BandwidthSampler::OnPacketAcknowledgedInner(
sample.rtt = ack_time - sent_packet.sent_time;
SentPacketToSendTimeState(sent_packet, &sample.state_at_send);
- QUIC_BUG_IF(sample.bandwidth.IsZero())
- << "ack_rate: " << ack_rate << ", send_rate: " << send_rate
- << ". acked packet number:" << packet_number
- << ", overestimate_avoidance_:" << overestimate_avoidance_ << "a1:{"
- << total_bytes_acked_ << "@" << ack_time << "}, a0:{"
- << a0.total_bytes_acked << "@" << a0.ack_time
- << "}, sent_packet:" << sent_packet;
+ if (sample.bandwidth.IsZero()) {
+ QUIC_LOG_EVERY_N_SEC(ERROR, 60)
+ << "ack_rate: " << ack_rate << ", send_rate: " << send_rate
+ << ". acked packet number:" << packet_number
+ << ", overestimate_avoidance_:" << overestimate_avoidance_ << "a1:{"
+ << total_bytes_acked_ << "@" << ack_time << "}, a0:{"
+ << a0.total_bytes_acked << "@" << a0.ack_time
+ << "}, sent_packet:" << sent_packet;
+ }
return sample;
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.cc
index 5a3046794be..90df9a0c0da 100644
--- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.cc
@@ -60,9 +60,7 @@ Bbr2NetworkModel::Bbr2NetworkModel(const Bbr2Params* params,
: params_(params),
bandwidth_sampler_([](QuicRoundTripCount max_height_tracker_window_length,
const BandwidthSampler* old_sampler) {
- if (GetQuicReloadableFlag(quic_bbr_copy_sampler_state_from_v1_to_v2) &&
- old_sampler != nullptr) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_bbr_copy_sampler_state_from_v1_to_v2);
+ if (old_sampler != nullptr) {
return BandwidthSampler(*old_sampler);
}
return BandwidthSampler(/*unacked_packet_map=*/nullptr,
@@ -111,10 +109,8 @@ void Bbr2NetworkModel::OnCongestionEventStart(
// Avoid updating |max_bandwidth_filter_| if a) this is a loss-only event, or
// b) all packets in |acked_packets| did not generate valid samples. (e.g. ack
// of ack-only packets). In both cases, total_bytes_acked() will not change.
- if (!fix_zero_bw_on_loss_only_event_ ||
- (prior_bytes_acked != total_bytes_acked())) {
- QUIC_BUG_IF((prior_bytes_acked != total_bytes_acked()) &&
- sample.sample_max_bandwidth.IsZero())
+ if (prior_bytes_acked != total_bytes_acked()) {
+ QUIC_BUG_IF(sample.sample_max_bandwidth.IsZero())
<< total_bytes_acked() - prior_bytes_acked << " bytes from "
<< acked_packets.size()
<< " packets have been acked, but sample_max_bandwidth is zero.";
@@ -123,14 +119,6 @@ void Bbr2NetworkModel::OnCongestionEventStart(
congestion_event->sample_max_bandwidth = sample.sample_max_bandwidth;
max_bandwidth_filter_.Update(congestion_event->sample_max_bandwidth);
}
- } else {
- if (acked_packets.empty()) {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr_fix_zero_bw_on_loss_only_event, 3,
- 4);
- } else {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr_fix_zero_bw_on_loss_only_event, 4,
- 4);
- }
}
if (!sample.sample_rtt.IsInfinite()) {
@@ -196,15 +184,17 @@ void Bbr2NetworkModel::AdaptLowerBounds(
if (bandwidth_lo_.IsInfinite()) {
bandwidth_lo_ = MaxBandwidth();
}
- if (inflight_lo_ == inflight_lo_default()) {
- inflight_lo_ = congestion_event.prior_cwnd;
- }
-
bandwidth_lo_ =
std::max(bandwidth_latest_, bandwidth_lo_ * (1.0 - Params().beta));
QUIC_DVLOG(3) << "bandwidth_lo_ updated to " << bandwidth_lo_
<< ", bandwidth_latest_ is " << bandwidth_latest_;
+ if (Params().ignore_inflight_lo) {
+ return;
+ }
+ if (inflight_lo_ == inflight_lo_default()) {
+ inflight_lo_ = congestion_event.prior_cwnd;
+ }
inflight_lo_ = std::max<QuicByteCount>(
inflight_latest_, inflight_lo_ * (1.0 - Params().beta));
}
@@ -292,6 +282,15 @@ void Bbr2NetworkModel::RestartRound() {
round_trip_counter_.RestartRound();
}
+void Bbr2NetworkModel::cap_inflight_lo(QuicByteCount cap) {
+ if (Params().ignore_inflight_lo) {
+ return;
+ }
+ if (inflight_lo_ != inflight_lo_default() && inflight_lo_ > cap) {
+ inflight_lo_ = cap;
+ }
+}
+
QuicByteCount Bbr2NetworkModel::inflight_hi_with_headroom() const {
QuicByteCount headroom = inflight_hi_ * Params().inflight_hi_headroom;
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 63a11e14681..e110a4c3297 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
@@ -77,7 +77,8 @@ struct QUIC_EXPORT_PRIVATE Bbr2Params {
// The gain for both CWND and PacingRate at startup.
// TODO(wub): Maybe change to the newly derived value of 2.773 (4 * ln(2)).
- float startup_gain = 2.885;
+ float startup_cwnd_gain = 2.885;
+ float startup_pacing_gain = 2.885;
// Full bandwidth is declared if the total bandwidth growth is less than
// |startup_full_bw_threshold| times in the last |startup_full_bw_rounds|
@@ -175,8 +176,14 @@ struct QUIC_EXPORT_PRIVATE Bbr2Params {
GetQuicReloadableFlag(quic_bbr2_add_ack_height_to_queueing_threshold);
// Can be disabled by connection option 'B2RP'.
- bool avoid_unnecessary_probe_rtt =
- GetQuicReloadableFlag(quic_bbr2_avoid_unnecessary_probe_rtt);
+ bool avoid_unnecessary_probe_rtt = true;
+
+ // Can be disabled by connection option 'B2CL'.
+ bool avoid_too_low_probe_bw_cwnd =
+ GetQuicReloadableFlag(quic_bbr2_avoid_too_low_probe_bw_cwnd);
+
+ // Can be enabled by connection option 'B2LO'.
+ bool ignore_inflight_lo = false;
};
class QUIC_EXPORT_PRIVATE RoundTripCounter {
@@ -420,11 +427,7 @@ class QUIC_EXPORT_PRIVATE Bbr2NetworkModel {
return std::numeric_limits<QuicByteCount>::max();
}
void clear_inflight_lo() { inflight_lo_ = inflight_lo_default(); }
- void cap_inflight_lo(QuicByteCount cap) {
- if (inflight_lo_ != inflight_lo_default() && inflight_lo_ > cap) {
- inflight_lo_ = cap;
- }
- }
+ void cap_inflight_lo(QuicByteCount cap);
QuicByteCount inflight_hi_with_headroom() const;
QuicByteCount inflight_hi() const { return inflight_hi_; }
@@ -472,9 +475,6 @@ class QUIC_EXPORT_PRIVATE Bbr2NetworkModel {
float cwnd_gain_;
float pacing_gain_;
-
- const bool fix_zero_bw_on_loss_only_event_ =
- GetQuicReloadableFlag(quic_bbr_fix_zero_bw_on_loss_only_event);
};
enum class Bbr2Mode : uint8_t {
diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_bw.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_bw.cc
index 1a7a7193a16..6fb7eee8059 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
@@ -79,12 +79,36 @@ Bbr2Mode Bbr2ProbeBwMode::OnCongestionEvent(
}
Limits<QuicByteCount> Bbr2ProbeBwMode::GetCwndLimits() const {
- if (cycle_.phase == CyclePhase::PROBE_CRUISE) {
+ if (!GetQuicReloadableFlag(quic_bbr2_avoid_too_low_probe_bw_cwnd)) {
+ if (cycle_.phase == CyclePhase::PROBE_CRUISE) {
+ return NoGreaterThan(
+ std::min(model_->inflight_lo(), model_->inflight_hi_with_headroom()));
+ }
+
return NoGreaterThan(
- std::min(model_->inflight_lo(), model_->inflight_hi_with_headroom()));
+ std::min(model_->inflight_lo(), model_->inflight_hi()));
+ }
+
+ QUIC_RELOADABLE_FLAG_COUNT(quic_bbr2_avoid_too_low_probe_bw_cwnd);
+
+ QuicByteCount upper_limit =
+ std::min(model_->inflight_lo(), cycle_.phase == CyclePhase::PROBE_CRUISE
+ ? model_->inflight_hi_with_headroom()
+ : model_->inflight_hi());
+
+ if (Params().avoid_too_low_probe_bw_cwnd) {
+ // Ensure upper_limit is at least BDP + AckHeight.
+ QuicByteCount bdp_with_ack_height =
+ model_->BDP(model_->MaxBandwidth()) + model_->MaxAckHeight();
+ if (upper_limit < bdp_with_ack_height) {
+ QUIC_DVLOG(3) << sender_ << " Rasing upper_limit from " << upper_limit
+ << " to " << bdp_with_ack_height;
+ QUIC_CODE_COUNT(quic_bbr2_avoid_too_low_probe_bw_cwnd_in_effect);
+ upper_limit = bdp_with_ack_height;
+ }
}
- return NoGreaterThan(std::min(model_->inflight_lo(), model_->inflight_hi()));
+ return NoGreaterThan(upper_limit);
}
bool Bbr2ProbeBwMode::IsProbingForBandwidth() const {
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 4d794432ec4..8c0171bc9bf 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
@@ -108,6 +108,37 @@ void Bbr2Sender::SetFromConfig(const QuicConfig& config,
if (config.HasClientRequestedIndependentOption(kB2RP, perspective)) {
params_.avoid_unnecessary_probe_rtt = false;
}
+ if (GetQuicReloadableFlag(quic_bbr2_avoid_too_low_probe_bw_cwnd) &&
+ config.HasClientRequestedIndependentOption(kB2CL, perspective)) {
+ params_.avoid_too_low_probe_bw_cwnd = false;
+ }
+ if (GetQuicReloadableFlag(quic_bbr2_fewer_startup_round_trips) &&
+ config.HasClientRequestedIndependentOption(k1RTT, perspective)) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr2_fewer_startup_round_trips, 1, 2);
+ params_.startup_full_bw_rounds = 1;
+ }
+ if (GetQuicReloadableFlag(quic_bbr2_fewer_startup_round_trips) &&
+ config.HasClientRequestedIndependentOption(k2RTT, perspective)) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr2_fewer_startup_round_trips, 2, 2);
+ params_.startup_full_bw_rounds = 2;
+ }
+ if (GetQuicReloadableFlag(quic_bbr2_ignore_inflight_lo) &&
+ config.HasClientRequestedIndependentOption(kB2LO, perspective)) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_bbr2_ignore_inflight_lo);
+ params_.ignore_inflight_lo = true;
+ }
+
+ ApplyConnectionOptions(config.ClientRequestedIndependentOptions(perspective));
+}
+
+void Bbr2Sender::ApplyConnectionOptions(
+ const QuicTagVector& connection_options) {
+ if (GetQuicReloadableFlag(quic_bbr2_lower_startup_cwnd_gain) &&
+ ContainsQuicTag(connection_options, kBBQ2)) {
+ // 2 is the lower, derived gain for CWND.
+ params_.startup_cwnd_gain = 2;
+ params_.drain_cwnd_gain = 2;
+ }
}
Limits<QuicByteCount> Bbr2Sender::GetCwndLimitsByMode() const {
@@ -206,7 +237,6 @@ void Bbr2Sender::OnCongestionEvent(bool /*rtt_updated*/,
last_sample_is_app_limited_ = congestion_event.last_sample_is_app_limited;
if (congestion_event.bytes_in_flight == 0 &&
params().avoid_unnecessary_probe_rtt) {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr2_avoid_unnecessary_probe_rtt, 2, 2);
OnEnterQuiescence(event_time);
}
@@ -301,7 +331,6 @@ void Bbr2Sender::OnPacketSent(QuicTime sent_time,
<< ", total_lost:" << model_.total_bytes_lost() << " @ "
<< sent_time;
if (bytes_in_flight == 0 && params().avoid_unnecessary_probe_rtt) {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr2_avoid_unnecessary_probe_rtt, 1, 2);
OnExitQuiescence(sent_time);
}
model_.OnPacketSent(sent_time, bytes_in_flight, packet_number, bytes,
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 d68a6a13265..60824cdbd4b 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
@@ -50,6 +50,8 @@ class QUIC_EXPORT_PRIVATE Bbr2Sender final : public SendAlgorithmInterface {
void SetFromConfig(const QuicConfig& config,
Perspective perspective) override;
+ void ApplyConnectionOptions(const QuicTagVector& connection_options) override;
+
void AdjustNetworkParameters(const NetworkParams& params) override;
void SetInitialCongestionWindowInPackets(
@@ -173,8 +175,8 @@ class QUIC_EXPORT_PRIVATE Bbr2Sender final : public SendAlgorithmInterface {
QuicRandom* random_;
QuicConnectionStats* connection_stats_;
- // Don't use it directly outside of SetFromConfig. Instead, use params() to
- // get read-only access.
+ // Don't use it directly outside of SetFromConfig and ApplyConnectionOptions.
+ // Instead, use params() to get read-only access.
Bbr2Params params_;
Bbr2NetworkModel model_;
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 949b2834e89..f803ab68cdf 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
@@ -890,11 +890,8 @@ TEST_F(Bbr2DefaultTopologyTest, ProbeRttAfterQuiescenceImmediatelyExits) {
sender_->OnPacketSent(SimulatedNow(), /*bytes_in_flight=*/0,
sender_unacked_map()->largest_sent_packet() + 1,
kDefaultMaxPacketSize, HAS_RETRANSMITTABLE_DATA);
- if (GetQuicReloadableFlag(quic_bbr2_avoid_unnecessary_probe_rtt)) {
- EXPECT_EQ(sender_->ExportDebugState().mode, Bbr2Mode::PROBE_BW);
- } else {
- EXPECT_EQ(sender_->ExportDebugState().mode, Bbr2Mode::PROBE_RTT);
- }
+
+ EXPECT_EQ(sender_->ExportDebugState().mode, Bbr2Mode::PROBE_BW);
}
TEST_F(Bbr2DefaultTopologyTest, ProbeBwAfterQuiescencePostponeMinRttTimestamp) {
@@ -921,7 +918,7 @@ TEST_F(Bbr2DefaultTopologyTest, ProbeBwAfterQuiescencePostponeMinRttTimestamp) {
// Wait for entering a quiescence of 15 seconds.
ASSERT_TRUE(simulator_.RunUntilOrTimeout(
[this]() { return sender_unacked_map()->bytes_in_flight() == 0; },
- params.RTT()));
+ params.RTT() + timeout));
simulator_.RunFor(QuicTime::Delta::FromSeconds(15));
@@ -929,19 +926,13 @@ TEST_F(Bbr2DefaultTopologyTest, ProbeBwAfterQuiescencePostponeMinRttTimestamp) {
SendBursts(params, 1, kDefaultTCPMSS, QuicTime::Delta::Zero());
const QuicTime min_rtt_timestamp_after_idle =
sender_->ExportDebugState().min_rtt_timestamp;
- if (GetQuicReloadableFlag(quic_bbr2_avoid_unnecessary_probe_rtt)) {
- EXPECT_LT(min_rtt_timestamp_before_idle + QuicTime::Delta::FromSeconds(14),
- min_rtt_timestamp_after_idle);
- } else {
- EXPECT_EQ(min_rtt_timestamp_before_idle, min_rtt_timestamp_after_idle);
- }
+
+ EXPECT_LT(min_rtt_timestamp_before_idle + QuicTime::Delta::FromSeconds(14),
+ min_rtt_timestamp_after_idle);
}
// Regression test for http://shortn/_Jt1QWtshAM.
TEST_F(Bbr2DefaultTopologyTest, SwitchToBbr2MidConnection) {
- if (!GetQuicReloadableFlag(quic_bbr_copy_sampler_state_from_v1_to_v2)) {
- return;
- }
QuicTime now = QuicTime::Zero();
BbrSender old_sender(sender_connection()->clock()->Now(),
sender_connection()->sent_packet_manager().GetRttStats(),
@@ -1039,7 +1030,7 @@ TEST_F(Bbr2DefaultTopologyTest, SwitchToBbr2MidConnection) {
// Receiver
class MultiSenderTopologyParams {
public:
- static const size_t kNumLocalLinks = 8;
+ static constexpr size_t kNumLocalLinks = 8;
std::array<LinkParams, kNumLocalLinks> local_links = {
LinkParams(10000, 1987), LinkParams(10000, 1993), LinkParams(10000, 1997),
LinkParams(10000, 1999), LinkParams(10000, 2003), LinkParams(10000, 2011),
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 8514d2accbc..1141ca09e05 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
@@ -47,8 +47,8 @@ Bbr2Mode Bbr2StartupMode::OnCongestionEvent(
CheckExcessiveLosses(congestion_event);
- model_->set_pacing_gain(Params().startup_gain);
- model_->set_cwnd_gain(Params().startup_gain);
+ model_->set_pacing_gain(Params().startup_pacing_gain);
+ model_->set_cwnd_gain(Params().startup_cwnd_gain);
// TODO(wub): Maybe implement STARTUP => PROBE_RTT.
return full_bandwidth_reached_ ? Bbr2Mode::DRAIN : Bbr2Mode::STARTUP;
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 e8f37ff9b81..378a4fd83fd 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
@@ -33,6 +33,8 @@ class QUIC_EXPORT_PRIVATE Bbr2StartupMode final : public Bbr2ModeBase {
const Bbr2CongestionEvent& congestion_event) override;
Limits<QuicByteCount> GetCwndLimits() const override {
+ // Inflight_lo is never set in STARTUP.
+ DCHECK_EQ(Bbr2NetworkModel::inflight_lo_default(), model_->inflight_lo());
return NoGreaterThan(model_->inflight_lo());
}
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 8331611252d..f150ec14787 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
@@ -259,9 +259,6 @@ bool BbrSender::IsPipeSufficientlyFull() const {
void BbrSender::SetFromConfig(const QuicConfig& config,
Perspective perspective) {
- if (config.HasClientRequestedIndependentOption(kLRTT, perspective)) {
- exit_startup_on_loss_ = true;
- }
if (config.HasClientRequestedIndependentOption(k1RTT, perspective)) {
num_startup_rtts_ = 1;
}
@@ -303,10 +300,6 @@ void BbrSender::SetFromConfig(const QuicConfig& config,
set_high_cwnd_gain(kDerivedHighGain);
set_drain_gain(1.f / kDerivedHighGain);
}
- if (!exit_startup_on_loss_ &&
- config.HasClientRequestedIndependentOption(kBBQ2, perspective)) {
- set_high_cwnd_gain(kDerivedHighCWNDGain);
- }
if (config.HasClientRequestedIndependentOption(kBBQ3, perspective)) {
enable_ack_aggregation_during_startup_ = true;
}
@@ -327,6 +320,18 @@ void BbrSender::SetFromConfig(const QuicConfig& config,
quic_avoid_overestimate_bandwidth_with_aggregation, 3, 4);
sampler_.EnableOverestimateAvoidance();
}
+
+ ApplyConnectionOptions(config.ClientRequestedIndependentOptions(perspective));
+}
+
+void BbrSender::ApplyConnectionOptions(
+ const QuicTagVector& connection_options) {
+ if (ContainsQuicTag(connection_options, kLRTT)) {
+ exit_startup_on_loss_ = true;
+ }
+ if (ContainsQuicTag(connection_options, kBBQ2)) {
+ set_high_cwnd_gain(kDerivedHighCWNDGain);
+ }
}
void BbrSender::AdjustNetworkParameters(const NetworkParams& params) {
@@ -428,10 +433,8 @@ void BbrSender::OnCongestionEvent(bool /*rtt_updated*/,
// packets in |acked_packets| did not generate valid samples. (e.g. ack of
// ack-only packets). In both cases, sampler_.total_bytes_acked() will not
// change.
- if (!fix_zero_bw_on_loss_only_event_ ||
- (total_bytes_acked_before != sampler_.total_bytes_acked())) {
- QUIC_BUG_IF((total_bytes_acked_before != sampler_.total_bytes_acked()) &&
- sample.sample_max_bandwidth.IsZero())
+ if (total_bytes_acked_before != sampler_.total_bytes_acked()) {
+ QUIC_BUG_IF(sample.sample_max_bandwidth.IsZero())
<< sampler_.total_bytes_acked() - total_bytes_acked_before
<< " bytes from " << acked_packets.size()
<< " packets have been acked, but sample_max_bandwidth is zero.";
@@ -439,15 +442,8 @@ void BbrSender::OnCongestionEvent(bool /*rtt_updated*/,
sample.sample_max_bandwidth > max_bandwidth_.GetBest()) {
max_bandwidth_.Update(sample.sample_max_bandwidth, round_trip_count_);
}
- } else {
- if (acked_packets.empty()) {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr_fix_zero_bw_on_loss_only_event, 1,
- 4);
- } else {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr_fix_zero_bw_on_loss_only_event, 2,
- 4);
- }
}
+
if (!sample.sample_rtt.IsInfinite()) {
min_rtt_expired = MaybeUpdateMinRtt(event_time, sample.sample_rtt);
}
@@ -503,7 +499,16 @@ CongestionControlType BbrSender::GetCongestionControlType() const {
}
QuicTime::Delta BbrSender::GetMinRtt() const {
- return !min_rtt_.IsZero() ? min_rtt_ : rtt_stats_->initial_rtt();
+ if (!min_rtt_.IsZero()) {
+ return min_rtt_;
+ }
+ if (GetQuicReloadableFlag(quic_bbr_use_available_min_rtt)) {
+ // min_rtt could be available if the handshake packet gets neutered then
+ // gets acknowledged. This could only happen for QUIC crypto where we do not
+ // drop keys.
+ return rtt_stats_->MinOrInitialRtt();
+ }
+ return rtt_stats_->initial_rtt();
}
QuicByteCount BbrSender::GetTargetCongestionWindow(float gain) const {
@@ -920,16 +925,9 @@ void BbrSender::CalculateRecoveryWindow(QuicByteCount bytes_acked,
recovery_window_ += bytes_acked;
}
- // Sanity checks. Ensure that we always allow to send at least an MSS or
- // |bytes_acked| in response, whichever is larger.
+ // Always allow sending at least |bytes_acked| in response.
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);
- }
recovery_window_ = std::max(min_congestion_window_, recovery_window_);
}
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 ab5d8197419..c7285d76f24 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
@@ -106,6 +106,7 @@ class QUIC_EXPORT_PRIVATE BbrSender : public SendAlgorithmInterface {
void SetFromConfig(const QuicConfig& config,
Perspective perspective) override;
+ void ApplyConnectionOptions(const QuicTagVector& connection_options) override;
void AdjustNetworkParameters(const NetworkParams& params) override;
void SetInitialCongestionWindowInPackets(
@@ -390,9 +391,6 @@ class QUIC_EXPORT_PRIVATE BbrSender : public SendAlgorithmInterface {
// or it's time for high gain mode.
bool drain_to_target_;
- const bool fix_zero_bw_on_loss_only_event_ =
- GetQuicReloadableFlag(quic_bbr_fix_zero_bw_on_loss_only_event);
-
// True if network parameters are adjusted, and this will be reset if
// overshooting is detected and pacing rate gets slowed.
bool network_parameters_adjusted_;
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 e07931b8c79..e50a7c04c61 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
@@ -341,7 +341,6 @@ TEST_F(BbrSenderTest, SimpleTransferSmallBuffer) {
}
TEST_F(BbrSenderTest, RemoveBytesLostInRecovery) {
- SetQuicReloadableFlag(quic_bbr_one_mss_conservation, false);
// Disable Ack Decimation on the receiver, because it can increase srtt.
QuicConnectionPeer::SetAckMode(receiver_.connection(), AckMode::TCP_ACKING);
CreateDefaultSetup();
@@ -1372,9 +1371,7 @@ TEST_F(BbrSenderTest, LossOnlyCongestionEvent) {
lost_packets);
// Bandwidth estimate should not change for the loss only event.
- if (GetQuicReloadableFlag(quic_bbr_fix_zero_bw_on_loss_only_event)) {
- EXPECT_EQ(prior_bandwidth_estimate, sender_->BandwidthEstimate());
- }
+ EXPECT_EQ(prior_bandwidth_estimate, sender_->BandwidthEstimate());
}
} // namespace test
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 6c090136c1a..f00045e7b8e 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
@@ -15,7 +15,7 @@ namespace quic {
GeneralLossAlgorithm::GeneralLossAlgorithm()
: loss_detection_timeout_(QuicTime::Zero()),
reordering_shift_(kDefaultLossDelayShift),
- reordering_threshold_(kNumberOfNacksBeforeRetransmission),
+ reordering_threshold_(kDefaultPacketReorderingThreshold),
use_adaptive_reordering_threshold_(true),
use_adaptive_time_threshold_(false),
use_packet_threshold_for_runt_packets_(true),
@@ -23,15 +23,17 @@ GeneralLossAlgorithm::GeneralLossAlgorithm()
packet_number_space_(NUM_PACKET_NUMBER_SPACES) {}
// Uses nack counts to decide when packets are lost.
-void GeneralLossAlgorithm::DetectLosses(
+LossDetectionInterface::DetectionStats GeneralLossAlgorithm::DetectLosses(
const QuicUnackedPacketMap& unacked_packets,
QuicTime time,
const RttStats& rtt_stats,
QuicPacketNumber largest_newly_acked,
const AckedPacketVector& packets_acked,
LostPacketVector* packets_lost) {
+ DetectionStats detection_stats;
+
loss_detection_timeout_ = QuicTime::Zero();
- if (!packets_acked.empty() &&
+ if (!packets_acked.empty() && least_in_flight_.IsInitialized() &&
packets_acked.front().packet_number == least_in_flight_) {
if (packets_acked.back().packet_number == largest_newly_acked &&
least_in_flight_ + packets_acked.size() - 1 == largest_newly_acked) {
@@ -40,7 +42,7 @@ void GeneralLossAlgorithm::DetectLosses(
// do not use this optimization if largest_newly_acked is not the largest
// packet in packets_acked.
least_in_flight_ = largest_newly_acked + 1;
- return;
+ return detection_stats;
}
// There is hole in acked_packets, increment least_in_flight_ if possible.
for (const auto& acked : packets_acked) {
@@ -50,6 +52,7 @@ void GeneralLossAlgorithm::DetectLosses(
++least_in_flight_;
}
}
+
QuicTime::Delta max_rtt =
std::max(rtt_stats.previous_srtt(), rtt_stats.latest_rtt());
max_rtt = std::max(kAlarmGranularity, max_rtt);
@@ -77,19 +80,23 @@ void GeneralLossAlgorithm::DetectLosses(
// Skip packets of different packet number space.
continue;
}
+
if (!it->in_flight) {
continue;
}
+
+ if (largest_newly_acked - packet_number >
+ detection_stats.sent_packets_max_sequence_reordering) {
+ detection_stats.sent_packets_max_sequence_reordering =
+ largest_newly_acked - packet_number;
+ }
+
// Packet threshold loss detection.
// Skip packet threshold loss detection if largest_newly_acked is a runt.
const bool skip_packet_threshold_detection =
!use_packet_threshold_for_runt_packets_ &&
it->bytes_sent >
unacked_packets.GetTransmissionInfo(largest_newly_acked).bytes_sent;
- if (skip_packet_threshold_detection) {
- QUIC_RELOADABLE_FLAG_COUNT_N(
- quic_skip_packet_threshold_loss_detection_with_runt, 2, 2);
- }
if (!skip_packet_threshold_detection &&
largest_newly_acked - packet_number >= reordering_threshold_) {
packets_lost->push_back(LostPacket(packet_number, it->bytes_sent));
@@ -112,6 +119,8 @@ void GeneralLossAlgorithm::DetectLosses(
// There is no in flight packet.
least_in_flight_ = largest_newly_acked + 1;
}
+
+ return detection_stats;
}
QuicTime GeneralLossAlgorithm::GetLossTimeout() const {
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 7ab0d536eb7..ee8ba64c2d7 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
@@ -11,6 +11,7 @@
#include "net/third_party/quiche/src/quic/core/congestion_control/loss_detection_interface.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_types.h"
#include "net/third_party/quiche/src/quic/core/quic_unacked_packet_map.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
@@ -21,21 +22,21 @@ namespace quic {
// Also implements TCP's early retransmit(RFC5827).
class QUIC_EXPORT_PRIVATE GeneralLossAlgorithm : public LossDetectionInterface {
public:
- // TCP retransmits after 3 nacks.
- static const QuicPacketCount kNumberOfNacksBeforeRetransmission = 3;
-
GeneralLossAlgorithm();
GeneralLossAlgorithm(const GeneralLossAlgorithm&) = delete;
GeneralLossAlgorithm& operator=(const GeneralLossAlgorithm&) = delete;
~GeneralLossAlgorithm() override {}
+ void SetFromConfig(const QuicConfig& /*config*/,
+ Perspective /*perspective*/) override {}
+
// Uses |largest_acked| and time to decide when packets are lost.
- void DetectLosses(const QuicUnackedPacketMap& unacked_packets,
- QuicTime time,
- const RttStats& rtt_stats,
- QuicPacketNumber largest_newly_acked,
- const AckedPacketVector& packets_acked,
- LostPacketVector* packets_lost) override;
+ DetectionStats DetectLosses(const QuicUnackedPacketMap& unacked_packets,
+ QuicTime time,
+ const RttStats& rtt_stats,
+ QuicPacketNumber largest_newly_acked,
+ const AckedPacketVector& packets_acked,
+ LostPacketVector* packets_lost) override;
// Returns a non-zero value when the early retransmit timer is active.
QuicTime GetLossTimeout() const override;
@@ -66,6 +67,8 @@ class QUIC_EXPORT_PRIVATE GeneralLossAlgorithm : public LossDetectionInterface {
void Reset();
+ QuicPacketCount reordering_threshold() const { return reordering_threshold_; }
+
int reordering_shift() const { return reordering_shift_; }
void set_reordering_shift(int reordering_shift) {
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 7bef933b93f..1a58ade2695 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
@@ -61,12 +61,25 @@ class GeneralLossAlgorithmTest : public QuicTest {
void VerifyLosses(uint64_t largest_newly_acked,
const AckedPacketVector& packets_acked,
const std::vector<uint64_t>& losses_expected) {
+ return VerifyLosses(largest_newly_acked, packets_acked, losses_expected,
+ quiche::QuicheOptional<QuicPacketCount>());
+ }
+
+ void VerifyLosses(uint64_t largest_newly_acked,
+ const AckedPacketVector& packets_acked,
+ const std::vector<uint64_t>& losses_expected,
+ quiche::QuicheOptional<QuicPacketCount>
+ max_sequence_reordering_expected) {
unacked_packets_.MaybeUpdateLargestAckedOfPacketNumberSpace(
APPLICATION_DATA, QuicPacketNumber(largest_newly_acked));
LostPacketVector lost_packets;
- loss_algorithm_.DetectLosses(unacked_packets_, clock_.Now(), rtt_stats_,
- QuicPacketNumber(largest_newly_acked),
- packets_acked, &lost_packets);
+ LossDetectionInterface::DetectionStats stats = loss_algorithm_.DetectLosses(
+ unacked_packets_, clock_.Now(), rtt_stats_,
+ QuicPacketNumber(largest_newly_acked), packets_acked, &lost_packets);
+ if (max_sequence_reordering_expected.has_value()) {
+ EXPECT_EQ(stats.sent_packets_max_sequence_reordering,
+ max_sequence_reordering_expected.value());
+ }
ASSERT_EQ(losses_expected.size(), lost_packets.size());
for (size_t i = 0; i < losses_expected.size(); ++i) {
EXPECT_EQ(lost_packets[i].packet_number,
@@ -91,19 +104,19 @@ TEST_F(GeneralLossAlgorithmTest, NackRetransmit1Packet) {
unacked_packets_.RemoveFromInFlight(QuicPacketNumber(2));
packets_acked.push_back(AckedPacket(
QuicPacketNumber(2), kMaxOutgoingPacketSize, QuicTime::Zero()));
- VerifyLosses(2, packets_acked, std::vector<uint64_t>{});
+ VerifyLosses(2, packets_acked, std::vector<uint64_t>{}, 1);
packets_acked.clear();
// No loss on two acks.
unacked_packets_.RemoveFromInFlight(QuicPacketNumber(3));
packets_acked.push_back(AckedPacket(
QuicPacketNumber(3), kMaxOutgoingPacketSize, QuicTime::Zero()));
- VerifyLosses(3, packets_acked, std::vector<uint64_t>{});
+ VerifyLosses(3, packets_acked, std::vector<uint64_t>{}, 2);
packets_acked.clear();
// Loss on three acks.
unacked_packets_.RemoveFromInFlight(QuicPacketNumber(4));
packets_acked.push_back(AckedPacket(
QuicPacketNumber(4), kMaxOutgoingPacketSize, QuicTime::Zero()));
- VerifyLosses(4, packets_acked, {1});
+ VerifyLosses(4, packets_acked, {1}, 3);
EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
}
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 729cbad62ad..8d91976de45 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
@@ -8,8 +8,10 @@
#define QUICHE_QUIC_CORE_CONGESTION_CONTROL_LOSS_DETECTION_INTERFACE_H_
#include "net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.h"
+#include "net/third_party/quiche/src/quic/core/quic_config.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_types.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
namespace quic {
@@ -20,13 +22,23 @@ class RttStats;
class QUIC_EXPORT_PRIVATE LossDetectionInterface {
public:
virtual ~LossDetectionInterface() {}
+
+ virtual void SetFromConfig(const QuicConfig& config,
+ Perspective perspective) = 0;
+
+ struct QUIC_NO_EXPORT DetectionStats {
+ // Maximum sequence reordering observed in newly acked packets.
+ QuicPacketCount sent_packets_max_sequence_reordering = 0;
+ };
+
// Called when a new ack arrives or the loss alarm fires.
- virtual void DetectLosses(const QuicUnackedPacketMap& unacked_packets,
- QuicTime time,
- const RttStats& rtt_stats,
- QuicPacketNumber largest_newly_acked,
- const AckedPacketVector& packets_acked,
- LostPacketVector* packets_lost) = 0;
+ virtual DetectionStats DetectLosses(
+ const QuicUnackedPacketMap& unacked_packets,
+ QuicTime time,
+ const RttStats& rtt_stats,
+ QuicPacketNumber largest_newly_acked,
+ const AckedPacketVector& packets_acked,
+ LostPacketVector* packets_lost) = 0;
// Get the time the LossDetectionAlgorithm wants to re-evaluate losses.
// Returns QuicTime::Zero if no alarm needs to be set.
diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/pacing_sender.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/pacing_sender.h
index 781a9211951..a8436f8fc7d 100644
--- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/pacing_sender.h
+++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/pacing_sender.h
@@ -74,10 +74,14 @@ class QUIC_EXPORT_PRIVATE PacingSender {
QuicBandwidth PacingRate(QuicByteCount bytes_in_flight) const;
- QuicTime ideal_next_packet_send_time() const {
- return ideal_next_packet_send_time_;
+ NextReleaseTimeResult GetNextReleaseTime() const {
+ bool allow_burst = (burst_tokens_ > 0 || lumpy_tokens_ > 0);
+ return {ideal_next_packet_send_time_, allow_burst};
}
+ protected:
+ uint32_t lumpy_tokens() const { return lumpy_tokens_; }
+
private:
friend class test::QuicSentPacketManagerPeer;
diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/pacing_sender_test.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/pacing_sender_test.cc
index 3ca80cda87a..8c298d9ccfb 100644
--- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/pacing_sender_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/pacing_sender_test.cc
@@ -27,6 +27,16 @@ namespace test {
const QuicByteCount kBytesInFlight = 1024;
const int kInitialBurstPackets = 10;
+class TestPacingSender : public PacingSender {
+ public:
+ using PacingSender::lumpy_tokens;
+ using PacingSender::PacingSender;
+
+ QuicTime ideal_next_packet_send_time() const {
+ return GetNextReleaseTime().release_time;
+ }
+};
+
class PacingSenderTest : public QuicTest {
protected:
PacingSenderTest()
@@ -34,7 +44,7 @@ class PacingSenderTest : public QuicTest {
infinite_time_(QuicTime::Delta::Infinite()),
packet_number_(1),
mock_sender_(new StrictMock<MockSendAlgorithm>()),
- pacing_sender_(new PacingSender) {
+ pacing_sender_(new TestPacingSender) {
pacing_sender_->set_sender(mock_sender_.get());
// Pick arbitrary time.
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(9));
@@ -44,7 +54,7 @@ class PacingSenderTest : public QuicTest {
void InitPacingRate(QuicPacketCount burst_size, QuicBandwidth bandwidth) {
mock_sender_ = std::make_unique<StrictMock<MockSendAlgorithm>>();
- pacing_sender_ = std::make_unique<PacingSender>();
+ pacing_sender_ = std::make_unique<TestPacingSender>();
pacing_sender_->set_sender(mock_sender_.get());
EXPECT_CALL(*mock_sender_, PacingRate(_)).WillRepeatedly(Return(bandwidth));
EXPECT_CALL(*mock_sender_, BandwidthEstimate())
@@ -132,7 +142,7 @@ class PacingSenderTest : public QuicTest {
MockClock clock_;
QuicPacketNumber packet_number_;
std::unique_ptr<StrictMock<MockSendAlgorithm>> mock_sender_;
- std::unique_ptr<PacingSender> pacing_sender_;
+ std::unique_ptr<TestPacingSender> pacing_sender_;
};
TEST_F(PacingSenderTest, NoSend) {
@@ -466,5 +476,77 @@ TEST_F(PacingSenderTest, NoLumpyPacingForLowBandwidthFlows) {
}
}
+TEST_F(PacingSenderTest, IdealNextPacketSendTimeWithLumpyPacing) {
+ // Set lumpy size to be 3, and cwnd faction to 0.5
+ SetQuicFlag(FLAGS_quic_lumpy_pacing_size, 3);
+ SetQuicFlag(FLAGS_quic_lumpy_pacing_cwnd_fraction, 0.5f);
+
+ // Configure pacing rate of 1 packet per millisecond.
+ QuicTime::Delta inter_packet_delay = QuicTime::Delta::FromMilliseconds(1);
+ InitPacingRate(kInitialBurstPackets,
+ QuicBandwidth::FromBytesAndTimeDelta(kMaxOutgoingPacketSize,
+ inter_packet_delay));
+
+ // Send kInitialBurstPackets packets, and verify that they are not paced.
+ for (int i = 0; i < kInitialBurstPackets; ++i) {
+ CheckPacketIsSentImmediately();
+ }
+
+ CheckPacketIsSentImmediately();
+ EXPECT_EQ(pacing_sender_->ideal_next_packet_send_time(),
+ clock_.Now() + inter_packet_delay);
+ EXPECT_EQ(pacing_sender_->lumpy_tokens(), 2u);
+
+ CheckPacketIsSentImmediately();
+ EXPECT_EQ(pacing_sender_->ideal_next_packet_send_time(),
+ clock_.Now() + 2 * inter_packet_delay);
+ EXPECT_EQ(pacing_sender_->lumpy_tokens(), 1u);
+
+ CheckPacketIsSentImmediately();
+ EXPECT_EQ(pacing_sender_->ideal_next_packet_send_time(),
+ clock_.Now() + 3 * inter_packet_delay);
+ EXPECT_EQ(pacing_sender_->lumpy_tokens(), 0u);
+
+ CheckPacketIsDelayed(3 * inter_packet_delay);
+
+ // Wake up on time.
+ clock_.AdvanceTime(3 * inter_packet_delay);
+ CheckPacketIsSentImmediately();
+ EXPECT_EQ(pacing_sender_->ideal_next_packet_send_time(),
+ clock_.Now() + inter_packet_delay);
+ EXPECT_EQ(pacing_sender_->lumpy_tokens(), 2u);
+
+ CheckPacketIsSentImmediately();
+ EXPECT_EQ(pacing_sender_->ideal_next_packet_send_time(),
+ clock_.Now() + 2 * inter_packet_delay);
+ EXPECT_EQ(pacing_sender_->lumpy_tokens(), 1u);
+
+ CheckPacketIsSentImmediately();
+ EXPECT_EQ(pacing_sender_->ideal_next_packet_send_time(),
+ clock_.Now() + 3 * inter_packet_delay);
+ EXPECT_EQ(pacing_sender_->lumpy_tokens(), 0u);
+
+ CheckPacketIsDelayed(3 * inter_packet_delay);
+
+ // Wake up late.
+ clock_.AdvanceTime(4.5 * inter_packet_delay);
+ CheckPacketIsSentImmediately();
+ EXPECT_EQ(pacing_sender_->ideal_next_packet_send_time(),
+ clock_.Now() - 0.5 * inter_packet_delay);
+ EXPECT_EQ(pacing_sender_->lumpy_tokens(), 2u);
+
+ CheckPacketIsSentImmediately();
+ EXPECT_EQ(pacing_sender_->ideal_next_packet_send_time(),
+ clock_.Now() + 0.5 * inter_packet_delay);
+ EXPECT_EQ(pacing_sender_->lumpy_tokens(), 1u);
+
+ CheckPacketIsSentImmediately();
+ EXPECT_EQ(pacing_sender_->ideal_next_packet_send_time(),
+ clock_.Now() + 1.5 * inter_packet_delay);
+ EXPECT_EQ(pacing_sender_->lumpy_tokens(), 0u);
+
+ CheckPacketIsDelayed(1.5 * inter_packet_delay);
+}
+
} // namespace test
} // namespace quic
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 9062c7a339c..f247c1caa28 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
@@ -72,6 +72,10 @@ class QUIC_EXPORT_PRIVATE RttStats {
return smoothed_rtt_.IsZero() ? initial_rtt_ : smoothed_rtt_;
}
+ QuicTime::Delta MinOrInitialRtt() const {
+ return min_rtt_.IsZero() ? initial_rtt_ : min_rtt_;
+ }
+
// Sets an initial RTT to be used for SmoothedRtt before any RTT updates.
void set_initial_rtt(QuicTime::Delta initial_rtt) {
if (initial_rtt.ToMicroseconds() <= 0) {
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 d7b2eca3c74..9d003c59a66 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
@@ -45,12 +45,7 @@ SendAlgorithmInterface* SendAlgorithmInterface::Create(
? static_cast<BbrSender*>(old_send_algorithm)
: nullptr);
case kPCC:
- if (GetQuicReloadableFlag(quic_enable_pcc3)) {
- return CreatePccSender(clock, rtt_stats, unacked_packets, random, stats,
- initial_congestion_window,
- max_congestion_window);
- }
- // Fall back to CUBIC if PCC is disabled.
+ // PCC is work has stalled, fall back to CUBIC instead.
QUIC_FALLTHROUGH_INTENDED;
case kCubicBytes:
return new TcpCubicSenderBytes(
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 2bfc2dfbcf3..ea0c375d8aa 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
@@ -86,6 +86,9 @@ class QUIC_EXPORT_PRIVATE SendAlgorithmInterface {
virtual void SetFromConfig(const QuicConfig& config,
Perspective perspective) = 0;
+ virtual void ApplyConnectionOptions(
+ const QuicTagVector& connection_options) = 0;
+
// Sets the initial congestion window in number of packets. May be ignored
// if called after the initial congestion window is no longer relevant.
virtual void SetInitialCongestionWindowInPackets(QuicPacketCount packets) = 0;
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 7a36f761c1a..59ca7f875be 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,6 +46,8 @@ class QUIC_EXPORT_PRIVATE TcpCubicSenderBytes : public SendAlgorithmInterface {
// Start implementation of SendAlgorithmInterface.
void SetFromConfig(const QuicConfig& config,
Perspective perspective) override;
+ void ApplyConnectionOptions(
+ const QuicTagVector& /*connection_options*/) override {}
void AdjustNetworkParameters(const NetworkParams& params) override;
void SetNumEmulatedConnections(int num_connections);
void SetInitialCongestionWindowInPackets(
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 73b26f5cda7..0f294d6b94e 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
@@ -6,6 +6,7 @@
#include <algorithm>
+#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
namespace quic {
@@ -17,13 +18,24 @@ UberLossAlgorithm::UberLossAlgorithm() {
}
}
-void UberLossAlgorithm::DetectLosses(
+void UberLossAlgorithm::SetFromConfig(const QuicConfig& config,
+ Perspective perspective) {
+ if (config.HasClientRequestedIndependentOption(kELDT, perspective) &&
+ tuner_ != nullptr) {
+ tuning_enabled_ = true;
+ MaybeStartTuning();
+ }
+}
+
+LossDetectionInterface::DetectionStats UberLossAlgorithm::DetectLosses(
const QuicUnackedPacketMap& unacked_packets,
QuicTime time,
const RttStats& rtt_stats,
QuicPacketNumber /*largest_newly_acked*/,
const AckedPacketVector& packets_acked,
LostPacketVector* packets_lost) {
+ DetectionStats overall_stats;
+
for (int8_t i = INITIAL_DATA; i < NUM_PACKET_NUMBER_SPACES; ++i) {
const QuicPacketNumber largest_acked =
unacked_packets.GetLargestAckedOfPacketNumberSpace(
@@ -35,10 +47,16 @@ void UberLossAlgorithm::DetectLosses(
continue;
}
- general_loss_algorithms_[i].DetectLosses(unacked_packets, time, rtt_stats,
- largest_acked, packets_acked,
- packets_lost);
+ DetectionStats stats = general_loss_algorithms_[i].DetectLosses(
+ unacked_packets, time, rtt_stats, largest_acked, packets_acked,
+ packets_lost);
+
+ overall_stats.sent_packets_max_sequence_reordering =
+ std::max(overall_stats.sent_packets_max_sequence_reordering,
+ stats.sent_packets_max_sequence_reordering);
}
+
+ return overall_stats;
}
QuicTime UberLossAlgorithm::GetLossTimeout() const {
@@ -78,7 +96,7 @@ void UberLossAlgorithm::SetLossDetectionTuner(
}
void UberLossAlgorithm::MaybeStartTuning() {
- if (tuner_ == nullptr || tuner_started_) {
+ if (tuner_started_ || !tuning_enabled_ || !min_rtt_available_) {
return;
}
@@ -88,6 +106,7 @@ void UberLossAlgorithm::MaybeStartTuning() {
void UberLossAlgorithm::OnConfigNegotiated() {}
void UberLossAlgorithm::OnMinRttAvailable() {
+ min_rtt_available_ = true;
MaybeStartTuning();
}
@@ -128,6 +147,10 @@ void UberLossAlgorithm::EnableAdaptiveTimeThreshold() {
}
}
+QuicPacketCount UberLossAlgorithm::GetPacketReorderingThreshold() const {
+ return general_loss_algorithms_[APPLICATION_DATA].reordering_threshold();
+}
+
void UberLossAlgorithm::DisablePacketThresholdForRuntPackets() {
for (int8_t i = INITIAL_DATA; i < NUM_PACKET_NUMBER_SPACES; ++i) {
general_loss_algorithms_[i].disable_packet_threshold_for_runt_packets();
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 ff1ac817b3c..86b652572b7 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
@@ -6,6 +6,7 @@
#define QUICHE_QUIC_CORE_CONGESTION_CONTROL_UBER_LOSS_ALGORITHM_H_
#include "net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_optional.h"
namespace quic {
@@ -46,13 +47,16 @@ class QUIC_EXPORT_PRIVATE UberLossAlgorithm : public LossDetectionInterface {
UberLossAlgorithm& operator=(const UberLossAlgorithm&) = delete;
~UberLossAlgorithm() override {}
+ void SetFromConfig(const QuicConfig& config,
+ Perspective perspective) override;
+
// Detects lost packets.
- void DetectLosses(const QuicUnackedPacketMap& unacked_packets,
- QuicTime time,
- const RttStats& rtt_stats,
- QuicPacketNumber largest_newly_acked,
- const AckedPacketVector& packets_acked,
- LostPacketVector* packets_lost) override;
+ DetectionStats DetectLosses(const QuicUnackedPacketMap& unacked_packets,
+ QuicTime time,
+ const RttStats& rtt_stats,
+ QuicPacketNumber largest_newly_acked,
+ const AckedPacketVector& packets_acked,
+ LostPacketVector* packets_lost) override;
// Returns the earliest time the early retransmit timer should be active.
QuicTime GetLossTimeout() const override;
@@ -85,6 +89,10 @@ class QUIC_EXPORT_PRIVATE UberLossAlgorithm : public LossDetectionInterface {
// Enable adaptive time threshold of all packet number spaces.
void EnableAdaptiveTimeThreshold();
+ // Get the packet reordering threshold from the APPLICATION_DATA PN space.
+ // Always 3 when adaptive reordering is not enabled.
+ QuicPacketCount GetPacketReorderingThreshold() const;
+
// Disable packet threshold loss detection for *runt* packets.
void DisablePacketThresholdForRuntPackets();
@@ -103,6 +111,8 @@ class QUIC_EXPORT_PRIVATE UberLossAlgorithm : public LossDetectionInterface {
std::unique_ptr<LossDetectionTunerInterface> tuner_;
LossDetectionParameters tuned_parameters_;
bool tuner_started_ = false;
+ bool min_rtt_available_ = false;
+ bool tuning_enabled_ = false; // Whether tuning is enabled by config.
};
} // namespace quic
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 a3daf095d56..6fd949f317a 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
@@ -11,6 +11,7 @@
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
#include "net/third_party/quiche/src/quic/test_tools/mock_clock.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_unacked_packet_map_peer.h"
+#include "net/third_party/quiche/src/common/platform/api/quiche_optional.h"
namespace quic {
namespace test {
@@ -64,10 +65,23 @@ class UberLossAlgorithmTest : public QuicTest {
void VerifyLosses(uint64_t largest_newly_acked,
const AckedPacketVector& packets_acked,
const std::vector<uint64_t>& losses_expected) {
+ return VerifyLosses(largest_newly_acked, packets_acked, losses_expected,
+ quiche::QuicheOptional<QuicPacketCount>());
+ }
+
+ void VerifyLosses(uint64_t largest_newly_acked,
+ const AckedPacketVector& packets_acked,
+ const std::vector<uint64_t>& losses_expected,
+ quiche::QuicheOptional<QuicPacketCount>
+ max_sequence_reordering_expected) {
LostPacketVector lost_packets;
- loss_algorithm_.DetectLosses(*unacked_packets_, clock_.Now(), rtt_stats_,
- QuicPacketNumber(largest_newly_acked),
- packets_acked, &lost_packets);
+ LossDetectionInterface::DetectionStats stats = loss_algorithm_.DetectLosses(
+ *unacked_packets_, clock_.Now(), rtt_stats_,
+ QuicPacketNumber(largest_newly_acked), packets_acked, &lost_packets);
+ if (max_sequence_reordering_expected.has_value()) {
+ EXPECT_EQ(stats.sent_packets_max_sequence_reordering,
+ max_sequence_reordering_expected.value());
+ }
ASSERT_EQ(losses_expected.size(), lost_packets.size());
for (size_t i = 0; i < losses_expected.size(); ++i) {
EXPECT_EQ(lost_packets[i].packet_number,
@@ -98,7 +112,7 @@ TEST_F(UberLossAlgorithmTest, ScenarioA) {
unacked_packets_->MaybeUpdateLargestAckedOfPacketNumberSpace(
HANDSHAKE_DATA, QuicPacketNumber(4));
// Verify no packet is detected lost.
- VerifyLosses(4, packets_acked_, std::vector<uint64_t>{});
+ VerifyLosses(4, packets_acked_, std::vector<uint64_t>{}, 0);
EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
}
@@ -114,7 +128,7 @@ TEST_F(UberLossAlgorithmTest, ScenarioB) {
unacked_packets_->MaybeUpdateLargestAckedOfPacketNumberSpace(
APPLICATION_DATA, QuicPacketNumber(4));
// No packet loss by acking 4.
- VerifyLosses(4, packets_acked_, std::vector<uint64_t>{});
+ VerifyLosses(4, packets_acked_, std::vector<uint64_t>{}, 1);
EXPECT_EQ(clock_.Now() + 1.25 * rtt_stats_.smoothed_rtt(),
loss_algorithm_.GetLossTimeout());
@@ -122,14 +136,14 @@ TEST_F(UberLossAlgorithmTest, ScenarioB) {
AckPackets({6});
unacked_packets_->MaybeUpdateLargestAckedOfPacketNumberSpace(
APPLICATION_DATA, QuicPacketNumber(6));
- VerifyLosses(6, packets_acked_, std::vector<uint64_t>{3});
+ VerifyLosses(6, packets_acked_, std::vector<uint64_t>{3}, 3);
EXPECT_EQ(clock_.Now() + 1.25 * rtt_stats_.smoothed_rtt(),
loss_algorithm_.GetLossTimeout());
packets_acked_.clear();
clock_.AdvanceTime(1.25 * rtt_stats_.latest_rtt());
// Verify 5 will be early retransmitted.
- VerifyLosses(6, packets_acked_, {5});
+ VerifyLosses(6, packets_acked_, {5}, 1);
}
TEST_F(UberLossAlgorithmTest, ScenarioC) {
@@ -151,14 +165,14 @@ TEST_F(UberLossAlgorithmTest, ScenarioC) {
unacked_packets_->MaybeUpdateLargestAckedOfPacketNumberSpace(
HANDSHAKE_DATA, QuicPacketNumber(5));
// No packet loss by acking 5.
- VerifyLosses(5, packets_acked_, std::vector<uint64_t>{});
+ VerifyLosses(5, packets_acked_, std::vector<uint64_t>{}, 2);
EXPECT_EQ(clock_.Now() + 1.25 * rtt_stats_.smoothed_rtt(),
loss_algorithm_.GetLossTimeout());
packets_acked_.clear();
clock_.AdvanceTime(1.25 * rtt_stats_.latest_rtt());
// Verify 2 and 3 will be early retransmitted.
- VerifyLosses(5, packets_acked_, std::vector<uint64_t>{2, 3});
+ VerifyLosses(5, packets_acked_, std::vector<uint64_t>{2, 3}, 2);
}
// Regression test for b/133771183.
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view.cc
index 6400528c8fd..0f17d121ca0 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view.cc
@@ -6,15 +6,24 @@
#include <cstdint>
#include <memory>
+#include <string>
+#include "third_party/boringssl/src/include/openssl/base.h"
#include "third_party/boringssl/src/include/openssl/bytestring.h"
+#include "third_party/boringssl/src/include/openssl/digest.h"
#include "third_party/boringssl/src/include/openssl/ec.h"
#include "third_party/boringssl/src/include/openssl/evp.h"
#include "third_party/boringssl/src/include/openssl/nid.h"
+#include "third_party/boringssl/src/include/openssl/rsa.h"
+#include "third_party/boringssl/src/include/openssl/ssl.h"
#include "net/third_party/quiche/src/quic/core/crypto/boring_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_ip_address.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
+#include "net/third_party/quiche/src/common/platform/api/quiche_optional.h"
+#include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
+#include "net/third_party/quiche/src/common/platform/api/quiche_text_utils.h"
// The literals below were encoded using `ascii2der | xxd -i`. The comments
// above the literals are the contents in the der2ascii syntax.
@@ -27,10 +36,110 @@ constexpr uint8_t kX509Version[] = {0x02, 0x01, 0x02};
// 2.5.29.17
constexpr uint8_t kSubjectAltNameOid[] = {0x55, 0x1d, 0x11};
+enum class PublicKeyType {
+ kRsa,
+ kP256,
+ kP384,
+ kEd25519,
+ kUnknown,
+};
+
+PublicKeyType PublicKeyTypeFromKey(EVP_PKEY* public_key) {
+ switch (EVP_PKEY_id(public_key)) {
+ case EVP_PKEY_RSA:
+ return PublicKeyType::kRsa;
+ case EVP_PKEY_EC: {
+ const EC_KEY* key = EVP_PKEY_get0_EC_KEY(public_key);
+ if (key == nullptr) {
+ return PublicKeyType::kUnknown;
+ }
+ const EC_GROUP* group = EC_KEY_get0_group(key);
+ if (group == nullptr) {
+ return PublicKeyType::kUnknown;
+ }
+ const int curve_nid = EC_GROUP_get_curve_name(group);
+ switch (curve_nid) {
+ case NID_X9_62_prime256v1:
+ return PublicKeyType::kP256;
+ case NID_secp384r1:
+ return PublicKeyType::kP384;
+ default:
+ return PublicKeyType::kUnknown;
+ }
+ }
+ case EVP_PKEY_ED25519:
+ return PublicKeyType::kEd25519;
+ default:
+ return PublicKeyType::kUnknown;
+ }
+}
+
+PublicKeyType PublicKeyTypeFromSignatureAlgorithm(
+ uint16_t signature_algorithm) {
+ switch (signature_algorithm) {
+ case SSL_SIGN_RSA_PSS_RSAE_SHA256:
+ return PublicKeyType::kRsa;
+ case SSL_SIGN_ECDSA_SECP256R1_SHA256:
+ return PublicKeyType::kP384;
+ case SSL_SIGN_ECDSA_SECP384R1_SHA384:
+ return PublicKeyType::kP384;
+ case SSL_SIGN_ED25519:
+ return PublicKeyType::kEd25519;
+ default:
+ return PublicKeyType::kUnknown;
+ }
+}
+
} // namespace
namespace quic {
+PemReadResult ReadNextPemMessage(std::istream* input) {
+ constexpr quiche::QuicheStringPiece kPemBegin = "-----BEGIN ";
+ constexpr quiche::QuicheStringPiece kPemEnd = "-----END ";
+ constexpr quiche::QuicheStringPiece kPemDashes = "-----";
+
+ std::string line_buffer, encoded_message_contents, expected_end;
+ bool pending_message = false;
+ PemReadResult result;
+ while (std::getline(*input, line_buffer)) {
+ quiche::QuicheStringPiece line(line_buffer);
+ quiche::QuicheTextUtils::RemoveLeadingAndTrailingWhitespace(&line);
+
+ // Handle BEGIN lines.
+ if (!pending_message &&
+ quiche::QuicheTextUtils::StartsWith(line, kPemBegin) &&
+ quiche::QuicheTextUtils::EndsWith(line, kPemDashes)) {
+ result.type = std::string(
+ line.substr(kPemBegin.size(),
+ line.size() - kPemDashes.size() - kPemBegin.size()));
+ expected_end = quiche::QuicheStrCat(kPemEnd, result.type, kPemDashes);
+ pending_message = true;
+ continue;
+ }
+
+ // Handle END lines.
+ if (pending_message && line == expected_end) {
+ quiche::QuicheOptional<std::string> data =
+ quiche::QuicheTextUtils::Base64Decode(encoded_message_contents);
+ if (data.has_value()) {
+ result.status = PemReadResult::kOk;
+ result.contents = data.value();
+ } else {
+ result.status = PemReadResult::kError;
+ }
+ return result;
+ }
+
+ if (pending_message) {
+ encoded_message_contents.append(std::string(line));
+ }
+ }
+ bool eof_reached = input->eof() && !pending_message;
+ return PemReadResult{
+ .status = (eof_reached ? PemReadResult::kEof : PemReadResult::kError)};
+}
+
std::unique_ptr<CertificateView> CertificateView::ParseSingleCertificate(
quiche::QuicheStringPiece certificate) {
std::unique_ptr<CertificateView> result(new CertificateView());
@@ -207,6 +316,24 @@ bool CertificateView::ParseExtensions(CBS extensions) {
return true;
}
+std::vector<std::string> CertificateView::LoadPemFromStream(
+ std::istream* input) {
+ std::vector<std::string> result;
+ for (;;) {
+ PemReadResult read_result = ReadNextPemMessage(input);
+ if (read_result.status == PemReadResult::kEof) {
+ return result;
+ }
+ if (read_result.status != PemReadResult::kOk) {
+ return std::vector<std::string>();
+ }
+ if (read_result.type != "CERTIFICATE") {
+ continue;
+ }
+ result.emplace_back(std::move(read_result.contents));
+ }
+}
+
bool CertificateView::ValidatePublicKeyParameters() {
// The profile here affects what certificates can be used:
// (1) when QUIC is used as a server library without any custom certificate
@@ -215,32 +342,130 @@ bool CertificateView::ValidatePublicKeyParameters() {
// The goal is to allow at minimum any certificate that would be allowed on a
// regular Web session over TLS 1.3 while ensuring we do not expose any
// algorithms we don't want to support long-term.
- switch (EVP_PKEY_id(public_key_.get())) {
- case EVP_PKEY_RSA:
+ PublicKeyType key_type = PublicKeyTypeFromKey(public_key_.get());
+ switch (key_type) {
+ case PublicKeyType::kRsa:
return EVP_PKEY_bits(public_key_.get()) >= 2048;
- case EVP_PKEY_EC: {
- const EC_KEY* key = EVP_PKEY_get0_EC_KEY(public_key_.get());
- if (key == nullptr) {
- return false;
- }
- const EC_GROUP* group = EC_KEY_get0_group(key);
- if (group == nullptr) {
- return false;
- }
- const int curve_nid = EC_GROUP_get_curve_name(group);
- switch (curve_nid) {
- case NID_X9_62_prime256v1:
- case NID_secp384r1:
- return true;
- default:
- return false;
- }
- }
- case EVP_PKEY_ED25519:
+ case PublicKeyType::kP256:
+ case PublicKeyType::kP384:
+ case PublicKeyType::kEd25519:
return true;
default:
return false;
}
}
+bool CertificateView::VerifySignature(quiche::QuicheStringPiece data,
+ quiche::QuicheStringPiece signature,
+ uint16_t signature_algorithm) const {
+ if (PublicKeyTypeFromSignatureAlgorithm(signature_algorithm) !=
+ PublicKeyTypeFromKey(public_key_.get())) {
+ QUIC_BUG << "Mismatch between the requested signature algorithm and the "
+ "type of the public key.";
+ return false;
+ }
+
+ bssl::ScopedEVP_MD_CTX md_ctx;
+ EVP_PKEY_CTX* pctx;
+ if (!EVP_DigestVerifyInit(
+ md_ctx.get(), &pctx,
+ SSL_get_signature_algorithm_digest(signature_algorithm), nullptr,
+ public_key_.get())) {
+ return false;
+ }
+ if (SSL_is_signature_algorithm_rsa_pss(signature_algorithm)) {
+ if (!EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) ||
+ !EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, -1)) {
+ return false;
+ }
+ }
+ return EVP_DigestVerify(
+ md_ctx.get(), reinterpret_cast<const uint8_t*>(signature.data()),
+ signature.size(), reinterpret_cast<const uint8_t*>(data.data()),
+ data.size());
+}
+
+std::unique_ptr<CertificatePrivateKey> CertificatePrivateKey::LoadFromDer(
+ quiche::QuicheStringPiece private_key) {
+ std::unique_ptr<CertificatePrivateKey> result(new CertificatePrivateKey());
+ CBS private_key_cbs = StringPieceToCbs(private_key);
+ result->private_key_.reset(EVP_parse_private_key(&private_key_cbs));
+ if (result->private_key_ == nullptr || CBS_len(&private_key_cbs) != 0) {
+ return nullptr;
+ }
+ return result;
+}
+
+std::unique_ptr<CertificatePrivateKey> CertificatePrivateKey::LoadPemFromStream(
+ std::istream* input) {
+ PemReadResult result = ReadNextPemMessage(input);
+ if (result.status != PemReadResult::kOk) {
+ return nullptr;
+ }
+ // RFC 5958 OneAsymmetricKey message.
+ if (result.type == "PRIVATE KEY") {
+ return LoadFromDer(result.contents);
+ }
+ // Legacy OpenSSL format: PKCS#1 (RFC 8017) RSAPrivateKey message.
+ if (result.type == "RSA PRIVATE KEY") {
+ CBS private_key_cbs = StringPieceToCbs(result.contents);
+ bssl::UniquePtr<RSA> rsa(RSA_parse_private_key(&private_key_cbs));
+ if (rsa == nullptr || CBS_len(&private_key_cbs) != 0) {
+ return nullptr;
+ }
+
+ std::unique_ptr<CertificatePrivateKey> key(new CertificatePrivateKey());
+ key->private_key_.reset(EVP_PKEY_new());
+ EVP_PKEY_assign_RSA(key->private_key_.get(), rsa.release());
+ return key;
+ }
+ // Unknown format.
+ return nullptr;
+}
+
+std::string CertificatePrivateKey::Sign(quiche::QuicheStringPiece input,
+ uint16_t signature_algorithm) {
+ if (PublicKeyTypeFromSignatureAlgorithm(signature_algorithm) !=
+ PublicKeyTypeFromKey(private_key_.get())) {
+ QUIC_BUG << "Mismatch between the requested signature algorithm and the "
+ "type of the private key.";
+ return "";
+ }
+
+ bssl::ScopedEVP_MD_CTX md_ctx;
+ EVP_PKEY_CTX* pctx;
+ if (!EVP_DigestSignInit(
+ md_ctx.get(), &pctx,
+ SSL_get_signature_algorithm_digest(signature_algorithm),
+ /*e=*/nullptr, private_key_.get())) {
+ return "";
+ }
+ if (SSL_is_signature_algorithm_rsa_pss(signature_algorithm)) {
+ if (!EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) ||
+ !EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, -1)) {
+ return "";
+ }
+ }
+
+ std::string output;
+ size_t output_size;
+ if (!EVP_DigestSign(md_ctx.get(), /*out_sig=*/nullptr, &output_size,
+ reinterpret_cast<const uint8_t*>(input.data()),
+ input.size())) {
+ return "";
+ }
+ output.resize(output_size);
+ if (!EVP_DigestSign(
+ md_ctx.get(), reinterpret_cast<uint8_t*>(&output[0]), &output_size,
+ reinterpret_cast<const uint8_t*>(input.data()), input.size())) {
+ return "";
+ }
+ output.resize(output_size);
+ return output;
+}
+
+bool CertificatePrivateKey::MatchesPublicKey(const CertificateView& view) {
+ return EVP_PKEY_cmp(view.public_key(), private_key_.get()) == 1;
+}
+
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view.h b/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view.h
index 3569f4e0d87..286226d7e20 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view.h
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view.h
@@ -5,8 +5,11 @@
#ifndef QUICHE_QUIC_CORE_CRYPTO_CERTIFICATE_VIEW_H_
#define QUICHE_QUIC_CORE_CRYPTO_CERTIFICATE_VIEW_H_
+#include <istream>
#include <memory>
+#include <vector>
+#include "third_party/boringssl/src/include/openssl/base.h"
#include "third_party/boringssl/src/include/openssl/bytestring.h"
#include "third_party/boringssl/src/include/openssl/evp.h"
#include "net/third_party/quiche/src/quic/core/crypto/boring_utils.h"
@@ -16,6 +19,18 @@
namespace quic {
+struct QUIC_EXPORT_PRIVATE PemReadResult {
+ enum Status { kOk, kEof, kError };
+ Status status;
+ std::string contents;
+ // The type of the PEM message (e.g., if the message starts with
+ // "-----BEGIN CERTIFICATE-----", the |type| would be "CERTIFICATE").
+ std::string type;
+};
+
+// Reads |input| line-by-line and returns the next available PEM message.
+QUIC_EXPORT_PRIVATE PemReadResult ReadNextPemMessage(std::istream* input);
+
// CertificateView represents a parsed version of a single X.509 certificate. As
// the word "view" implies, it does not take ownership of the underlying strings
// and consists primarily of pointers into the certificate that is passed into
@@ -27,7 +42,11 @@ class QUIC_EXPORT_PRIVATE CertificateView {
static std::unique_ptr<CertificateView> ParseSingleCertificate(
quiche::QuicheStringPiece certificate);
- EVP_PKEY* public_key() { return public_key_.get(); }
+ // Loads all PEM-encoded X.509 certificates found in the |input| stream
+ // without parsing them. Returns an empty vector if any parsing error occurs.
+ static std::vector<std::string> LoadPemFromStream(std::istream* input);
+
+ const EVP_PKEY* public_key() const { return public_key_.get(); }
const std::vector<quiche::QuicheStringPiece>& subject_alt_name_domains()
const {
@@ -37,6 +56,11 @@ class QUIC_EXPORT_PRIVATE CertificateView {
return subject_alt_name_ips_;
}
+ // |signature_algorithm| is a TLS signature algorithm ID.
+ bool VerifySignature(quiche::QuicheStringPiece data,
+ quiche::QuicheStringPiece signature,
+ uint16_t signature_algorithm) const;
+
private:
CertificateView() = default;
@@ -52,6 +76,33 @@ class QUIC_EXPORT_PRIVATE CertificateView {
bool ValidatePublicKeyParameters();
};
+// CertificatePrivateKey represents a private key that can be used with an X.509
+// certificate.
+class QUIC_EXPORT_PRIVATE CertificatePrivateKey {
+ public:
+ // Loads a DER-encoded PrivateKeyInfo structure (RFC 5958) as a private key.
+ static std::unique_ptr<CertificatePrivateKey> LoadFromDer(
+ quiche::QuicheStringPiece private_key);
+
+ // Loads a private key from a PEM file formatted according to RFC 7468. Also
+ // supports legacy OpenSSL RSA key format ("BEGIN RSA PRIVATE KEY").
+ static std::unique_ptr<CertificatePrivateKey> LoadPemFromStream(
+ std::istream* input);
+
+ // |signature_algorithm| is a TLS signature algorithm ID.
+ std::string Sign(quiche::QuicheStringPiece input,
+ uint16_t signature_algorithm);
+
+ // Verifies that the private key in question matches the public key of the
+ // certificate |view|.
+ bool MatchesPublicKey(const CertificateView& view);
+
+ private:
+ CertificatePrivateKey() = default;
+
+ bssl::UniquePtr<EVP_PKEY> private_key_;
+};
+
} // namespace quic
#endif // QUICHE_QUIC_CORE_CRYPTO_CERTIFICATE_VIEW_H_
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view_der_fuzzer.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view_der_fuzzer.cc
new file mode 100644
index 00000000000..e2de1ba7efe
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view_der_fuzzer.cc
@@ -0,0 +1,15 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+
+#include "net/third_party/quiche/src/quic/core/crypto/certificate_view.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ std::string input(reinterpret_cast<const char*>(data), size);
+
+ quic::CertificateView::ParseSingleCertificate(input);
+ quic::CertificatePrivateKey::LoadFromDer(input);
+ return 0;
+}
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view_pem_fuzzer.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view_pem_fuzzer.cc
new file mode 100644
index 00000000000..e1efd988bb9
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view_pem_fuzzer.cc
@@ -0,0 +1,18 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <sstream>
+#include <string>
+
+#include "net/third_party/quiche/src/quic/core/crypto/certificate_view.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ std::string input(reinterpret_cast<const char*>(data), size);
+ std::stringstream stream(input);
+
+ quic::CertificateView::LoadPemFromStream(&stream);
+ stream.seekg(0);
+ quic::CertificatePrivateKey::LoadPemFromStream(&stream);
+ return 0;
+}
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view_test.cc
index 6be0e4ae7a6..b0b52f14f3b 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view_test.cc
@@ -4,131 +4,38 @@
#include "net/third_party/quiche/src/quic/core/crypto/certificate_view.h"
+#include <memory>
+#include <sstream>
+
#include "third_party/boringssl/src/include/openssl/base.h"
#include "third_party/boringssl/src/include/openssl/evp.h"
+#include "third_party/boringssl/src/include/openssl/ssl.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+#include "net/third_party/quiche/src/quic/test_tools/test_certificates.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
namespace quic {
+namespace test {
namespace {
using testing::ElementsAre;
+using testing::HasSubstr;
+
+TEST(CertificateViewTest, PemParser) {
+ std::stringstream stream(kTestCertificatePem);
+ PemReadResult result = ReadNextPemMessage(&stream);
+ EXPECT_EQ(result.status, PemReadResult::kOk);
+ EXPECT_EQ(result.type, "CERTIFICATE");
+ EXPECT_EQ(result.contents, kTestCertificate);
-// A test certificate generated by //net/tools/quic/certs/generate-certs.sh.
-constexpr char kTestCertificate[] = {
- '\x30', '\x82', '\x03', '\xb4', '\x30', '\x82', '\x02', '\x9c', '\xa0',
- '\x03', '\x02', '\x01', '\x02', '\x02', '\x01', '\x01', '\x30', '\x0d',
- '\x06', '\x09', '\x2a', '\x86', '\x48', '\x86', '\xf7', '\x0d', '\x01',
- '\x01', '\x0b', '\x05', '\x00', '\x30', '\x1e', '\x31', '\x1c', '\x30',
- '\x1a', '\x06', '\x03', '\x55', '\x04', '\x03', '\x0c', '\x13', '\x51',
- '\x55', '\x49', '\x43', '\x20', '\x53', '\x65', '\x72', '\x76', '\x65',
- '\x72', '\x20', '\x52', '\x6f', '\x6f', '\x74', '\x20', '\x43', '\x41',
- '\x30', '\x1e', '\x17', '\x0d', '\x32', '\x30', '\x30', '\x31', '\x33',
- '\x30', '\x31', '\x38', '\x31', '\x33', '\x35', '\x39', '\x5a', '\x17',
- '\x0d', '\x32', '\x30', '\x30', '\x32', '\x30', '\x32', '\x31', '\x38',
- '\x31', '\x33', '\x35', '\x39', '\x5a', '\x30', '\x64', '\x31', '\x0b',
- '\x30', '\x09', '\x06', '\x03', '\x55', '\x04', '\x06', '\x13', '\x02',
- '\x55', '\x53', '\x31', '\x13', '\x30', '\x11', '\x06', '\x03', '\x55',
- '\x04', '\x08', '\x0c', '\x0a', '\x43', '\x61', '\x6c', '\x69', '\x66',
- '\x6f', '\x72', '\x6e', '\x69', '\x61', '\x31', '\x16', '\x30', '\x14',
- '\x06', '\x03', '\x55', '\x04', '\x07', '\x0c', '\x0d', '\x4d', '\x6f',
- '\x75', '\x6e', '\x74', '\x61', '\x69', '\x6e', '\x20', '\x56', '\x69',
- '\x65', '\x77', '\x31', '\x14', '\x30', '\x12', '\x06', '\x03', '\x55',
- '\x04', '\x0a', '\x0c', '\x0b', '\x51', '\x55', '\x49', '\x43', '\x20',
- '\x53', '\x65', '\x72', '\x76', '\x65', '\x72', '\x31', '\x12', '\x30',
- '\x10', '\x06', '\x03', '\x55', '\x04', '\x03', '\x0c', '\x09', '\x31',
- '\x32', '\x37', '\x2e', '\x30', '\x2e', '\x30', '\x2e', '\x31', '\x30',
- '\x82', '\x01', '\x22', '\x30', '\x0d', '\x06', '\x09', '\x2a', '\x86',
- '\x48', '\x86', '\xf7', '\x0d', '\x01', '\x01', '\x01', '\x05', '\x00',
- '\x03', '\x82', '\x01', '\x0f', '\x00', '\x30', '\x82', '\x01', '\x0a',
- '\x02', '\x82', '\x01', '\x01', '\x00', '\xc5', '\xe2', '\x51', '\x6d',
- '\x3f', '\xd6', '\x28', '\xf2', '\xad', '\x34', '\x73', '\x87', '\x64',
- '\xca', '\x33', '\x19', '\x33', '\xb7', '\x75', '\x91', '\xab', '\x31',
- '\x19', '\x2b', '\xe3', '\xa4', '\x26', '\x09', '\x29', '\x8b', '\x2d',
- '\xf7', '\x52', '\x75', '\xa7', '\x55', '\x15', '\xf0', '\x11', '\xc7',
- '\xc2', '\xc4', '\xed', '\x18', '\x1b', '\x33', '\x0b', '\x71', '\x32',
- '\xe6', '\x35', '\x89', '\xcd', '\x2d', '\x5a', '\x05', '\x57', '\x4e',
- '\xc2', '\x78', '\x75', '\x65', '\x72', '\x2d', '\x8a', '\x17', '\x83',
- '\xd6', '\x32', '\x90', '\x85', '\xf8', '\x22', '\xe2', '\x65', '\xa9',
- '\xe0', '\xa0', '\xfe', '\x19', '\xb2', '\x39', '\x2d', '\x14', '\x03',
- '\x10', '\x2f', '\xcc', '\x8b', '\x5e', '\xaa', '\x25', '\x27', '\x0d',
- '\xa3', '\x37', '\x10', '\x0c', '\x17', '\xec', '\xf0', '\x8b', '\xc5',
- '\x6b', '\xed', '\x6b', '\x5e', '\xb2', '\xe2', '\x35', '\x3e', '\x46',
- '\x3b', '\xf7', '\xf6', '\x59', '\xb1', '\xe0', '\x16', '\xa6', '\xfb',
- '\x03', '\xbf', '\x84', '\x4f', '\xce', '\x64', '\x15', '\x0d', '\x59',
- '\x99', '\xa6', '\xf0', '\x7f', '\x8a', '\x33', '\x4b', '\xbb', '\x0b',
- '\xb8', '\xf2', '\xd1', '\x27', '\x90', '\x8f', '\x38', '\xf8', '\x5a',
- '\x41', '\x82', '\x07', '\x9b', '\x0d', '\xd9', '\x52', '\xe0', '\x70',
- '\xff', '\xde', '\xda', '\xd8', '\x25', '\x4e', '\x2f', '\x2d', '\x9f',
- '\xaf', '\x92', '\x63', '\xc7', '\x42', '\xb4', '\xdc', '\x16', '\x95',
- '\x23', '\x05', '\x02', '\x6b', '\xb0', '\xe8', '\xc5', '\xfe', '\x15',
- '\x9a', '\xe8', '\x7d', '\x2f', '\xdc', '\x43', '\xf4', '\x70', '\x91',
- '\x1a', '\x93', '\xbe', '\x71', '\xaf', '\x85', '\x84', '\xdb', '\xcf',
- '\x6b', '\x5c', '\x80', '\xb2', '\xd3', '\xf3', '\x42', '\x6e', '\x24',
- '\xec', '\x2a', '\x62', '\x99', '\xc6', '\x3c', '\xe5', '\x32', '\xe5',
- '\x72', '\x37', '\x30', '\x9b', '\x0b', '\xe4', '\x06', '\xb4', '\x64',
- '\x26', '\x95', '\x59', '\xba', '\xf1', '\x53', '\x83', '\x3d', '\x99',
- '\x6d', '\xf0', '\x80', '\xe2', '\xdb', '\x6b', '\x34', '\x52', '\x06',
- '\x77', '\x3c', '\x73', '\xbe', '\xc6', '\xe3', '\xce', '\xb2', '\x11',
- '\x02', '\x03', '\x01', '\x00', '\x01', '\xa3', '\x81', '\xb6', '\x30',
- '\x81', '\xb3', '\x30', '\x0c', '\x06', '\x03', '\x55', '\x1d', '\x13',
- '\x01', '\x01', '\xff', '\x04', '\x02', '\x30', '\x00', '\x30', '\x1d',
- '\x06', '\x03', '\x55', '\x1d', '\x0e', '\x04', '\x16', '\x04', '\x14',
- '\xc8', '\x54', '\x28', '\xf6', '\xd2', '\xd5', '\x12', '\x35', '\x89',
- '\x15', '\x75', '\xb8', '\xbf', '\xdd', '\xfb', '\x4a', '\xfc', '\x6c',
- '\x89', '\xde', '\x30', '\x1f', '\x06', '\x03', '\x55', '\x1d', '\x23',
- '\x04', '\x18', '\x30', '\x16', '\x80', '\x14', '\x50', '\xe4', '\x1d',
- '\xc3', '\x1a', '\xfb', '\xfd', '\x38', '\xdd', '\xa2', '\x05', '\xfd',
- '\xc8', '\xfa', '\x57', '\x0a', '\xc1', '\x06', '\x0f', '\xae', '\x30',
- '\x1d', '\x06', '\x03', '\x55', '\x1d', '\x25', '\x04', '\x16', '\x30',
- '\x14', '\x06', '\x08', '\x2b', '\x06', '\x01', '\x05', '\x05', '\x07',
- '\x03', '\x01', '\x06', '\x08', '\x2b', '\x06', '\x01', '\x05', '\x05',
- '\x07', '\x03', '\x02', '\x30', '\x44', '\x06', '\x03', '\x55', '\x1d',
- '\x11', '\x04', '\x3d', '\x30', '\x3b', '\x82', '\x0f', '\x77', '\x77',
- '\x77', '\x2e', '\x65', '\x78', '\x61', '\x6d', '\x70', '\x6c', '\x65',
- '\x2e', '\x6f', '\x72', '\x67', '\x82', '\x10', '\x6d', '\x61', '\x69',
- '\x6c', '\x2e', '\x65', '\x78', '\x61', '\x6d', '\x70', '\x6c', '\x65',
- '\x2e', '\x6f', '\x72', '\x67', '\x82', '\x10', '\x6d', '\x61', '\x69',
- '\x6c', '\x2e', '\x65', '\x78', '\x61', '\x6d', '\x70', '\x6c', '\x65',
- '\x2e', '\x63', '\x6f', '\x6d', '\x87', '\x04', '\x7f', '\x00', '\x00',
- '\x01', '\x30', '\x0d', '\x06', '\x09', '\x2a', '\x86', '\x48', '\x86',
- '\xf7', '\x0d', '\x01', '\x01', '\x0b', '\x05', '\x00', '\x03', '\x82',
- '\x01', '\x01', '\x00', '\x45', '\x41', '\x7a', '\x68', '\xe0', '\xa7',
- '\x59', '\xa1', '\x62', '\x54', '\x73', '\x74', '\x14', '\x4f', '\xde',
- '\x9c', '\x51', '\xac', '\x25', '\x97', '\x70', '\xf7', '\x09', '\x51',
- '\x39', '\x72', '\x39', '\x3c', '\xd0', '\x31', '\xe1', '\xc3', '\x02',
- '\x91', '\x14', '\x4d', '\x8f', '\x1d', '\x31', '\xab', '\x98', '\x7e',
- '\xe6', '\xbb', '\xab', '\x6a', '\xd9', '\xc5', '\x86', '\xaa', '\x4e',
- '\x6a', '\x48', '\xe9', '\xf8', '\xd7', '\xb3', '\x1d', '\xa0', '\xc5',
- '\xe6', '\xbf', '\x4c', '\x5a', '\x9b', '\xb5', '\x78', '\x01', '\xa3',
- '\x39', '\x7b', '\x5f', '\xbc', '\xb8', '\xa7', '\xc2', '\x71', '\xb0',
- '\x7b', '\xdd', '\xa1', '\x87', '\xa6', '\x54', '\x9c', '\xf6', '\x59',
- '\x81', '\xb1', '\x2c', '\xde', '\xc5', '\x8a', '\xa2', '\x06', '\x89',
- '\xb5', '\xc1', '\x7a', '\xbe', '\x0c', '\x9f', '\x3d', '\xde', '\x81',
- '\x48', '\x53', '\x71', '\x7b', '\x8d', '\xc7', '\xea', '\x87', '\xd7',
- '\xd1', '\xda', '\x94', '\xb4', '\xc5', '\xac', '\x1e', '\x83', '\xa3',
- '\x42', '\x7d', '\xe6', '\xab', '\x3f', '\xd6', '\x1c', '\xd6', '\x65',
- '\xc3', '\x60', '\xe9', '\x76', '\x54', '\x79', '\x3f', '\xeb', '\x65',
- '\x85', '\x4f', '\x60', '\x7d', '\xbb', '\x96', '\x03', '\x54', '\x2e',
- '\xd0', '\x1b', '\xe2', '\x6c', '\x2d', '\x91', '\xae', '\x33', '\x9c',
- '\x04', '\xc4', '\x44', '\x0a', '\x7d', '\x5f', '\xbb', '\x80', '\xa2',
- '\x01', '\xbc', '\x90', '\x81', '\xa5', '\xdc', '\x4a', '\xc8', '\x77',
- '\xc9', '\x8d', '\x34', '\x17', '\xe6', '\x2a', '\x7d', '\x02', '\x1e',
- '\x32', '\x3f', '\x7d', '\xd7', '\x0c', '\x80', '\x5b', '\xc6', '\x94',
- '\x6a', '\x42', '\x36', '\x05', '\x9f', '\x9e', '\xc5', '\x85', '\x9f',
- '\x60', '\xe3', '\x72', '\x73', '\x34', '\x39', '\x44', '\x75', '\x55',
- '\x60', '\x24', '\x7a', '\x8b', '\x09', '\x74', '\x84', '\x72', '\xfd',
- '\x91', '\x68', '\x93', '\x57', '\x9e', '\x70', '\x46', '\x4d', '\xe4',
- '\x30', '\x84', '\x5f', '\x20', '\x07', '\xad', '\xfd', '\x86', '\x32',
- '\xd3', '\xfb', '\xba', '\xaf', '\xd9', '\x61', '\x14', '\x3c', '\xe0',
- '\xa1', '\xa9', '\x51', '\x51', '\x0f', '\xad', '\x60'};
+ result = ReadNextPemMessage(&stream);
+ EXPECT_EQ(result.status, PemReadResult::kEof);
+}
TEST(CertificateViewTest, Parse) {
- quiche::QuicheStringPiece certificate(kTestCertificate,
- sizeof(kTestCertificate));
std::unique_ptr<CertificateView> view =
- CertificateView::ParseSingleCertificate(certificate);
+ CertificateView::ParseSingleCertificate(kTestCertificate);
ASSERT_TRUE(view != nullptr);
EXPECT_THAT(view->subject_alt_name_domains(),
@@ -140,5 +47,68 @@ TEST(CertificateViewTest, Parse) {
EXPECT_EQ(EVP_PKEY_id(view->public_key()), EVP_PKEY_RSA);
}
+TEST(CertificateViewTest, PemSingleCertificate) {
+ std::stringstream pem_stream(kTestCertificatePem);
+ std::vector<std::string> chain =
+ CertificateView::LoadPemFromStream(&pem_stream);
+ EXPECT_THAT(chain, ElementsAre(kTestCertificate));
+}
+
+TEST(CertificateViewTest, PemMultipleCertificates) {
+ std::stringstream pem_stream(kTestCertificateChainPem);
+ std::vector<std::string> chain =
+ CertificateView::LoadPemFromStream(&pem_stream);
+ EXPECT_THAT(chain,
+ ElementsAre(kTestCertificate, HasSubstr("QUIC Server Root CA")));
+}
+
+TEST(CertificateViewTest, PemNoCertificates) {
+ std::stringstream pem_stream("one\ntwo\nthree\n");
+ std::vector<std::string> chain =
+ CertificateView::LoadPemFromStream(&pem_stream);
+ EXPECT_TRUE(chain.empty());
+}
+
+TEST(CertificateViewTest, SignAndVerify) {
+ std::unique_ptr<CertificatePrivateKey> key =
+ CertificatePrivateKey::LoadFromDer(kTestCertificatePrivateKey);
+ ASSERT_TRUE(key != nullptr);
+
+ std::string data = "A really important message";
+ std::string signature = key->Sign(data, SSL_SIGN_RSA_PSS_RSAE_SHA256);
+ ASSERT_FALSE(signature.empty());
+
+ std::unique_ptr<CertificateView> view =
+ CertificateView::ParseSingleCertificate(kTestCertificate);
+ ASSERT_TRUE(view != nullptr);
+ EXPECT_TRUE(key->MatchesPublicKey(*view));
+
+ EXPECT_TRUE(
+ view->VerifySignature(data, signature, SSL_SIGN_RSA_PSS_RSAE_SHA256));
+ EXPECT_FALSE(view->VerifySignature("An unimportant message", signature,
+ SSL_SIGN_RSA_PSS_RSAE_SHA256));
+ EXPECT_FALSE(view->VerifySignature(data, "Not a signature",
+ SSL_SIGN_RSA_PSS_RSAE_SHA256));
+}
+
+TEST(CertificateViewTest, PrivateKeyPem) {
+ std::unique_ptr<CertificateView> view =
+ CertificateView::ParseSingleCertificate(kTestCertificate);
+ ASSERT_TRUE(view != nullptr);
+
+ std::stringstream pem_stream(kTestCertificatePrivateKeyPem);
+ std::unique_ptr<CertificatePrivateKey> pem_key =
+ CertificatePrivateKey::LoadPemFromStream(&pem_stream);
+ ASSERT_TRUE(pem_key != nullptr);
+ EXPECT_TRUE(pem_key->MatchesPublicKey(*view));
+
+ std::stringstream legacy_stream(kTestCertificatePrivateKeyLegacyPem);
+ std::unique_ptr<CertificatePrivateKey> legacy_key =
+ CertificatePrivateKey::LoadPemFromStream(&legacy_stream);
+ ASSERT_TRUE(legacy_key != nullptr);
+ EXPECT_TRUE(legacy_key->MatchesPublicKey(*view));
+}
+
} // namespace
+} // namespace test
} // namespace quic
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 d5b4635d1d4..2c92923b35b 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
@@ -50,6 +50,17 @@ CryptoHandshakeMessage& CryptoHandshakeMessage::operator=(
CryptoHandshakeMessage& CryptoHandshakeMessage::operator=(
CryptoHandshakeMessage&& other) = default;
+bool CryptoHandshakeMessage::operator==(
+ const CryptoHandshakeMessage& rhs) const {
+ return tag_ == rhs.tag_ && tag_value_map_ == rhs.tag_value_map_ &&
+ minimum_size_ == rhs.minimum_size_;
+}
+
+bool CryptoHandshakeMessage::operator!=(
+ const CryptoHandshakeMessage& rhs) const {
+ return !(*this == rhs);
+}
+
void CryptoHandshakeMessage::Clear() {
tag_ = 0;
tag_value_map_.clear();
@@ -279,7 +290,6 @@ std::string CryptoHandshakeMessage::DebugStringInternal(size_t indent) const {
case kIRTT:
case kMIUS:
case kMIBS:
- case kSCLS:
case kTCID:
case kMAD:
// uint32_t value
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h
index 409738a1f81..95390507a6a 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h
@@ -30,6 +30,9 @@ class QUIC_EXPORT_PRIVATE CryptoHandshakeMessage {
CryptoHandshakeMessage& operator=(const CryptoHandshakeMessage& other);
CryptoHandshakeMessage& operator=(CryptoHandshakeMessage&& other);
+ bool operator==(const CryptoHandshakeMessage& rhs) const;
+ bool operator!=(const CryptoHandshakeMessage& rhs) const;
+
// Clears state.
void Clear();
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 8af8a0429d1..172fd822d0b 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
@@ -27,7 +27,7 @@ namespace quic {
typedef std::string ServerConfigID;
// The following tags have been deprecated and should not be reused:
-// "1CON", "BBQ4", "NCON", "RCID", "SREJ", "TBKP", "TB10"
+// "1CON", "BBQ4", "NCON", "RCID", "SREJ", "TBKP", "TB10", "SCLS", "SMHL"
// clang-format off
const QuicTag kCHLO = TAG('C', 'H', 'L', 'O'); // Client hello
@@ -121,6 +121,10 @@ const QuicTag kB2NA = TAG('B', '2', 'N', 'A'); // For BBRv2, do not add ack
// height to queueing threshold
const QuicTag kB2RP = TAG('B', '2', 'R', 'P'); // For BBRv2, run PROBE_RTT on
// the regular schedule
+const QuicTag kB2CL = TAG('B', '2', 'C', 'L'); // For BBRv2, allow PROBE_BW
+ // cwnd to be below BDP + ack
+ // height.
+const QuicTag kB2LO = TAG('B', '2', 'L', 'O'); // Ignore inflight_lo in BBR2
const QuicTag kBSAO = TAG('B', 'S', 'A', 'O'); // Avoid Overestimation in
// Bandwidth Sampler with ack
// aggregation
@@ -184,10 +188,6 @@ const QuicTag kILD4 = TAG('I', 'L', 'D', '4'); // IETF style loss detection
// threshold
const QuicTag kRUNT = TAG('R', 'U', 'N', 'T'); // No packet threshold loss
// detection for "runt" packet.
-// 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
- // settings frame.
const QuicTag kNSTP = TAG('N', 'S', 'T', 'P'); // No stop waiting frames.
const QuicTag kNRTT = TAG('N', 'R', 'T', 'T'); // Ignore initial RTT
@@ -226,6 +226,8 @@ const QuicTag kPLE2 = TAG('P', 'L', 'E', '2'); // Arm the 1st PTO with
// and at least 1.5*srtt from
// last sent packet.
+const QuicTag kELDT = TAG('E', 'L', 'D', 'T'); // Enable Loss Detection Tuning
+
// 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
// peer.
@@ -251,6 +253,17 @@ 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 kBWP0 = TAG('B', 'W', 'P', '0'); // QUIC Initial CWND - SPDY
+ // priority 0.
+const QuicTag kBWP1 = TAG('B', 'W', 'P', '1'); // QUIC Initial CWND - SPDY
+ // priorities 0 and 1.
+const QuicTag kBWP2 = TAG('B', 'W', 'P', '2'); // QUIC Initial CWND - SPDY
+ // priorities 0, 1 and 2.
+const QuicTag kBWP3 = TAG('B', 'W', 'P', '3'); // QUIC Initial CWND - SPDY
+ // priorities 0, 1, 2 and 3.
+const QuicTag kBWP4 = TAG('B', 'W', 'P', '4'); // QUIC Initial CWND - SPDY
+ // priorities >= 0, 1, 2 , 3 and
+ // 4.
const QuicTag kBWS7 = TAG('B', 'W', 'S', '7'); // QUIC Initial CWND - Enabled
// with 0.75 * default
// multiplier.
@@ -294,7 +307,6 @@ const QuicTag kAEAD = TAG('A', 'E', 'A', 'D'); // Authenticated
const QuicTag kCOPT = TAG('C', 'O', 'P', 'T'); // Connection options
const QuicTag kCLOP = TAG('C', 'L', 'O', 'P'); // Client connection options
const QuicTag kICSL = TAG('I', 'C', 'S', 'L'); // Idle network timeout
-const QuicTag kSCLS = TAG('S', 'C', 'L', 'S'); // Silently close on timeout
const QuicTag kMIBS = TAG('M', 'I', 'D', 'S'); // Max incoming bidi streams
const QuicTag kMIUS = TAG('M', 'I', 'U', 'S'); // Max incoming unidi streams
const QuicTag kADE = TAG('A', 'D', 'E', 0); // Ack Delay Exponent (IETF
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 4cf618b8a6a..ee9dc53cf64 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
@@ -223,7 +223,7 @@ class CryptoServerTest : public QuicTestWithParam<TestParams> {
bool called = false;
QuicSocketAddress server_address(QuicIpAddress::Any4(), 5);
config_.ValidateClientHello(
- message, client_address_.host(), server_address,
+ message, client_address_, server_address,
supported_versions_.front().transport_version, &clock_, signed_config_,
std::make_unique<ValidateCallback>(this, true, "", &called));
EXPECT_TRUE(called);
@@ -241,7 +241,7 @@ class CryptoServerTest : public QuicTestWithParam<TestParams> {
bool* called) {
QuicSocketAddress server_address(QuicIpAddress::Any4(), 5);
config_.ValidateClientHello(
- message, client_address_.host(), server_address,
+ message, client_address_, server_address,
supported_versions_.front().transport_version, &clock_, signed_config_,
std::make_unique<ValidateCallback>(this, false, error_substr, called));
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/curve25519_key_exchange.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/curve25519_key_exchange.cc
index f4cc7937d7b..2f19e9d486c 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/curve25519_key_exchange.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/curve25519_key_exchange.cc
@@ -5,6 +5,7 @@
#include "net/third_party/quiche/src/quic/core/crypto/curve25519_key_exchange.h"
#include <cstdint>
+#include <cstring>
#include <string>
#include "third_party/boringssl/src/include/openssl/curve25519.h"
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/p256_key_exchange.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/p256_key_exchange.cc
index a1b45ba5f9c..01f345de824 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/p256_key_exchange.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/p256_key_exchange.cc
@@ -5,6 +5,7 @@
#include "net/third_party/quiche/src/quic/core/crypto/p256_key_exchange.h"
#include <cstdint>
+#include <cstring>
#include <memory>
#include <string>
#include <utility>
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 e208b94c26c..c4224f46607 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
@@ -119,6 +119,7 @@ class QUIC_EXPORT_PRIVATE ProofSource {
//
// Callers should expect that |callback| might be invoked synchronously.
virtual void GetProof(const QuicSocketAddress& server_address,
+ const QuicSocketAddress& client_address,
const std::string& hostname,
const std::string& server_config,
QuicTransportVersion transport_version,
@@ -128,6 +129,7 @@ class QUIC_EXPORT_PRIVATE ProofSource {
// Returns the certificate chain for |hostname| in leaf-first order.
virtual QuicReferenceCountedPointer<Chain> GetCertChain(
const QuicSocketAddress& server_address,
+ const QuicSocketAddress& client_address,
const std::string& hostname) = 0;
// Computes a signature using the private key of the certificate for
@@ -140,10 +142,59 @@ class QUIC_EXPORT_PRIVATE ProofSource {
// Callers should expect that |callback| might be invoked synchronously.
virtual void ComputeTlsSignature(
const QuicSocketAddress& server_address,
+ const QuicSocketAddress& client_address,
const std::string& hostname,
uint16_t signature_algorithm,
quiche::QuicheStringPiece in,
std::unique_ptr<SignatureCallback> callback) = 0;
+
+ class QUIC_EXPORT_PRIVATE DecryptCallback {
+ public:
+ DecryptCallback() = default;
+ virtual ~DecryptCallback() = default;
+
+ virtual void Run(std::vector<uint8_t> plaintext) = 0;
+
+ private:
+ DecryptCallback(const Callback&) = delete;
+ DecryptCallback& operator=(const Callback&) = delete;
+ };
+
+ // TicketCrypter is an interface for managing encryption and decryption of TLS
+ // session tickets. A TicketCrypter gets used as an
+ // SSL_CTX_set_ticket_aead_method in BoringSSL, which has a synchronous
+ // Encrypt/Seal operation and a potentially asynchronous Decrypt/Open
+ // operation. This interface allows for ticket decryptions to be performed on
+ // a remote service.
+ class QUIC_EXPORT_PRIVATE TicketCrypter {
+ public:
+ TicketCrypter() = default;
+ virtual ~TicketCrypter() = default;
+
+ // MaxOverhead returns the maximum number of bytes of overhead that may get
+ // added when encrypting the ticket.
+ virtual size_t MaxOverhead() = 0;
+
+ // Encrypt takes a serialized TLS session ticket in |in|, encrypts it, and
+ // returns the encrypted ticket. The resulting value must not be larger than
+ // MaxOverhead bytes larger than |in|. If encryption fails, this method
+ // returns an empty vector.
+ virtual std::vector<uint8_t> Encrypt(quiche::QuicheStringPiece in) = 0;
+
+ // Decrypt takes an encrypted ticket |in|, decrypts it, and calls
+ // |callback->Run| with the decrypted ticket, which must not be larger than
+ // |in|. If decryption fails, the callback is invoked with an empty
+ // vector.
+ virtual void Decrypt(quiche::QuicheStringPiece in,
+ std::unique_ptr<DecryptCallback> callback) = 0;
+ };
+
+ // Returns the TicketCrypter used for encrypting and decrypting TLS
+ // session tickets, or nullptr if that functionality is not supported. The
+ // TicketCrypter returned (if not nullptr) must be valid for the lifetime of
+ // the ProofSource, and the caller does not take ownership of said
+ // TicketCrypter.
+ virtual TicketCrypter* GetTicketCrypter() = 0;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source_x509.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source_x509.cc
new file mode 100644
index 00000000000..6afc65f557a
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source_x509.cc
@@ -0,0 +1,135 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/core/crypto/proof_source_x509.h"
+
+#include <memory>
+
+#include "third_party/boringssl/src/include/openssl/ssl.h"
+#include "net/third_party/quiche/src/quic/core/crypto/certificate_view.h"
+#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h"
+#include "net/third_party/quiche/src/quic/core/quic_data_writer.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"
+#include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h"
+#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
+
+namespace quic {
+
+std::unique_ptr<ProofSourceX509> ProofSourceX509::Create(
+ QuicReferenceCountedPointer<Chain> default_chain,
+ CertificatePrivateKey default_key) {
+ std::unique_ptr<ProofSourceX509> result(new ProofSourceX509());
+ if (!result->AddCertificateChain(default_chain, std::move(default_key))) {
+ return nullptr;
+ }
+ result->default_certificate_ = &result->certificates_.front();
+ return result;
+}
+
+void ProofSourceX509::GetProof(
+ const QuicSocketAddress& /*server_address*/,
+ const QuicSocketAddress& /*client_address*/,
+ const std::string& hostname,
+ const std::string& server_config,
+ QuicTransportVersion /*transport_version*/,
+ quiche::QuicheStringPiece chlo_hash,
+ std::unique_ptr<ProofSource::Callback> callback) {
+ QuicCryptoProof proof;
+
+ size_t payload_size = sizeof(kProofSignatureLabel) + sizeof(uint32_t) +
+ chlo_hash.size() + server_config.size();
+ auto payload = std::make_unique<char[]>(payload_size);
+ QuicDataWriter payload_writer(payload_size, payload.get(),
+ quiche::Endianness::HOST_BYTE_ORDER);
+ bool success = payload_writer.WriteBytes(kProofSignatureLabel,
+ sizeof(kProofSignatureLabel)) &&
+ payload_writer.WriteUInt32(chlo_hash.size()) &&
+ payload_writer.WriteStringPiece(chlo_hash) &&
+ payload_writer.WriteStringPiece(server_config);
+ if (!success) {
+ callback->Run(/*ok=*/false, nullptr, proof, nullptr);
+ return;
+ }
+
+ Certificate* certificate = GetCertificate(hostname);
+ proof.signature = certificate->key.Sign(
+ quiche::QuicheStringPiece(payload.get(), payload_size),
+ SSL_SIGN_RSA_PSS_RSAE_SHA256);
+ callback->Run(/*ok=*/!proof.signature.empty(), certificate->chain, proof,
+ nullptr);
+}
+
+QuicReferenceCountedPointer<ProofSource::Chain> ProofSourceX509::GetCertChain(
+ const QuicSocketAddress& /*server_address*/,
+ const QuicSocketAddress& /*client_address*/,
+ const std::string& hostname) {
+ return GetCertificate(hostname)->chain;
+}
+
+void ProofSourceX509::ComputeTlsSignature(
+ const QuicSocketAddress& /*server_address*/,
+ const QuicSocketAddress& /*client_address*/,
+ const std::string& hostname,
+ uint16_t signature_algorithm,
+ quiche::QuicheStringPiece in,
+ std::unique_ptr<ProofSource::SignatureCallback> callback) {
+ std::string signature =
+ GetCertificate(hostname)->key.Sign(in, signature_algorithm);
+ callback->Run(/*ok=*/!signature.empty(), signature, nullptr);
+}
+
+ProofSource::TicketCrypter* ProofSourceX509::GetTicketCrypter() {
+ return nullptr;
+}
+
+bool ProofSourceX509::AddCertificateChain(
+ QuicReferenceCountedPointer<Chain> chain,
+ CertificatePrivateKey key) {
+ if (chain->certs.empty()) {
+ QUIC_BUG << "Empty certificate chain supplied.";
+ return false;
+ }
+
+ std::unique_ptr<CertificateView> leaf =
+ CertificateView::ParseSingleCertificate(chain->certs[0]);
+ if (leaf == nullptr) {
+ QUIC_BUG << "Unable to parse X.509 leaf certificate in the supplied chain.";
+ return false;
+ }
+ if (!key.MatchesPublicKey(*leaf)) {
+ QUIC_BUG << "Private key does not match the leaf certificate.";
+ return false;
+ }
+
+ certificates_.push_front(Certificate{
+ .chain = chain,
+ .key = std::move(key),
+ });
+ Certificate* certificate = &certificates_.front();
+
+ for (quiche::QuicheStringPiece host : leaf->subject_alt_name_domains()) {
+ certificate_map_[std::string(host)] = certificate;
+ }
+ return true;
+}
+
+ProofSourceX509::Certificate* ProofSourceX509::GetCertificate(
+ const std::string& hostname) const {
+ auto it = certificate_map_.find(hostname);
+ if (it != certificate_map_.end()) {
+ return it->second;
+ }
+ auto dot_pos = hostname.find('.');
+ if (dot_pos != std::string::npos) {
+ std::string wildcard = quiche::QuicheStrCat("*", hostname.substr(dot_pos));
+ it = certificate_map_.find(wildcard);
+ if (it != certificate_map_.end()) {
+ return it->second;
+ }
+ }
+ return default_certificate_;
+}
+
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source_x509.h b/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source_x509.h
new file mode 100644
index 00000000000..8632d4bfe95
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source_x509.h
@@ -0,0 +1,76 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_CORE_CRYPTO_PROOF_SOURCE_X509_H_
+#define QUICHE_QUIC_CORE_CRYPTO_PROOF_SOURCE_X509_H_
+
+#include <forward_list>
+#include <memory>
+
+#include "net/third_party/quiche/src/quic/core/crypto/certificate_view.h"
+#include "net/third_party/quiche/src/quic/core/crypto/proof_source.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_macros.h"
+#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
+
+namespace quic {
+
+// ProofSourceX509 accepts X.509 certificates with private keys and picks a
+// certificate internally based on its SubjectAltName value.
+class QUIC_EXPORT_PRIVATE ProofSourceX509 : public ProofSource {
+ public:
+ // Creates a proof source that uses |default_chain| when no SubjectAltName
+ // value matches. Returns nullptr if |default_chain| is invalid.
+ static std::unique_ptr<ProofSourceX509> Create(
+ QuicReferenceCountedPointer<Chain> default_chain,
+ CertificatePrivateKey default_key);
+
+ // ProofSource implementation.
+ void GetProof(const QuicSocketAddress& server_address,
+ const QuicSocketAddress& client_address,
+ const std::string& hostname,
+ const std::string& server_config,
+ QuicTransportVersion transport_version,
+ quiche::QuicheStringPiece chlo_hash,
+ std::unique_ptr<Callback> callback) override;
+ QuicReferenceCountedPointer<Chain> GetCertChain(
+ const QuicSocketAddress& server_address,
+ const QuicSocketAddress& client_address,
+ const std::string& hostname) override;
+ void ComputeTlsSignature(
+ const QuicSocketAddress& server_address,
+ const QuicSocketAddress& client_address,
+ const std::string& hostname,
+ uint16_t signature_algorithm,
+ quiche::QuicheStringPiece in,
+ std::unique_ptr<SignatureCallback> callback) override;
+ TicketCrypter* GetTicketCrypter() override;
+
+ // Adds a certificate chain to the verifier. Returns false if the chain is
+ // not valid. Newer certificates will override older certificates with the
+ // same SubjectAltName value.
+ QUIC_MUST_USE_RESULT bool AddCertificateChain(
+ QuicReferenceCountedPointer<Chain> chain,
+ CertificatePrivateKey key);
+
+ private:
+ ProofSourceX509() = default;
+
+ struct QUIC_EXPORT_PRIVATE Certificate {
+ QuicReferenceCountedPointer<Chain> chain;
+ CertificatePrivateKey key;
+ };
+
+ // Looks up certficiate for hostname, returns the default if no certificate is
+ // found.
+ Certificate* GetCertificate(const std::string& hostname) const;
+
+ std::forward_list<Certificate> certificates_;
+ Certificate* default_certificate_;
+ QuicUnorderedMap<std::string, Certificate*> certificate_map_;
+};
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_CORE_CRYPTO_PROOF_SOURCE_X509_H_
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source_x509_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source_x509_test.cc
new file mode 100644
index 00000000000..23311d08232
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source_x509_test.cc
@@ -0,0 +1,136 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/core/crypto/proof_source_x509.h"
+
+#include <memory>
+
+#include "third_party/boringssl/src/include/openssl/ssl.h"
+#include "net/third_party/quiche/src/quic/core/crypto/certificate_view.h"
+#include "net/third_party/quiche/src/quic/core/crypto/proof_source.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_reference_counted.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+#include "net/third_party/quiche/src/quic/test_tools/test_certificates.h"
+#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
+
+namespace quic {
+namespace test {
+namespace {
+
+QuicReferenceCountedPointer<ProofSource::Chain> MakeChain(
+ quiche::QuicheStringPiece cert) {
+ return QuicReferenceCountedPointer<ProofSource::Chain>(
+ new ProofSource::Chain(std::vector<std::string>{std::string(cert)}));
+}
+
+class ProofSourceX509Test : public QuicTest {
+ public:
+ ProofSourceX509Test()
+ : test_chain_(MakeChain(kTestCertificate)),
+ wildcard_chain_(MakeChain(kWildcardCertificate)),
+ test_key_(
+ CertificatePrivateKey::LoadFromDer(kTestCertificatePrivateKey)),
+ wildcard_key_(CertificatePrivateKey::LoadFromDer(
+ kWildcardCertificatePrivateKey)) {
+ CHECK(test_key_ != nullptr);
+ CHECK(wildcard_key_ != nullptr);
+ }
+
+ protected:
+ QuicReferenceCountedPointer<ProofSource::Chain> test_chain_, wildcard_chain_;
+ std::unique_ptr<CertificatePrivateKey> test_key_, wildcard_key_;
+};
+
+TEST_F(ProofSourceX509Test, AddCertificates) {
+ std::unique_ptr<ProofSourceX509> proof_source =
+ ProofSourceX509::Create(test_chain_, std::move(*test_key_));
+ ASSERT_TRUE(proof_source != nullptr);
+ EXPECT_TRUE(proof_source->AddCertificateChain(wildcard_chain_,
+ std::move(*wildcard_key_)));
+}
+
+TEST_F(ProofSourceX509Test, AddCertificateKeyMismatch) {
+ std::unique_ptr<ProofSourceX509> proof_source =
+ ProofSourceX509::Create(test_chain_, std::move(*test_key_));
+ ASSERT_TRUE(proof_source != nullptr);
+ test_key_ = CertificatePrivateKey::LoadFromDer(kTestCertificatePrivateKey);
+ bool result;
+ EXPECT_QUIC_BUG(result = proof_source->AddCertificateChain(
+ wildcard_chain_, std::move(*test_key_)),
+ "Private key does not match");
+}
+
+TEST_F(ProofSourceX509Test, CertificateSelection) {
+ std::unique_ptr<ProofSourceX509> proof_source =
+ ProofSourceX509::Create(test_chain_, std::move(*test_key_));
+ ASSERT_TRUE(proof_source != nullptr);
+ ASSERT_TRUE(proof_source->AddCertificateChain(wildcard_chain_,
+ std::move(*wildcard_key_)));
+
+ // Default certificate.
+ EXPECT_EQ(proof_source
+ ->GetCertChain(QuicSocketAddress(), QuicSocketAddress(),
+ "unknown.test")
+ ->certs[0],
+ kTestCertificate);
+ // mail.example.org is explicitly a SubjectAltName in kTestCertificate.
+ EXPECT_EQ(proof_source
+ ->GetCertChain(QuicSocketAddress(), QuicSocketAddress(),
+ "mail.example.org")
+ ->certs[0],
+ kTestCertificate);
+ // www.foo.test is in kWildcardCertificate.
+ EXPECT_EQ(proof_source
+ ->GetCertChain(QuicSocketAddress(), QuicSocketAddress(),
+ "www.foo.test")
+ ->certs[0],
+ kWildcardCertificate);
+ // *.wildcard.test is in kWildcardCertificate.
+ EXPECT_EQ(proof_source
+ ->GetCertChain(QuicSocketAddress(), QuicSocketAddress(),
+ "www.wildcard.test")
+ ->certs[0],
+ kWildcardCertificate);
+ EXPECT_EQ(proof_source
+ ->GetCertChain(QuicSocketAddress(), QuicSocketAddress(),
+ "etc.wildcard.test")
+ ->certs[0],
+ kWildcardCertificate);
+ // wildcard.test itself is not in kWildcardCertificate.
+ EXPECT_EQ(proof_source
+ ->GetCertChain(QuicSocketAddress(), QuicSocketAddress(),
+ "wildcard.test")
+ ->certs[0],
+ kTestCertificate);
+}
+
+TEST_F(ProofSourceX509Test, TlsSignature) {
+ class Callback : public ProofSource::SignatureCallback {
+ public:
+ void Run(bool ok,
+ std::string signature,
+ std::unique_ptr<ProofSource::Details> /*details*/) override {
+ ASSERT_TRUE(ok);
+ std::unique_ptr<CertificateView> view =
+ CertificateView::ParseSingleCertificate(kTestCertificate);
+ EXPECT_TRUE(view->VerifySignature("Test data", signature,
+ SSL_SIGN_RSA_PSS_RSAE_SHA256));
+ }
+ };
+
+ std::unique_ptr<ProofSourceX509> proof_source =
+ ProofSourceX509::Create(test_chain_, std::move(*test_key_));
+ ASSERT_TRUE(proof_source != nullptr);
+
+ proof_source->ComputeTlsSignature(QuicSocketAddress(), QuicSocketAddress(),
+ "example.com", SSL_SIGN_RSA_PSS_RSAE_SHA256,
+ "Test data", std::make_unique<Callback>());
+}
+
+} // namespace
+} // namespace test
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/proof_verifier.h b/chromium/net/third_party/quiche/src/quic/core/crypto/proof_verifier.h
index 12036d69887..0380b8a87d8 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/proof_verifier.h
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/proof_verifier.h
@@ -102,6 +102,7 @@ class QUIC_EXPORT_PRIVATE ProofVerifier {
// In this case, the ProofVerifier will take ownership of |callback|.
virtual QuicAsyncStatus VerifyCertChain(
const std::string& hostname,
+ const uint16_t port,
const std::vector<std::string>& certs,
const std::string& ocsp_response,
const std::string& cert_sct,
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 e4f7061a82c..e3867c8e7b2 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
@@ -42,13 +42,13 @@ struct QUIC_EXPORT_PRIVATE QuicResumptionState {
// 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<TransportParameters> transport_params;
+ TransportParameters* 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<uint8_t> application_state;
+ ApplicationState* application_state;
};
// SessionCache is an interface for managing storing and retrieving
@@ -57,15 +57,16 @@ 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.
+ // Inserts |session|, |params|, and |application_states| into the cache, keyed
+ // by |server_id|. Insert is first called after all three values are present.
+ // The ownership of |session| is transferred to the cache, while other two are
+ // copied. Multiple sessions might need to be inserted for a connection.
+ // SessionCache implementations should support storing
+ // multiple entries per server ID.
virtual void Insert(const QuicServerId& server_id,
- std::unique_ptr<QuicResumptionState> state) = 0;
+ bssl::UniquePtr<SSL_SESSION> session,
+ const TransportParameters& params,
+ const ApplicationState* application_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
@@ -392,10 +393,14 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig {
// Saves the |alpn| that will be passed in QUIC's CHLO message.
void set_alpn(const std::string& alpn) { alpn_ = alpn; }
+ // Saves the pre-shared key used during the handshake.
void set_pre_shared_key(quiche::QuicheStringPiece psk) {
pre_shared_key_ = std::string(psk);
}
+ // Returns the pre-shared key used during the handshake.
+ const std::string& pre_shared_key() const { return pre_shared_key_; }
+
bool pad_inchoate_hello() const { return pad_inchoate_hello_; }
void set_pad_inchoate_hello(bool new_value) {
pad_inchoate_hello_ = new_value;
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 4dc34ffd13f..9cb089bf0e8 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
@@ -46,6 +46,7 @@
#include "net/third_party/quiche/src/quic/platform/api/quic_hostname_utils.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_reference_counted.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_text_utils.h"
@@ -242,7 +243,7 @@ QuicCryptoServerConfig::QuicCryptoServerConfig(
proof_source_(std::move(proof_source)),
client_cert_mode_(ClientCertMode::kNone),
key_exchange_source_(std::move(key_exchange_source)),
- ssl_ctx_(TlsServerConnection::CreateSslCtx()),
+ ssl_ctx_(TlsServerConnection::CreateSslCtx(proof_source_.get())),
source_address_token_future_secs_(3600),
source_address_token_lifetime_secs_(86400),
enable_serving_sct_(false),
@@ -524,7 +525,7 @@ void QuicCryptoServerConfig::GetConfigIds(
void QuicCryptoServerConfig::ValidateClientHello(
const CryptoHandshakeMessage& client_hello,
- const QuicIpAddress& client_ip,
+ const QuicSocketAddress& client_address,
const QuicSocketAddress& server_address,
QuicTransportVersion version,
const QuicClock* clock,
@@ -533,8 +534,8 @@ void QuicCryptoServerConfig::ValidateClientHello(
const QuicWallTime now(clock->WallNow());
QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result> result(
- new ValidateClientHelloResultCallback::Result(client_hello, client_ip,
- now));
+ new ValidateClientHelloResultCallback::Result(
+ client_hello, client_address.host(), now));
quiche::QuicheStringPiece requested_scid;
client_hello.GetStringPiece(kSCID, &requested_scid);
@@ -551,8 +552,8 @@ void QuicCryptoServerConfig::ValidateClientHello(
signed_config->chain = nullptr;
signed_config->proof.signature = "";
signed_config->proof.leaf_cert_scts = "";
- EvaluateClientHello(server_address, version, configs, result,
- std::move(done_cb));
+ EvaluateClientHello(server_address, client_address, version, configs,
+ result, std::move(done_cb));
} else {
done_cb->Run(result, /* details = */ nullptr);
}
@@ -717,8 +718,9 @@ void QuicCryptoServerConfig::ProcessClientHello(
this, std::move(context), configs);
DCHECK(proof_source_.get());
- proof_source_->GetProof(server_address, sni, configs.primary->serialized,
- transport_version, chlo_hash, std::move(cb));
+ proof_source_->GetProof(server_address, client_address, sni,
+ configs.primary->serialized, transport_version,
+ chlo_hash, std::move(cb));
return;
}
@@ -1016,10 +1018,12 @@ void QuicCryptoServerConfig::SendRejectWithFallbackConfig(
const std::string sni(context->info().sni);
const QuicTransportVersion transport_version = context->transport_version();
+ const QuicSocketAddress& client_address = context->client_address();
auto cb = std::make_unique<SendRejectWithFallbackConfigCallback>(
this, std::move(context), fallback_config);
- proof_source_->GetProof(server_address, sni, fallback_config->serialized,
- transport_version, chlo_hash, std::move(cb));
+ proof_source_->GetProof(server_address, client_address, sni,
+ fallback_config->serialized, transport_version,
+ chlo_hash, std::move(cb));
}
void QuicCryptoServerConfig::SendRejectWithFallbackConfigAfterGetProof(
@@ -1196,6 +1200,7 @@ void QuicCryptoServerConfig::SelectNewPrimaryConfig(
void QuicCryptoServerConfig::EvaluateClientHello(
const QuicSocketAddress& server_address,
+ const QuicSocketAddress& client_address,
QuicTransportVersion /*version*/,
const Configs& configs,
QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
@@ -1270,7 +1275,8 @@ void QuicCryptoServerConfig::EvaluateClientHello(
}
QuicReferenceCountedPointer<ProofSource::Chain> chain =
- proof_source_->GetCertChain(server_address, std::string(info->sni));
+ proof_source_->GetCertChain(server_address, client_address,
+ std::string(info->sni));
if (!chain) {
info->reject_reasons.push_back(SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE);
} else if (!ValidateExpectedLeafCertificate(client_hello, chain->certs)) {
@@ -1303,7 +1309,7 @@ void QuicCryptoServerConfig::BuildServerConfigUpdateMessage(
quiche::QuicheStringPiece chlo_hash,
const SourceAddressTokens& previous_source_address_tokens,
const QuicSocketAddress& server_address,
- const QuicIpAddress& client_ip,
+ const QuicSocketAddress& client_address,
const QuicClock* clock,
QuicRandom* rand,
QuicCompressedCertsCache* compressed_certs_cache,
@@ -1318,8 +1324,8 @@ void QuicCryptoServerConfig::BuildServerConfigUpdateMessage(
serialized = primary_config_->serialized;
common_cert_sets = primary_config_->common_cert_sets;
source_address_token = NewSourceAddressToken(
- *primary_config_, previous_source_address_tokens, client_ip, rand,
- clock->WallNow(), cached_network_params);
+ *primary_config_, previous_source_address_tokens, client_address.host(),
+ rand, clock->WallNow(), cached_network_params);
}
CryptoHandshakeMessage message;
@@ -1332,8 +1338,9 @@ void QuicCryptoServerConfig::BuildServerConfigUpdateMessage(
this, compressed_certs_cache, common_cert_sets, params,
std::move(message), std::move(cb));
- proof_source_->GetProof(server_address, params.sni, serialized, version,
- chlo_hash, std::move(proof_source_cb));
+ proof_source_->GetProof(server_address, client_address, params.sni,
+ serialized, version, chlo_hash,
+ std::move(proof_source_cb));
}
QuicCryptoServerConfig::BuildServerConfigUpdateMessageProofSourceCallback::
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 4a8cb737c98..9f2db603416 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
@@ -294,7 +294,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerConfig {
// completion of an asynchronous operation.
void ValidateClientHello(
const CryptoHandshakeMessage& client_hello,
- const QuicIpAddress& client_ip,
+ const QuicSocketAddress& client_address,
const QuicSocketAddress& server_address,
QuicTransportVersion version,
const QuicClock* clock,
@@ -360,7 +360,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerConfig {
quiche::QuicheStringPiece chlo_hash,
const SourceAddressTokens& previous_source_address_tokens,
const QuicSocketAddress& server_address,
- const QuicIpAddress& client_ip,
+ const QuicSocketAddress& client_address,
const QuicClock* clock,
QuicRandom* rand,
QuicCompressedCertsCache* compressed_certs_cache,
@@ -432,6 +432,8 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerConfig {
SSL_CTX* ssl_ctx() const;
+ // Pre-shared key used during the handshake.
+ const std::string& pre_shared_key() const { return pre_shared_key_; }
void set_pre_shared_key(quiche::QuicheStringPiece psk) {
pre_shared_key_ = std::string(psk);
}
@@ -551,6 +553,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerConfig {
// are written to |client_hello_state->info|.
void EvaluateClientHello(
const QuicSocketAddress& server_address,
+ const QuicSocketAddress& client_address,
QuicTransportVersion version,
const Configs& configs,
QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
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 8dd1108b37f..6f0c047b95b 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
@@ -481,7 +481,7 @@ TEST_F(CryptoServerConfigsTest, AdvancePrimaryViaValidate) {
test_peer_.SelectNewPrimaryConfig(1000);
test_peer_.CheckConfigs({{"a", true}, {"b", false}});
CryptoHandshakeMessage client_hello;
- QuicIpAddress client_ip;
+ QuicSocketAddress client_address;
QuicSocketAddress server_address;
QuicTransportVersion transport_version = QUIC_VERSION_UNSUPPORTED;
for (const ParsedQuicVersion& version : AllSupportedVersions()) {
@@ -497,7 +497,7 @@ TEST_F(CryptoServerConfigsTest, AdvancePrimaryViaValidate) {
std::unique_ptr<ValidateClientHelloResultCallback> done_cb(
new ValidateCallback);
clock.AdvanceTime(QuicTime::Delta::FromSeconds(1100));
- config_.ValidateClientHello(client_hello, client_ip, server_address,
+ config_.ValidateClientHello(client_hello, client_address, server_address,
transport_version, &clock, signed_config,
std::move(done_cb));
test_peer_.CheckConfigs({{"a", false}, {"b", true}});
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/tls_connection.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/tls_connection.cc
index b0d2147c286..75d28c55d60 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/tls_connection.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/tls_connection.cc
@@ -108,18 +108,10 @@ TlsConnection* TlsConnection::ConnectionFromSsl(const SSL* ssl) {
ssl, SslIndexSingleton::GetInstance()->ssl_ex_data_index_connection()));
}
-// TODO(nharper): Once
-// https://boringssl-review.googlesource.com/c/boringssl/+/40127 lands and is
-// rolled into google3, remove the BORINGSSL_API_VERSION check.
const SSL_QUIC_METHOD TlsConnection::kSslQuicMethod{
-#if BORINGSSL_API_VERSION < 10
- TlsConnection::SetEncryptionSecretCallback,
-#else
- TlsConnection::SetReadSecretCallback, TlsConnection::SetWriteSecretCallback,
-#endif
- TlsConnection::WriteMessageCallback, TlsConnection::FlushFlightCallback,
- TlsConnection::SendAlertCallback
-};
+ TlsConnection::SetReadSecretCallback, TlsConnection::SetWriteSecretCallback,
+ TlsConnection::WriteMessageCallback, TlsConnection::FlushFlightCallback,
+ TlsConnection::SendAlertCallback};
// static
int TlsConnection::SetEncryptionSecretCallback(
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 bdc941ade7c..54db5455ca5 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
@@ -4,6 +4,9 @@
#include "net/third_party/quiche/src/quic/core/crypto/tls_server_connection.h"
+#include "third_party/boringssl/src/include/openssl/ssl.h"
+#include "net/third_party/quiche/src/quic/core/crypto/proof_source.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
namespace quic {
@@ -13,12 +16,24 @@ TlsServerConnection::TlsServerConnection(SSL_CTX* ssl_ctx, Delegate* delegate)
delegate_(delegate) {}
// static
-bssl::UniquePtr<SSL_CTX> TlsServerConnection::CreateSslCtx() {
+bssl::UniquePtr<SSL_CTX> TlsServerConnection::CreateSslCtx(
+ ProofSource* proof_source) {
bssl::UniquePtr<SSL_CTX> ssl_ctx = TlsConnection::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);
+ // We don't actually need the TicketCrypter here, but we need to know
+ // whether it's set.
+ if (GetQuicReloadableFlag(quic_enable_tls_resumption) &&
+ proof_source->GetTicketCrypter()) {
+ SSL_CTX_set_ticket_aead_method(ssl_ctx.get(),
+ &TlsServerConnection::kSessionTicketMethod);
+ if (GetQuicReloadableFlag(quic_enable_zero_rtt_for_tls)) {
+ SSL_CTX_set_early_data_enabled(ssl_ctx.get(), 1);
+ }
+ } else {
+ SSL_CTX_set_options(ssl_ctx.get(), SSL_OP_NO_TICKET);
+ }
return ssl_ctx;
}
@@ -81,4 +96,41 @@ ssl_private_key_result_t TlsServerConnection::PrivateKeyComplete(
max_out);
}
+// static
+const SSL_TICKET_AEAD_METHOD TlsServerConnection::kSessionTicketMethod{
+ TlsServerConnection::SessionTicketMaxOverhead,
+ TlsServerConnection::SessionTicketSeal,
+ TlsServerConnection::SessionTicketOpen,
+};
+
+// static
+size_t TlsServerConnection::SessionTicketMaxOverhead(SSL* ssl) {
+ return ConnectionFromSsl(ssl)->delegate_->SessionTicketMaxOverhead();
+}
+
+// static
+int TlsServerConnection::SessionTicketSeal(SSL* ssl,
+ uint8_t* out,
+ size_t* out_len,
+ size_t max_out_len,
+ const uint8_t* in,
+ size_t in_len) {
+ return ConnectionFromSsl(ssl)->delegate_->SessionTicketSeal(
+ out, out_len, max_out_len,
+ quiche::QuicheStringPiece(reinterpret_cast<const char*>(in), in_len));
+}
+
+// static
+enum ssl_ticket_aead_result_t TlsServerConnection::SessionTicketOpen(
+ SSL* ssl,
+ uint8_t* out,
+ size_t* out_len,
+ size_t max_out_len,
+ const uint8_t* in,
+ size_t in_len) {
+ return ConnectionFromSsl(ssl)->delegate_->SessionTicketOpen(
+ out, out_len, max_out_len,
+ quiche::QuicheStringPiece(reinterpret_cast<const char*>(in), in_len));
+}
+
} // namespace quic
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 85ce7e79a81..6da81141335 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
@@ -5,6 +5,7 @@
#ifndef QUICHE_QUIC_CORE_CRYPTO_TLS_SERVER_CONNECTION_H_
#define QUICHE_QUIC_CORE_CRYPTO_TLS_SERVER_CONNECTION_H_
+#include "net/third_party/quiche/src/quic/core/crypto/proof_source.h"
#include "net/third_party/quiche/src/quic/core/crypto/tls_connection.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
@@ -59,6 +60,50 @@ class QUIC_EXPORT_PRIVATE TlsServerConnection : public TlsConnection {
size_t* out_len,
size_t max_out) = 0;
+ // The following functions are used to implement an SSL_TICKET_AEAD_METHOD.
+ // See
+ // https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#ssl_ticket_aead_result_t
+ // for details on the BoringSSL API.
+
+ // SessionTicketMaxOverhead returns the maximum number of bytes of overhead
+ // that SessionTicketSeal may add when encrypting a session ticket.
+ virtual size_t SessionTicketMaxOverhead() = 0;
+
+ // SessionTicketSeal encrypts the session ticket in |in|, putting the
+ // resulting encrypted ticket in |out|, writing the length of the bytes
+ // written to |*out_len|, which is no larger than |max_out_len|. It returns
+ // 1 on success and 0 on error.
+ virtual int SessionTicketSeal(uint8_t* out,
+ size_t* out_len,
+ size_t max_out_len,
+ quiche::QuicheStringPiece in) = 0;
+
+ // SessionTicketOpen is called when BoringSSL has an encrypted session
+ // ticket |in| and wants the ticket decrypted. This decryption operation can
+ // happen synchronously or asynchronously.
+ //
+ // If the decrypted ticket is not available at the time of the function
+ // call, this function returns ssl_ticket_aead_retry. If this function
+ // returns ssl_ticket_aead_retry, then SSL_do_handshake will return
+ // SSL_ERROR_PENDING_TICKET. Once the pending ticket decryption has
+ // completed, SSL_do_handshake needs to be called again.
+ //
+ // When this function is called and the decrypted ticket is available
+ // (either the ticket was decrypted synchronously, or an asynchronous
+ // operation has completed and SSL_do_handshake has been called again), the
+ // decrypted ticket is put in |out|, and the length of that output is
+ // written to |*out_len|, not to exceed |max_out_len|, and
+ // ssl_ticket_aead_success is returned. If the ticket cannot be decrypted
+ // and should be ignored, this function returns
+ // ssl_ticket_aead_ignore_ticket and a full handshake will be performed
+ // instead. If a fatal error occurs, ssl_ticket_aead_error can be returned
+ // which will terminate the handshake.
+ virtual enum ssl_ticket_aead_result_t SessionTicketOpen(
+ uint8_t* out,
+ size_t* out_len,
+ size_t max_out_len,
+ quiche::QuicheStringPiece in) = 0;
+
// Provides the delegate for callbacks that are shared between client and
// server.
virtual TlsConnection::Delegate* ConnectionDelegate() = 0;
@@ -69,7 +114,7 @@ class QUIC_EXPORT_PRIVATE TlsServerConnection : public TlsConnection {
TlsServerConnection(SSL_CTX* ssl_ctx, Delegate* delegate);
// Creates and configures an SSL_CTX that is appropriate for servers to use.
- static bssl::UniquePtr<SSL_CTX> CreateSslCtx();
+ static bssl::UniquePtr<SSL_CTX> CreateSslCtx(ProofSource* proof_source);
void SetCertChain(const std::vector<CRYPTO_BUFFER*>& cert_chain);
@@ -105,6 +150,25 @@ class QUIC_EXPORT_PRIVATE TlsServerConnection : public TlsConnection {
size_t* out_len,
size_t max_out);
+ // Implementation of SSL_TICKET_AEAD_METHOD which delegates to corresponding
+ // methods in TlsServerConnection::Delegate (a.k.a. TlsServerHandshaker).
+ static const SSL_TICKET_AEAD_METHOD kSessionTicketMethod;
+
+ // The following functions make up the contents of |kSessionTicketMethod|.
+ static size_t SessionTicketMaxOverhead(SSL* ssl);
+ static int SessionTicketSeal(SSL* ssl,
+ uint8_t* out,
+ size_t* out_len,
+ size_t max_out_len,
+ const uint8_t* in,
+ size_t in_len);
+ static enum ssl_ticket_aead_result_t SessionTicketOpen(SSL* ssl,
+ uint8_t* out,
+ size_t* out_len,
+ size_t max_out_len,
+ const uint8_t* in,
+ size_t in_len);
+
Delegate* 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 4cefcddad22..3e286adc84b 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
@@ -7,9 +7,11 @@
#include <cstdint>
#include <cstring>
#include <forward_list>
+#include <memory>
#include <utility>
#include "net/third_party/quiche/src/quic/core/crypto/crypto_framer.h"
+#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h"
#include "net/third_party/quiche/src/quic/core/quic_connection_id.h"
#include "net/third_party/quiche/src/quic/core/quic_data_reader.h"
#include "net/third_party/quiche/src/quic/core/quic_data_writer.h"
@@ -47,6 +49,9 @@ enum TransportParameters::TransportParameterId : uint64_t {
kMaxDatagramFrameSize = 0x20,
+ kInitialRoundTripTime = 0x3127,
+ kGoogleConnectionOptions = 0x3128,
+ kGoogleUserAgentId = 0x3129,
kGoogleQuicParam = 18257, // Used for non-standard Google-specific params.
kGoogleQuicVersion =
18258, // Used to transmit version and supported_versions.
@@ -57,12 +62,14 @@ namespace {
// The following constants define minimum and maximum allowed values for some of
// the parameters. These come from the "Transport Parameter Definitions"
// section of draft-ietf-quic-transport.
-const uint64_t kMinMaxPacketSizeTransportParam = 1200;
-const uint64_t kMaxAckDelayExponentTransportParam = 20;
-const uint64_t kDefaultAckDelayExponentTransportParam = 3;
-const uint64_t kMaxMaxAckDelayTransportParam = 16383;
-const uint64_t kDefaultMaxAckDelayTransportParam = 25;
-const size_t kStatelessResetTokenLength = 16;
+constexpr uint64_t kMinMaxPacketSizeTransportParam = 1200;
+constexpr uint64_t kMaxAckDelayExponentTransportParam = 20;
+constexpr uint64_t kDefaultAckDelayExponentTransportParam = 3;
+constexpr uint64_t kMaxMaxAckDelayTransportParam = 16383;
+constexpr uint64_t kDefaultMaxAckDelayTransportParam = 25;
+constexpr size_t kStatelessResetTokenLength = 16;
+constexpr uint64_t kMinActiveConnectionIdLimitTransportParam = 2;
+constexpr uint64_t kDefaultActiveConnectionIdLimitTransportParam = 2;
std::string TransportParameterIdToString(
TransportParameters::TransportParameterId param_id) {
@@ -99,6 +106,12 @@ std::string TransportParameterIdToString(
return "active_connection_id_limit";
case TransportParameters::kMaxDatagramFrameSize:
return "max_datagram_frame_size";
+ case TransportParameters::kInitialRoundTripTime:
+ return "initial_round_trip_time";
+ case TransportParameters::kGoogleConnectionOptions:
+ return "google_connection_options";
+ case TransportParameters::kGoogleUserAgentId:
+ return "user_agent_id";
case TransportParameters::kGoogleQuicParam:
return "google";
case TransportParameters::kGoogleQuicVersion:
@@ -107,6 +120,35 @@ std::string TransportParameterIdToString(
return "Unknown(" + quiche::QuicheTextUtils::Uint64ToString(param_id) + ")";
}
+bool TransportParameterIdIsKnown(
+ TransportParameters::TransportParameterId param_id) {
+ switch (param_id) {
+ case TransportParameters::kOriginalConnectionId:
+ case TransportParameters::kIdleTimeout:
+ case TransportParameters::kStatelessResetToken:
+ case TransportParameters::kMaxPacketSize:
+ case TransportParameters::kInitialMaxData:
+ case TransportParameters::kInitialMaxStreamDataBidiLocal:
+ case TransportParameters::kInitialMaxStreamDataBidiRemote:
+ case TransportParameters::kInitialMaxStreamDataUni:
+ case TransportParameters::kInitialMaxStreamsBidi:
+ case TransportParameters::kInitialMaxStreamsUni:
+ case TransportParameters::kAckDelayExponent:
+ case TransportParameters::kMaxAckDelay:
+ case TransportParameters::kDisableMigration:
+ case TransportParameters::kPreferredAddress:
+ case TransportParameters::kActiveConnectionIdLimit:
+ case TransportParameters::kMaxDatagramFrameSize:
+ case TransportParameters::kInitialRoundTripTime:
+ case TransportParameters::kGoogleConnectionOptions:
+ case TransportParameters::kGoogleUserAgentId:
+ case TransportParameters::kGoogleQuicParam:
+ case TransportParameters::kGoogleQuicVersion:
+ return true;
+ }
+ return false;
+}
+
bool WriteTransportParameterId(
QuicDataWriter* writer,
TransportParameters::TransportParameterId param_id,
@@ -310,6 +352,19 @@ TransportParameters::PreferredAddress::PreferredAddress()
TransportParameters::PreferredAddress::~PreferredAddress() {}
+bool TransportParameters::PreferredAddress::operator==(
+ const PreferredAddress& rhs) const {
+ return ipv4_socket_address == rhs.ipv4_socket_address &&
+ ipv6_socket_address == rhs.ipv6_socket_address &&
+ connection_id == rhs.connection_id &&
+ stateless_reset_token == rhs.stateless_reset_token;
+}
+
+bool TransportParameters::PreferredAddress::operator!=(
+ const PreferredAddress& rhs) const {
+ return !(*this == rhs);
+}
+
std::ostream& operator<<(
std::ostream& os,
const TransportParameters::PreferredAddress& preferred_address) {
@@ -346,9 +401,9 @@ std::string TransportParameters::ToString() const {
rv += " supported_versions " +
QuicVersionLabelVectorToString(supported_versions);
}
- if (!original_connection_id.IsEmpty()) {
+ if (original_connection_id.has_value()) {
rv += " " + TransportParameterIdToString(kOriginalConnectionId) + " " +
- original_connection_id.ToString();
+ original_connection_id.value().ToString();
}
rv += idle_timeout_milliseconds.ToString(/*for_use_in_list=*/true);
if (!stateless_reset_token.empty()) {
@@ -375,20 +430,36 @@ std::string TransportParameters::ToString() const {
}
rv += active_connection_id_limit.ToString(/*for_use_in_list=*/true);
rv += max_datagram_frame_size.ToString(/*for_use_in_list=*/true);
+ rv += initial_round_trip_time_us.ToString(/*for_use_in_list=*/true);
+ if (google_connection_options.has_value()) {
+ rv += " " + TransportParameterIdToString(kGoogleConnectionOptions) + " ";
+ bool first = true;
+ for (const QuicTag& connection_option : google_connection_options.value()) {
+ if (first) {
+ first = false;
+ } else {
+ rv += ",";
+ }
+ rv += QuicTagToString(connection_option);
+ }
+ }
+ if (user_agent_id.has_value()) {
+ rv += " " + TransportParameterIdToString(kGoogleUserAgentId) + " \"" +
+ user_agent_id.value() + "\"";
+ }
if (google_quic_params) {
rv += " " + TransportParameterIdToString(kGoogleQuicParam);
}
- rv += "]";
for (const auto& kv : custom_parameters) {
rv += " 0x" + quiche::QuicheTextUtils::Hex(static_cast<uint32_t>(kv.first));
rv += "=" + quiche::QuicheTextUtils::HexEncode(kv.second);
}
+ rv += "]";
return rv;
}
TransportParameters::TransportParameters()
: version(0),
- original_connection_id(EmptyQuicConnectionId()),
idle_timeout_milliseconds(kIdleTimeout),
max_packet_size(kMaxPacketSize,
kDefaultMaxPacketSizeTransportParam,
@@ -409,13 +480,109 @@ TransportParameters::TransportParameters()
0,
kMaxMaxAckDelayTransportParam),
disable_migration(false),
- active_connection_id_limit(kActiveConnectionIdLimit),
- max_datagram_frame_size(kMaxDatagramFrameSize)
+ active_connection_id_limit(kActiveConnectionIdLimit,
+ kDefaultActiveConnectionIdLimitTransportParam,
+ kMinActiveConnectionIdLimitTransportParam,
+ kVarInt62MaxValue),
+ max_datagram_frame_size(kMaxDatagramFrameSize),
+ initial_round_trip_time_us(kInitialRoundTripTime)
// Important note: any new transport parameters must be added
// to TransportParameters::AreValid, SerializeTransportParameters and
-// ParseTransportParameters.
+// ParseTransportParameters, TransportParameters's custom copy constructor, the
+// operator==, and TransportParametersTest.Comparator.
{}
+TransportParameters::TransportParameters(const TransportParameters& other)
+ : perspective(other.perspective),
+ version(other.version),
+ supported_versions(other.supported_versions),
+ original_connection_id(other.original_connection_id),
+ idle_timeout_milliseconds(other.idle_timeout_milliseconds),
+ stateless_reset_token(other.stateless_reset_token),
+ max_packet_size(other.max_packet_size),
+ initial_max_data(other.initial_max_data),
+ initial_max_stream_data_bidi_local(
+ other.initial_max_stream_data_bidi_local),
+ initial_max_stream_data_bidi_remote(
+ other.initial_max_stream_data_bidi_remote),
+ initial_max_stream_data_uni(other.initial_max_stream_data_uni),
+ initial_max_streams_bidi(other.initial_max_streams_bidi),
+ initial_max_streams_uni(other.initial_max_streams_uni),
+ ack_delay_exponent(other.ack_delay_exponent),
+ max_ack_delay(other.max_ack_delay),
+ disable_migration(other.disable_migration),
+ active_connection_id_limit(other.active_connection_id_limit),
+ max_datagram_frame_size(other.max_datagram_frame_size),
+ initial_round_trip_time_us(other.initial_round_trip_time_us),
+ google_connection_options(other.google_connection_options),
+ user_agent_id(other.user_agent_id),
+ custom_parameters(other.custom_parameters) {
+ if (other.preferred_address) {
+ preferred_address = std::make_unique<TransportParameters::PreferredAddress>(
+ *other.preferred_address);
+ }
+ if (other.google_quic_params) {
+ google_quic_params =
+ std::make_unique<CryptoHandshakeMessage>(*other.google_quic_params);
+ }
+}
+
+bool TransportParameters::operator==(const TransportParameters& rhs) const {
+ if (!(perspective == rhs.perspective && version == rhs.version &&
+ supported_versions == rhs.supported_versions &&
+ original_connection_id == rhs.original_connection_id &&
+ idle_timeout_milliseconds.value() ==
+ rhs.idle_timeout_milliseconds.value() &&
+ stateless_reset_token == rhs.stateless_reset_token &&
+ max_packet_size.value() == rhs.max_packet_size.value() &&
+ initial_max_data.value() == rhs.initial_max_data.value() &&
+ initial_max_stream_data_bidi_local.value() ==
+ rhs.initial_max_stream_data_bidi_local.value() &&
+ initial_max_stream_data_bidi_remote.value() ==
+ rhs.initial_max_stream_data_bidi_remote.value() &&
+ initial_max_stream_data_uni.value() ==
+ rhs.initial_max_stream_data_uni.value() &&
+ initial_max_streams_bidi.value() ==
+ rhs.initial_max_streams_bidi.value() &&
+ initial_max_streams_uni.value() ==
+ rhs.initial_max_streams_uni.value() &&
+ ack_delay_exponent.value() == rhs.ack_delay_exponent.value() &&
+ max_ack_delay.value() == rhs.max_ack_delay.value() &&
+ disable_migration == rhs.disable_migration &&
+ active_connection_id_limit.value() ==
+ rhs.active_connection_id_limit.value() &&
+ max_datagram_frame_size.value() ==
+ rhs.max_datagram_frame_size.value() &&
+ initial_round_trip_time_us.value() ==
+ rhs.initial_round_trip_time_us.value() &&
+ google_connection_options == rhs.google_connection_options &&
+ user_agent_id == rhs.user_agent_id &&
+ custom_parameters == rhs.custom_parameters)) {
+ return false;
+ }
+
+ if ((!preferred_address && rhs.preferred_address) ||
+ (preferred_address && !rhs.preferred_address) ||
+ (!google_quic_params && rhs.google_quic_params) ||
+ (google_quic_params && !rhs.google_quic_params)) {
+ return false;
+ }
+ bool address = true;
+ if (preferred_address && rhs.preferred_address) {
+ address = (*preferred_address == *rhs.preferred_address);
+ }
+
+ bool google_quic = true;
+ if (google_quic_params && rhs.google_quic_params) {
+ google_quic = (*google_quic_params == *rhs.google_quic_params);
+ }
+ return address && google_quic;
+}
+
+bool TransportParameters::operator!=(const TransportParameters& rhs) const {
+ return !(*this == rhs);
+}
+
bool TransportParameters::AreValid(std::string* error_details) const {
DCHECK(perspective == Perspective::IS_CLIENT ||
perspective == Perspective::IS_SERVER);
@@ -424,7 +591,7 @@ bool TransportParameters::AreValid(std::string* error_details) const {
return false;
}
if (perspective == Perspective::IS_CLIENT &&
- !original_connection_id.IsEmpty()) {
+ original_connection_id.has_value()) {
*error_details = "Client cannot send original connection ID";
return false;
}
@@ -452,6 +619,23 @@ bool TransportParameters::AreValid(std::string* error_details) const {
*error_details = "Internal preferred address family failure";
return false;
}
+ for (const auto& kv : custom_parameters) {
+ if (TransportParameterIdIsKnown(kv.first)) {
+ *error_details = quiche::QuicheStrCat(
+ "Using custom_parameters with known ID ",
+ TransportParameterIdToString(kv.first), " is not allowed");
+ return false;
+ }
+ }
+ if (perspective == Perspective::IS_SERVER &&
+ initial_round_trip_time_us.value() > 0) {
+ *error_details = "Server cannot send initial round trip time";
+ return false;
+ }
+ if (perspective == Perspective::IS_SERVER && user_agent_id.has_value()) {
+ *error_details = "Server cannot send user agent ID";
+ return false;
+ }
const bool ok =
idle_timeout_milliseconds.IsValid() && max_packet_size.IsValid() &&
initial_max_data.IsValid() &&
@@ -460,7 +644,8 @@ bool TransportParameters::AreValid(std::string* error_details) const {
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();
+ active_connection_id_limit.IsValid() &&
+ max_datagram_frame_size.IsValid() && initial_round_trip_time_us.IsValid();
if (!ok) {
*error_details = "Invalid transport parameters " + this->ToString();
}
@@ -504,17 +689,18 @@ bool SerializeTransportParameters(ParsedQuicVersion version,
}
// original_connection_id
- if (!in.original_connection_id.IsEmpty()) {
+ if (in.original_connection_id.has_value()) {
DCHECK_EQ(Perspective::IS_SERVER, in.perspective);
+ QuicConnectionId original_connection_id = in.original_connection_id.value();
if (!WriteTransportParameterId(
&writer, TransportParameters::kOriginalConnectionId, version) ||
!WriteTransportParameterStringPiece(
&writer,
- quiche::QuicheStringPiece(in.original_connection_id.data(),
- in.original_connection_id.length()),
+ quiche::QuicheStringPiece(original_connection_id.data(),
+ original_connection_id.length()),
version)) {
QUIC_BUG << "Failed to write original_connection_id "
- << in.original_connection_id << " for " << in;
+ << in.original_connection_id.value() << " for " << in;
return false;
}
}
@@ -552,7 +738,8 @@ bool SerializeTransportParameters(ParsedQuicVersion version,
!in.ack_delay_exponent.Write(&writer, version) ||
!in.max_ack_delay.Write(&writer, version) ||
!in.active_connection_id_limit.Write(&writer, version) ||
- !in.max_datagram_frame_size.Write(&writer, version)) {
+ !in.max_datagram_frame_size.Write(&writer, version) ||
+ !in.initial_round_trip_time_us.Write(&writer, version)) {
QUIC_BUG << "Failed to write integers for " << in;
return false;
}
@@ -604,6 +791,42 @@ bool SerializeTransportParameters(ParsedQuicVersion version,
}
}
+ // Google-specific connection options.
+ if (in.google_connection_options.has_value()) {
+ static_assert(sizeof(in.google_connection_options.value().front()) == 4,
+ "bad size");
+ uint64_t connection_options_length =
+ in.google_connection_options.value().size() * 4;
+ if (!WriteTransportParameterId(
+ &writer, TransportParameters::kGoogleConnectionOptions, version) ||
+ !WriteTransportParameterLength(&writer, connection_options_length,
+ version)) {
+ QUIC_BUG << "Failed to write google_connection_options of length "
+ << connection_options_length << " for " << in;
+ return false;
+ }
+ for (const QuicTag& connection_option :
+ in.google_connection_options.value()) {
+ if (!writer.WriteTag(connection_option)) {
+ QUIC_BUG << "Failed to write google_connection_option "
+ << QuicTagToString(connection_option) << " for " << in;
+ return false;
+ }
+ }
+ }
+
+ // Google-specific user agent identifier.
+ if (in.user_agent_id.has_value()) {
+ if (!WriteTransportParameterId(
+ &writer, TransportParameters::kGoogleUserAgentId, version) ||
+ !WriteTransportParameterStringPiece(&writer, in.user_agent_id.value(),
+ version)) {
+ QUIC_BUG << "Failed to write Google user agent ID \""
+ << in.user_agent_id.value() << "\" for " << in;
+ return false;
+ }
+ }
+
// Google-specific non-standard parameter.
if (in.google_quic_params) {
const QuicData& serialized_google_quic_params =
@@ -648,12 +871,56 @@ bool SerializeTransportParameters(ParsedQuicVersion version,
}
for (const auto& kv : in.custom_parameters) {
- QUIC_BUG_IF(static_cast<uint64_t>(kv.first) < 0xff00)
- << "custom_parameters should not be used "
- "for non-private use parameters";
- if (!WriteTransportParameterId(&writer, kv.first, version) ||
+ const TransportParameters::TransportParameterId param_id = kv.first;
+ if (param_id % 31 == 27) {
+ // See the "Reserved Transport Parameters" section of
+ // draft-ietf-quic-transport.
+ QUIC_BUG << "Serializing custom_parameters with GREASE ID " << param_id
+ << " is not allowed";
+ return false;
+ }
+ if (!WriteTransportParameterId(&writer, param_id, version) ||
!WriteTransportParameterStringPiece(&writer, kv.second, version)) {
- QUIC_BUG << "Failed to write custom parameter " << kv.first;
+ QUIC_BUG << "Failed to write custom parameter " << param_id;
+ return false;
+ }
+ }
+
+ {
+ // Add a random GREASE transport parameter, as defined in the
+ // "Reserved Transport Parameters" section of draft-ietf-quic-transport.
+ // https://quicwg.org/base-drafts/draft-ietf-quic-transport.html
+ // This forces receivers to support unexpected input.
+ QuicRandom* random = QuicRandom::GetInstance();
+ uint64_t grease_id64 = random->RandUint64();
+ if (version.HasVarIntTransportParams()) {
+ // With these versions, identifiers are 62 bits long so we need to ensure
+ // that the output of the computation below fits in 62 bits.
+ grease_id64 %= ((1ULL << 62) - 31);
+ } else {
+ // Same with 16 bits.
+ grease_id64 %= ((1ULL << 16) - 31);
+ }
+ // Make sure grease_id % 31 == 27. Note that this is not uniformely
+ // distributed but is acceptable since no security depends on this
+ // randomness.
+ grease_id64 = (grease_id64 / 31) * 31 + 27;
+ DCHECK(version.HasVarIntTransportParams() ||
+ grease_id64 <= std::numeric_limits<uint16_t>::max())
+ << grease_id64 << " invalid for " << version;
+ TransportParameters::TransportParameterId grease_id =
+ static_cast<TransportParameters::TransportParameterId>(grease_id64);
+ const size_t kMaxGreaseLength = 16;
+ const size_t grease_length = random->RandUint64() % kMaxGreaseLength;
+ DCHECK_GE(kMaxGreaseLength, grease_length);
+ char grease_contents[kMaxGreaseLength];
+ random->RandBytes(grease_contents, grease_length);
+ if (!WriteTransportParameterId(&writer, grease_id, version) ||
+ !WriteTransportParameterStringPiece(
+ &writer, quiche::QuicheStringPiece(grease_contents, grease_length),
+ version)) {
+ QUIC_BUG << "Failed to write GREASE parameter "
+ << TransportParameterIdToString(grease_id);
return false;
}
}
@@ -679,6 +946,7 @@ bool SerializeTransportParameters(ParsedQuicVersion version,
QUIC_DLOG(INFO) << "Serialized " << in << " as " << writer.length()
<< " bytes";
+
return true;
}
@@ -722,7 +990,7 @@ bool ParseTransportParameters(ParsedQuicVersion version,
bool parse_success = true;
switch (param_id) {
case TransportParameters::kOriginalConnectionId: {
- if (!out->original_connection_id.IsEmpty()) {
+ if (out->original_connection_id.has_value()) {
*error_details = "Received a second original connection ID";
return false;
}
@@ -734,11 +1002,13 @@ bool ParseTransportParameters(ParsedQuicVersion version,
connection_id_length);
return false;
}
- if (!value_reader.ReadConnectionId(&out->original_connection_id,
+ QuicConnectionId original_connection_id;
+ if (!value_reader.ReadConnectionId(&original_connection_id,
connection_id_length)) {
*error_details = "Failed to read original connection ID";
return false;
}
+ out->original_connection_id = original_connection_id;
} break;
case TransportParameters::kIdleTimeout:
parse_success =
@@ -848,6 +1118,32 @@ bool ParseTransportParameters(ParsedQuicVersion version,
parse_success =
out->max_datagram_frame_size.Read(&value_reader, error_details);
break;
+ case TransportParameters::kInitialRoundTripTime:
+ parse_success =
+ out->initial_round_trip_time_us.Read(&value_reader, error_details);
+ break;
+ case TransportParameters::kGoogleConnectionOptions: {
+ if (out->google_connection_options.has_value()) {
+ *error_details = "Received a second Google connection options";
+ return false;
+ }
+ out->google_connection_options = QuicTagVector{};
+ while (!value_reader.IsDoneReading()) {
+ QuicTag connection_option;
+ if (!value_reader.ReadTag(&connection_option)) {
+ *error_details = "Failed to read a Google connection option";
+ return false;
+ }
+ out->google_connection_options.value().push_back(connection_option);
+ }
+ } break;
+ case TransportParameters::kGoogleUserAgentId:
+ if (out->user_agent_id.has_value()) {
+ *error_details = "Received a second user agent ID";
+ return false;
+ }
+ out->user_agent_id = std::string(value_reader.ReadRemainingPayload());
+ break;
case TransportParameters::kGoogleQuicParam: {
if (out->google_quic_params) {
*error_details = "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 831caecd1a9..9dec484a552 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
@@ -15,6 +15,7 @@
#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/common/platform/api/quiche_optional.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
namespace quic {
@@ -35,7 +36,6 @@ struct QUIC_EXPORT_PRIVATE TransportParameters {
public:
// Forbid constructing and copying apart from TransportParameters.
IntegerParameter() = delete;
- IntegerParameter(const IntegerParameter&) = delete;
IntegerParameter& operator=(const IntegerParameter&) = delete;
// Sets the value of this transport parameter.
void set_value(uint64_t value);
@@ -67,6 +67,8 @@ struct QUIC_EXPORT_PRIVATE TransportParameters {
uint64_t default_value,
uint64_t min_value,
uint64_t max_value);
+ IntegerParameter(const IntegerParameter& other) = default;
+ IntegerParameter(IntegerParameter&& other) = default;
// Human-readable string representation.
std::string ToString(bool for_use_in_list) const;
@@ -88,7 +90,11 @@ struct QUIC_EXPORT_PRIVATE TransportParameters {
// send to clients.
struct QUIC_EXPORT_PRIVATE PreferredAddress {
PreferredAddress();
+ PreferredAddress(const PreferredAddress& other) = default;
+ PreferredAddress(PreferredAddress&& other) = default;
~PreferredAddress();
+ bool operator==(const PreferredAddress& rhs) const;
+ bool operator!=(const PreferredAddress& rhs) const;
QuicSocketAddress ipv4_socket_address;
QuicSocketAddress ipv6_socket_address;
@@ -103,7 +109,10 @@ struct QUIC_EXPORT_PRIVATE TransportParameters {
};
TransportParameters();
+ TransportParameters(const TransportParameters& other);
~TransportParameters();
+ bool operator==(const TransportParameters& rhs) const;
+ bool operator!=(const TransportParameters& rhs) const;
// Represents the sender of the transport parameters. When |perspective| is
// Perspective::IS_CLIENT, this struct is being used in the client_hello
@@ -123,7 +132,7 @@ struct QUIC_EXPORT_PRIVATE TransportParameters {
// The value of the Destination Connection ID field from the first
// Initial packet sent by the client.
- QuicConnectionId original_connection_id;
+ quiche::QuicheOptional<QuicConnectionId> original_connection_id;
// Idle timeout expressed in milliseconds.
IntegerParameter idle_timeout_milliseconds;
@@ -172,9 +181,19 @@ struct QUIC_EXPORT_PRIVATE TransportParameters {
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.
+ // the sender accepts. See draft-ietf-quic-datagram.
IntegerParameter max_datagram_frame_size;
+ // Google-specific transport parameter that carries an estimate of the
+ // initial round-trip time in microseconds.
+ IntegerParameter initial_round_trip_time_us;
+
+ // Google-specific connection options.
+ quiche::QuicheOptional<QuicTagVector> google_connection_options;
+
+ // Google-specific user agent identifier.
+ quiche::QuicheOptional<std::string> user_agent_id;
+
// Transport parameters used by Google QUIC but not IETF QUIC. This is
// serialized into a TransportParameter struct with a TransportParameterId of
// kGoogleQuicParamId.
@@ -209,7 +228,6 @@ QUIC_EXPORT_PRIVATE bool SerializeTransportParameters(
// This method returns true if the input was successfully parsed.
// On failure, this method will write a human-readable error message to
// |error_details|.
-// TODO(nharper): Write fuzz tests for this method.
QUIC_EXPORT_PRIVATE bool ParseTransportParameters(ParsedQuicVersion version,
Perspective perspective,
const uint8_t* in,
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 bbcba74efb8..1fc1f5c5c93 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
@@ -7,6 +7,10 @@
#include <cstring>
#include <utility>
+#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h"
+#include "net/third_party/quiche/src/quic/core/quic_connection_id.h"
+#include "net/third_party/quiche/src/quic/core/quic_tag.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_expect_bug.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h"
@@ -19,9 +23,6 @@ namespace quic {
namespace test {
namespace {
-using testing::Pair;
-using testing::UnorderedElementsAre;
-
const QuicVersionLabel kFakeVersionLabel = 0x01234567;
const QuicVersionLabel kFakeVersionLabel2 = 0x89ABCDEF;
const uint64_t kFakeIdleTimeoutMilliseconds = 12012;
@@ -39,6 +40,7 @@ const uint64_t kFakeAckDelayExponent = 10;
const uint64_t kFakeMaxAckDelay = 51;
const bool kFakeDisableMigration = true;
const uint64_t kFakeActiveConnectionIdLimit = 52;
+const uint64_t kFakeInitialRoundTripTime = 53;
const uint8_t kFakePreferredStatelessResetTokenData[16] = {
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F};
@@ -101,14 +103,26 @@ CreateFakePreferredAddress() {
preferred_address);
}
-std::vector<ParsedQuicVersion> AllSupportedTlsVersions() {
- std::vector<ParsedQuicVersion> tls_versions;
- for (const ParsedQuicVersion& version : AllSupportedVersions()) {
- if (version.handshake_protocol == PROTOCOL_TLS1_3) {
- tls_versions.push_back(version);
+QuicTagVector CreateFakeGoogleConnectionOptions() {
+ return {kALPN, MakeQuicTag('E', 'F', 'G', 0x00),
+ MakeQuicTag('H', 'I', 'J', 0xff)};
+}
+
+std::string CreateFakeUserAgentId() {
+ return "FakeUAID";
+}
+
+void RemoveGreaseParameters(TransportParameters* params) {
+ std::vector<TransportParameters::TransportParameterId> grease_params;
+ for (const auto& kv : params->custom_parameters) {
+ if (kv.first % 31 == 27) {
+ grease_params.push_back(kv.first);
}
}
- return tls_versions;
+ EXPECT_EQ(grease_params.size(), 1u);
+ for (TransportParameters::TransportParameterId param_id : grease_params) {
+ params->custom_parameters.erase(param_id);
+ }
}
} // namespace
@@ -122,9 +136,129 @@ class TransportParametersTest : public QuicTestWithParam<ParsedQuicVersion> {
INSTANTIATE_TEST_SUITE_P(TransportParametersTests,
TransportParametersTest,
- ::testing::ValuesIn(AllSupportedTlsVersions()),
+ ::testing::ValuesIn(AllSupportedVersionsWithTls()),
::testing::PrintToStringParamName());
+TEST_P(TransportParametersTest, Comparator) {
+ TransportParameters orig_params;
+ TransportParameters new_params;
+ // Test comparison on primitive members.
+ orig_params.perspective = Perspective::IS_CLIENT;
+ new_params.perspective = Perspective::IS_SERVER;
+ EXPECT_NE(orig_params, new_params);
+ EXPECT_FALSE(orig_params == new_params);
+ EXPECT_TRUE(orig_params != new_params);
+ new_params.perspective = Perspective::IS_CLIENT;
+ orig_params.version = kFakeVersionLabel;
+ new_params.version = kFakeVersionLabel;
+ orig_params.disable_migration = true;
+ new_params.disable_migration = true;
+ EXPECT_EQ(orig_params, new_params);
+ EXPECT_TRUE(orig_params == new_params);
+ EXPECT_FALSE(orig_params != new_params);
+
+ // Test comparison on vectors.
+ orig_params.supported_versions.push_back(kFakeVersionLabel);
+ new_params.supported_versions.push_back(kFakeVersionLabel2);
+ EXPECT_NE(orig_params, new_params);
+ EXPECT_FALSE(orig_params == new_params);
+ EXPECT_TRUE(orig_params != new_params);
+ new_params.supported_versions.pop_back();
+ new_params.supported_versions.push_back(kFakeVersionLabel);
+ orig_params.stateless_reset_token = CreateFakeStatelessResetToken();
+ new_params.stateless_reset_token = CreateFakeStatelessResetToken();
+ EXPECT_EQ(orig_params, new_params);
+ EXPECT_TRUE(orig_params == new_params);
+ EXPECT_FALSE(orig_params != new_params);
+
+ // Test comparison on IntegerParameters.
+ orig_params.max_packet_size.set_value(kFakeMaxPacketSize);
+ new_params.max_packet_size.set_value(kFakeMaxPacketSize + 1);
+ EXPECT_NE(orig_params, new_params);
+ EXPECT_FALSE(orig_params == new_params);
+ EXPECT_TRUE(orig_params != new_params);
+ new_params.max_packet_size.set_value(kFakeMaxPacketSize);
+ EXPECT_EQ(orig_params, new_params);
+ EXPECT_TRUE(orig_params == new_params);
+ EXPECT_FALSE(orig_params != new_params);
+
+ // Test comparison on PreferredAddress
+ orig_params.preferred_address = CreateFakePreferredAddress();
+ EXPECT_NE(orig_params, new_params);
+ EXPECT_FALSE(orig_params == new_params);
+ EXPECT_TRUE(orig_params != new_params);
+ new_params.preferred_address = CreateFakePreferredAddress();
+ EXPECT_EQ(orig_params, new_params);
+ EXPECT_TRUE(orig_params == new_params);
+ EXPECT_FALSE(orig_params != new_params);
+
+ // Test comparison on CryptoHandshakeMessage.
+ orig_params.google_quic_params = std::make_unique<CryptoHandshakeMessage>();
+ const std::string kTestString = "test string";
+ orig_params.google_quic_params->SetStringPiece(42, kTestString);
+ const uint32_t kTestValue = 12;
+ orig_params.google_quic_params->SetValue(1337, kTestValue);
+ EXPECT_NE(orig_params, new_params);
+ EXPECT_FALSE(orig_params == new_params);
+ EXPECT_TRUE(orig_params != new_params);
+
+ new_params.google_quic_params = std::make_unique<CryptoHandshakeMessage>();
+ new_params.google_quic_params->SetStringPiece(42, kTestString);
+ new_params.google_quic_params->SetValue(1337, kTestValue + 1);
+ EXPECT_NE(orig_params, new_params);
+ EXPECT_FALSE(orig_params == new_params);
+ EXPECT_TRUE(orig_params != new_params);
+ new_params.google_quic_params->SetValue(1337, kTestValue);
+ EXPECT_EQ(orig_params, new_params);
+ EXPECT_TRUE(orig_params == new_params);
+ EXPECT_FALSE(orig_params != new_params);
+
+ // Test comparison on CustomMap
+ orig_params.custom_parameters[kCustomParameter1] = kCustomParameter1Value;
+ orig_params.custom_parameters[kCustomParameter2] = kCustomParameter2Value;
+
+ new_params.custom_parameters[kCustomParameter2] = kCustomParameter2Value;
+ new_params.custom_parameters[kCustomParameter1] = kCustomParameter1Value;
+ EXPECT_EQ(orig_params, new_params);
+ EXPECT_TRUE(orig_params == new_params);
+ EXPECT_FALSE(orig_params != new_params);
+}
+
+TEST_P(TransportParametersTest, CopyConstructor) {
+ TransportParameters orig_params;
+ orig_params.perspective = Perspective::IS_CLIENT;
+ orig_params.version = kFakeVersionLabel;
+ orig_params.supported_versions.push_back(kFakeVersionLabel);
+ orig_params.supported_versions.push_back(kFakeVersionLabel2);
+ orig_params.original_connection_id = CreateFakeOriginalConnectionId();
+ orig_params.idle_timeout_milliseconds.set_value(kFakeIdleTimeoutMilliseconds);
+ 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(
+ kFakeInitialMaxStreamDataBidiLocal);
+ orig_params.initial_max_stream_data_bidi_remote.set_value(
+ kFakeInitialMaxStreamDataBidiRemote);
+ orig_params.initial_max_stream_data_uni.set_value(
+ kFakeInitialMaxStreamDataUni);
+ orig_params.initial_max_streams_bidi.set_value(kFakeInitialMaxStreamsBidi);
+ orig_params.initial_max_streams_uni.set_value(kFakeInitialMaxStreamsUni);
+ orig_params.ack_delay_exponent.set_value(kFakeAckDelayExponent);
+ orig_params.max_ack_delay.set_value(kFakeMaxAckDelay);
+ orig_params.disable_migration = kFakeDisableMigration;
+ orig_params.preferred_address = CreateFakePreferredAddress();
+ orig_params.active_connection_id_limit.set_value(
+ kFakeActiveConnectionIdLimit);
+ orig_params.initial_round_trip_time_us.set_value(kFakeInitialRoundTripTime);
+ orig_params.google_connection_options = CreateFakeGoogleConnectionOptions();
+ orig_params.user_agent_id = CreateFakeUserAgentId();
+ orig_params.custom_parameters[kCustomParameter1] = kCustomParameter1Value;
+ orig_params.custom_parameters[kCustomParameter2] = kCustomParameter2Value;
+
+ TransportParameters new_params(orig_params);
+ EXPECT_EQ(new_params, orig_params);
+}
+
TEST_P(TransportParametersTest, RoundTripClient) {
TransportParameters orig_params;
orig_params.perspective = Perspective::IS_CLIENT;
@@ -145,6 +279,9 @@ TEST_P(TransportParametersTest, RoundTripClient) {
orig_params.disable_migration = kFakeDisableMigration;
orig_params.active_connection_id_limit.set_value(
kFakeActiveConnectionIdLimit);
+ orig_params.initial_round_trip_time_us.set_value(kFakeInitialRoundTripTime);
+ orig_params.google_connection_options = CreateFakeGoogleConnectionOptions();
+ orig_params.user_agent_id = CreateFakeUserAgentId();
orig_params.custom_parameters[kCustomParameter1] = kCustomParameter1Value;
orig_params.custom_parameters[kCustomParameter2] = kCustomParameter2Value;
@@ -158,34 +295,8 @@ TEST_P(TransportParametersTest, RoundTripClient) {
&new_params, &error_details))
<< error_details;
EXPECT_TRUE(error_details.empty());
- EXPECT_EQ(Perspective::IS_CLIENT, new_params.perspective);
- EXPECT_EQ(kFakeVersionLabel, new_params.version);
- EXPECT_TRUE(new_params.supported_versions.empty());
- EXPECT_EQ(EmptyQuicConnectionId(), new_params.original_connection_id);
- EXPECT_EQ(kFakeIdleTimeoutMilliseconds,
- new_params.idle_timeout_milliseconds.value());
- EXPECT_TRUE(new_params.stateless_reset_token.empty());
- EXPECT_EQ(kFakeMaxPacketSize, new_params.max_packet_size.value());
- EXPECT_EQ(kFakeInitialMaxData, new_params.initial_max_data.value());
- EXPECT_EQ(kFakeInitialMaxStreamDataBidiLocal,
- new_params.initial_max_stream_data_bidi_local.value());
- EXPECT_EQ(kFakeInitialMaxStreamDataBidiRemote,
- new_params.initial_max_stream_data_bidi_remote.value());
- EXPECT_EQ(kFakeInitialMaxStreamDataUni,
- new_params.initial_max_stream_data_uni.value());
- EXPECT_EQ(kFakeInitialMaxStreamsBidi,
- new_params.initial_max_streams_bidi.value());
- EXPECT_EQ(kFakeInitialMaxStreamsUni,
- new_params.initial_max_streams_uni.value());
- EXPECT_EQ(kFakeAckDelayExponent, new_params.ack_delay_exponent.value());
- EXPECT_EQ(kFakeMaxAckDelay, new_params.max_ack_delay.value());
- EXPECT_EQ(kFakeDisableMigration, new_params.disable_migration);
- EXPECT_EQ(kFakeActiveConnectionIdLimit,
- new_params.active_connection_id_limit.value());
- EXPECT_THAT(
- new_params.custom_parameters,
- UnorderedElementsAre(Pair(kCustomParameter1, kCustomParameter1Value),
- Pair(kCustomParameter2, kCustomParameter2Value)));
+ RemoveGreaseParameters(&new_params);
+ EXPECT_EQ(new_params, orig_params);
}
TEST_P(TransportParametersTest, RoundTripServer) {
@@ -213,6 +324,7 @@ TEST_P(TransportParametersTest, RoundTripServer) {
orig_params.preferred_address = CreateFakePreferredAddress();
orig_params.active_connection_id_limit.set_value(
kFakeActiveConnectionIdLimit);
+ orig_params.google_connection_options = CreateFakeGoogleConnectionOptions();
std::vector<uint8_t> serialized;
ASSERT_TRUE(SerializeTransportParameters(version_, orig_params, &serialized));
@@ -224,43 +336,8 @@ TEST_P(TransportParametersTest, RoundTripServer) {
&new_params, &error_details))
<< error_details;
EXPECT_TRUE(error_details.empty());
- EXPECT_EQ(Perspective::IS_SERVER, new_params.perspective);
- EXPECT_EQ(kFakeVersionLabel, new_params.version);
- 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(CreateFakeOriginalConnectionId(),
- new_params.original_connection_id);
- EXPECT_EQ(kFakeIdleTimeoutMilliseconds,
- new_params.idle_timeout_milliseconds.value());
- 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,
- new_params.initial_max_stream_data_bidi_local.value());
- EXPECT_EQ(kFakeInitialMaxStreamDataBidiRemote,
- new_params.initial_max_stream_data_bidi_remote.value());
- EXPECT_EQ(kFakeInitialMaxStreamDataUni,
- new_params.initial_max_stream_data_uni.value());
- EXPECT_EQ(kFakeInitialMaxStreamsBidi,
- new_params.initial_max_streams_bidi.value());
- EXPECT_EQ(kFakeInitialMaxStreamsUni,
- new_params.initial_max_streams_uni.value());
- EXPECT_EQ(kFakeAckDelayExponent, new_params.ack_delay_exponent.value());
- EXPECT_EQ(kFakeMaxAckDelay, new_params.max_ack_delay.value());
- EXPECT_EQ(kFakeDisableMigration, new_params.disable_migration);
- ASSERT_NE(nullptr, new_params.preferred_address.get());
- EXPECT_EQ(CreateFakeV4SocketAddress(),
- new_params.preferred_address->ipv4_socket_address);
- EXPECT_EQ(CreateFakeV6SocketAddress(),
- new_params.preferred_address->ipv6_socket_address);
- EXPECT_EQ(CreateFakePreferredConnectionId(),
- new_params.preferred_address->connection_id);
- EXPECT_EQ(CreateFakePreferredStatelessResetToken(),
- new_params.preferred_address->stateless_reset_token);
- EXPECT_EQ(kFakeActiveConnectionIdLimit,
- new_params.active_connection_id_limit.value());
- EXPECT_EQ(0u, new_params.custom_parameters.size());
+ RemoveGreaseParameters(&new_params);
+ EXPECT_EQ(new_params, orig_params);
}
TEST_P(TransportParametersTest, AreValid) {
@@ -330,6 +407,29 @@ TEST_P(TransportParametersTest, AreValid) {
"Invalid transport parameters [Client ack_delay_exponent 21 "
"(Invalid)]");
}
+ {
+ TransportParameters params;
+ std::string error_details;
+ params.perspective = Perspective::IS_CLIENT;
+ EXPECT_TRUE(params.AreValid(&error_details));
+ EXPECT_TRUE(error_details.empty());
+ params.active_connection_id_limit.set_value(2);
+ EXPECT_TRUE(params.AreValid(&error_details));
+ EXPECT_TRUE(error_details.empty());
+ params.active_connection_id_limit.set_value(999999);
+ EXPECT_TRUE(params.AreValid(&error_details));
+ EXPECT_TRUE(error_details.empty());
+ params.active_connection_id_limit.set_value(1);
+ EXPECT_FALSE(params.AreValid(&error_details));
+ EXPECT_EQ(error_details,
+ "Invalid transport parameters [Client active_connection_id_limit"
+ " 1 (Invalid)]");
+ params.active_connection_id_limit.set_value(0);
+ EXPECT_FALSE(params.AreValid(&error_details));
+ EXPECT_EQ(error_details,
+ "Invalid transport parameters [Client active_connection_id_limit"
+ " 0 (Invalid)]");
+ }
}
TEST_P(TransportParametersTest, NoClientParamsWithStatelessResetToken) {
@@ -352,7 +452,7 @@ TEST_P(TransportParametersTest, NoClientParamsWithStatelessResetToken) {
TEST_P(TransportParametersTest, ParseClientParams) {
// clang-format off
const uint8_t kClientParamsOld[] = {
- 0x00, 0x49, // length of the parameters array that follows
+ 0x00, 0x6a, // length of the parameters array that follows
// idle_timeout
0x00, 0x01, // parameter id
0x00, 0x02, // length
@@ -400,6 +500,20 @@ TEST_P(TransportParametersTest, ParseClientParams) {
0x00, 0x0e, // parameter id
0x00, 0x01, // length
0x34, // value
+ // initial_round_trip_time_us
+ 0x31, 0x27, // parameter id
+ 0x00, 0x01, // length
+ 0x35, // value
+ // google_connection_options
+ 0x31, 0x28, // parameter id
+ 0x00, 0x0c, // length
+ 'A', 'L', 'P', 'N', // value
+ 'E', 'F', 'G', 0x00,
+ 'H', 'I', 'J', 0xff,
+ // user_agent_id
+ 0x31, 0x29, // parameter id
+ 0x00, 0x08, // length
+ 'F', 'a', 'k', 'e', 'U', 'A', 'I', 'D', // value
// Google version extension
0x47, 0x52, // parameter id
0x00, 0x04, // length
@@ -453,6 +567,20 @@ TEST_P(TransportParametersTest, ParseClientParams) {
0x0e, // parameter id
0x01, // length
0x34, // value
+ // initial_round_trip_time_us
+ 0x71, 0x27, // parameter id
+ 0x01, // length
+ 0x35, // value
+ // google_connection_options
+ 0x71, 0x28, // parameter id
+ 0x0c, // length
+ 'A', 'L', 'P', 'N', // value
+ 'E', 'F', 'G', 0x00,
+ 'H', 'I', 'J', 0xff,
+ // user_agent_id
+ 0x71, 0x29, // parameter id
+ 0x08, // length
+ 'F', 'a', 'k', 'e', 'U', 'A', 'I', 'D', // value
// Google version extension
0x80, 0x00, 0x47, 0x52, // parameter id
0x04, // length
@@ -476,7 +604,7 @@ TEST_P(TransportParametersTest, ParseClientParams) {
EXPECT_EQ(Perspective::IS_CLIENT, new_params.perspective);
EXPECT_EQ(kFakeVersionLabel, new_params.version);
EXPECT_TRUE(new_params.supported_versions.empty());
- EXPECT_EQ(EmptyQuicConnectionId(), new_params.original_connection_id);
+ EXPECT_FALSE(new_params.original_connection_id.has_value());
EXPECT_EQ(kFakeIdleTimeoutMilliseconds,
new_params.idle_timeout_milliseconds.value());
EXPECT_TRUE(new_params.stateless_reset_token.empty());
@@ -497,6 +625,13 @@ TEST_P(TransportParametersTest, ParseClientParams) {
EXPECT_EQ(kFakeDisableMigration, new_params.disable_migration);
EXPECT_EQ(kFakeActiveConnectionIdLimit,
new_params.active_connection_id_limit.value());
+ EXPECT_EQ(kFakeInitialRoundTripTime,
+ new_params.initial_round_trip_time_us.value());
+ ASSERT_TRUE(new_params.google_connection_options.has_value());
+ EXPECT_EQ(CreateFakeGoogleConnectionOptions(),
+ new_params.google_connection_options.value());
+ ASSERT_TRUE(new_params.user_agent_id.has_value());
+ EXPECT_EQ(CreateFakeUserAgentId(), new_params.user_agent_id.value());
}
TEST_P(TransportParametersTest,
@@ -664,7 +799,7 @@ TEST_P(TransportParametersTest, ParseClientParametersRepeated) {
TEST_P(TransportParametersTest, ParseServerParams) {
// clang-format off
const uint8_t kServerParamsOld[] = {
- 0x00, 0xa7, // length of parameters array that follows
+ 0x00, 0xb7, // length of parameters array that follows
// original_connection_id
0x00, 0x00, // parameter id
0x00, 0x08, // length
@@ -733,6 +868,12 @@ TEST_P(TransportParametersTest, ParseServerParams) {
0x00, 0x0e, // parameter id
0x00, 0x01, // length
0x34, // value
+ // google_connection_options
+ 0x31, 0x28, // parameter id
+ 0x00, 0x0c, // length
+ 'A', 'L', 'P', 'N', // value
+ 'E', 'F', 'G', 0x00,
+ 'H', 'I', 'J', 0xff,
// Google version extension
0x47, 0x52, // parameter id
0x00, 0x0d, // length
@@ -810,6 +951,12 @@ TEST_P(TransportParametersTest, ParseServerParams) {
0x0e, // parameter id
0x01, // length
0x34, // value
+ // google_connection_options
+ 0x71, 0x28, // parameter id
+ 0x0c, // length
+ 'A', 'L', 'P', 'N', // value
+ 'E', 'F', 'G', 0x00,
+ 'H', 'I', 'J', 0xff,
// Google version extension
0x80, 0x00, 0x47, 0x52, // parameter id
0x0d, // length
@@ -838,8 +985,9 @@ TEST_P(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]);
+ ASSERT_TRUE(new_params.original_connection_id.has_value());
EXPECT_EQ(CreateFakeOriginalConnectionId(),
- new_params.original_connection_id);
+ new_params.original_connection_id.value());
EXPECT_EQ(kFakeIdleTimeoutMilliseconds,
new_params.idle_timeout_milliseconds.value());
EXPECT_EQ(CreateFakeStatelessResetToken(), new_params.stateless_reset_token);
@@ -869,6 +1017,10 @@ TEST_P(TransportParametersTest, ParseServerParams) {
new_params.preferred_address->stateless_reset_token);
EXPECT_EQ(kFakeActiveConnectionIdLimit,
new_params.active_connection_id_limit.value());
+ ASSERT_TRUE(new_params.google_connection_options.has_value());
+ EXPECT_EQ(CreateFakeGoogleConnectionOptions(),
+ new_params.google_connection_options.value());
+ EXPECT_FALSE(new_params.user_agent_id.has_value());
}
TEST_P(TransportParametersTest, ParseServerParametersRepeated) {
@@ -928,6 +1080,59 @@ TEST_P(TransportParametersTest, ParseServerParametersRepeated) {
EXPECT_EQ(error_details, "Received a second idle_timeout");
}
+TEST_P(TransportParametersTest,
+ ParseServerParametersEmptyOriginalConnectionId) {
+ // clang-format off
+ const uint8_t kServerParamsEmptyOriginalConnectionIdOld[] = {
+ 0x00, 0x1e, // length of parameters array that follows
+ // original_connection_id
+ 0x00, 0x00, // parameter id
+ 0x00, 0x00, // length
+ // idle_timeout
+ 0x00, 0x01, // parameter id
+ 0x00, 0x02, // length
+ 0x6e, 0xec, // value
+ // stateless_reset_token
+ 0x00, 0x02, // parameter id
+ 0x00, 0x10, // length
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+ };
+ const uint8_t kServerParamsEmptyOriginalConnectionId[] = {
+ // original_connection_id
+ 0x00, // parameter id
+ 0x00, // length
+ // idle_timeout
+ 0x01, // parameter id
+ 0x02, // length
+ 0x6e, 0xec, // value
+ // stateless_reset_token
+ 0x02, // parameter id
+ 0x10, // length
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+ };
+ // clang-format on
+ const uint8_t* server_params =
+ reinterpret_cast<const uint8_t*>(kServerParamsEmptyOriginalConnectionId);
+ size_t server_params_length =
+ QUICHE_ARRAYSIZE(kServerParamsEmptyOriginalConnectionId);
+ if (!version_.HasVarIntTransportParams()) {
+ server_params = reinterpret_cast<const uint8_t*>(
+ kServerParamsEmptyOriginalConnectionIdOld);
+ server_params_length =
+ QUICHE_ARRAYSIZE(kServerParamsEmptyOriginalConnectionIdOld);
+ }
+ TransportParameters out_params;
+ std::string error_details;
+ ASSERT_TRUE(ParseTransportParameters(version_, Perspective::IS_SERVER,
+ server_params, server_params_length,
+ &out_params, &error_details))
+ << error_details;
+ ASSERT_TRUE(out_params.original_connection_id.has_value());
+ EXPECT_EQ(out_params.original_connection_id.value(), EmptyQuicConnectionId());
+}
+
TEST_P(TransportParametersTest, CryptoHandshakeMessageRoundtrip) {
TransportParameters orig_params;
orig_params.perspective = Perspective::IS_CLIENT;
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 2946c01af8b..3fd3dea6120 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
@@ -26,12 +26,7 @@ bool IsAwaitingPacket(const QuicAckFrame& ack_frame,
!ack_frame.packets.Contains(packet_number);
}
-QuicAckFrame::QuicAckFrame()
- : ack_delay_time(QuicTime::Delta::Infinite()),
- ecn_counters_populated(false),
- ect_0_count(0),
- ect_1_count(0),
- ecn_ce_count(0) {}
+QuicAckFrame::QuicAckFrame() = default;
QuicAckFrame::QuicAckFrame(const QuicAckFrame& other) = default;
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 9003c76e3d3..69023404db3 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
@@ -108,7 +108,7 @@ struct QUIC_EXPORT_PRIVATE QuicAckFrame {
// Time elapsed since largest_observed() was received until this Ack frame was
// sent.
- QuicTime::Delta ack_delay_time;
+ QuicTime::Delta ack_delay_time = QuicTime::Delta::Infinite();
// Vector of <packet_number, time> for when packets arrived.
PacketTimeVector received_packet_times;
@@ -118,10 +118,10 @@ struct QUIC_EXPORT_PRIVATE QuicAckFrame {
// ECN counters, used only in version 99's ACK frame and valid only when
// |ecn_counters_populated| is true.
- bool ecn_counters_populated;
- QuicPacketCount ect_0_count;
- QuicPacketCount ect_1_count;
- QuicPacketCount ecn_ce_count;
+ bool ecn_counters_populated = false;
+ QuicPacketCount ect_0_count = 0;
+ QuicPacketCount ect_1_count = 0;
+ QuicPacketCount ecn_ce_count = 0;
};
// The highest acked packet number we've observed from the peer. If no packets
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_blocked_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_blocked_frame.cc
index 41ba1443ce9..1da520e03b0 100644
--- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_blocked_frame.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_blocked_frame.cc
@@ -3,13 +3,9 @@
// found in the LICENSE file.
#include "net/third_party/quiche/src/quic/core/frames/quic_blocked_frame.h"
-#include "net/third_party/quiche/src/quic/core/quic_constants.h"
namespace quic {
-QuicBlockedFrame::QuicBlockedFrame()
- : control_frame_id(kInvalidControlFrameId), stream_id(0), offset(0) {}
-
QuicBlockedFrame::QuicBlockedFrame(QuicControlFrameId control_frame_id,
QuicStreamId stream_id)
: control_frame_id(control_frame_id), stream_id(stream_id), offset(0) {}
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_blocked_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_blocked_frame.h
index 30dcdf4ca05..64f3aeed477 100644
--- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_blocked_frame.h
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_blocked_frame.h
@@ -7,6 +7,7 @@
#include <ostream>
+#include "net/third_party/quiche/src/quic/core/quic_constants.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
namespace quic {
@@ -16,7 +17,7 @@ namespace quic {
// send data. The BLOCKED frame is purely advisory and optional.
// Based on SPDY's BLOCKED frame (undocumented as of 2014-01-28).
struct QUIC_EXPORT_PRIVATE QuicBlockedFrame {
- QuicBlockedFrame();
+ QuicBlockedFrame() = default;
QuicBlockedFrame(QuicControlFrameId control_frame_id, QuicStreamId stream_id);
QuicBlockedFrame(QuicControlFrameId control_frame_id,
QuicStreamId stream_id,
@@ -28,7 +29,7 @@ struct QUIC_EXPORT_PRIVATE QuicBlockedFrame {
// A unique identifier of this control frame. 0 when this frame is received,
// and non-zero when sent.
- QuicControlFrameId control_frame_id;
+ QuicControlFrameId control_frame_id = kInvalidControlFrameId;
// 0 is a special case meaning the connection is blocked, rather than a
// stream. So stream_id 0 corresponds to a BLOCKED frame and non-0
@@ -36,10 +37,10 @@ struct QUIC_EXPORT_PRIVATE QuicBlockedFrame {
// TODO(fkastenholz): This should be converted to use
// QuicUtils::GetInvalidStreamId to get the correct invalid stream id value
// and not rely on 0.
- QuicStreamId stream_id;
+ QuicStreamId stream_id = 0;
// For Google QUIC, the offset is ignored.
- QuicStreamOffset offset;
+ QuicStreamOffset offset = 0;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_connection_close_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_connection_close_frame.cc
index 35aedf4a292..e1b9302ceb4 100644
--- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_connection_close_frame.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_connection_close_frame.cc
@@ -7,60 +7,55 @@
#include <memory>
#include "net/third_party/quiche/src/quic/core/quic_constants.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
namespace quic {
-QuicConnectionCloseFrame::QuicConnectionCloseFrame()
- // Default close type ensures that existing, pre-V99 code works as expected.
- : close_type(GOOGLE_QUIC_CONNECTION_CLOSE),
- quic_error_code(QUIC_NO_ERROR),
- extracted_error_code(QUIC_NO_ERROR),
- transport_close_frame_type(0) {}
QuicConnectionCloseFrame::QuicConnectionCloseFrame(
QuicTransportVersion transport_version,
QuicErrorCode error_code,
std::string error_phrase,
uint64_t frame_type)
- : extracted_error_code(error_code), error_details(error_phrase) {
+ : quic_error_code(error_code), error_details(error_phrase) {
if (!VersionHasIetfQuicFrames(transport_version)) {
close_type = GOOGLE_QUIC_CONNECTION_CLOSE;
- quic_error_code = error_code;
+ wire_error_code = error_code;
transport_close_frame_type = 0;
return;
}
QuicErrorCodeToIetfMapping mapping =
QuicErrorCodeToTransportErrorCode(error_code);
- if (mapping.is_transport_close_) {
+ wire_error_code = mapping.error_code;
+ if (mapping.is_transport_close) {
// Maps to a transport close
close_type = IETF_QUIC_TRANSPORT_CONNECTION_CLOSE;
- transport_error_code = mapping.transport_error_code_;
transport_close_frame_type = frame_type;
return;
}
// Maps to an application close.
close_type = IETF_QUIC_APPLICATION_CONNECTION_CLOSE;
- application_error_code = mapping.application_error_code_;
transport_close_frame_type = 0;
}
std::ostream& operator<<(
std::ostream& os,
const QuicConnectionCloseFrame& connection_close_frame) {
- os << "{ Close type: " << connection_close_frame.close_type
- << ", error_code: ";
+ os << "{ Close type: " << connection_close_frame.close_type;
switch (connection_close_frame.close_type) {
case IETF_QUIC_TRANSPORT_CONNECTION_CLOSE:
- os << connection_close_frame.transport_error_code;
+ os << ", wire_error_code: "
+ << static_cast<QuicIetfTransportErrorCodes>(
+ connection_close_frame.wire_error_code);
break;
case IETF_QUIC_APPLICATION_CONNECTION_CLOSE:
- os << connection_close_frame.application_error_code;
+ os << ", wire_error_code: " << connection_close_frame.wire_error_code;
break;
case GOOGLE_QUIC_CONNECTION_CLOSE:
- os << connection_close_frame.quic_error_code;
+ // Do not log, value same as |quic_error_code|.
break;
}
- os << ", extracted_error_code: "
- << QuicErrorCodeToString(connection_close_frame.extracted_error_code)
+ os << ", quic_error_code: "
+ << QuicErrorCodeToString(connection_close_frame.quic_error_code)
<< ", error_details: '" << connection_close_frame.error_details << "'";
if (connection_close_frame.close_type ==
IETF_QUIC_TRANSPORT_CONNECTION_CLOSE) {
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_connection_close_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_connection_close_frame.h
index 4ee41b97fd9..de40dadc860 100644
--- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_connection_close_frame.h
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_connection_close_frame.h
@@ -16,7 +16,7 @@
namespace quic {
struct QUIC_EXPORT_PRIVATE QuicConnectionCloseFrame {
- QuicConnectionCloseFrame();
+ QuicConnectionCloseFrame() = default;
// Builds a connection close frame based on the transport version
// and the mapping of error_code. THIS IS THE PREFERRED C'TOR
@@ -31,33 +31,25 @@ struct QUIC_EXPORT_PRIVATE QuicConnectionCloseFrame {
std::ostream& os,
const QuicConnectionCloseFrame& c);
- // Indicates whether the received CONNECTION_CLOSE frame is a Google QUIC
- // CONNECTION_CLOSE, IETF QUIC CONNECTION_CLOSE.
- QuicConnectionCloseType close_type;
+ // Indicates whether the the frame is a Google QUIC CONNECTION_CLOSE frame,
+ // an IETF QUIC CONNECTION_CLOSE frame with transport error code,
+ // or an IETF QUIC CONNECTION_CLOSE frame with application error code.
+ QuicConnectionCloseType close_type = GOOGLE_QUIC_CONNECTION_CLOSE;
- // This is the error field in the frame.
- // The CONNECTION_CLOSE frame reports an error code:
- // - The transport error code as reported in a CONNECTION_CLOSE/Transport
- // frame (serialized as a VarInt),
- // - An opaque 64-bit code as reported in CONNECTION_CLOSE/Application frames
- // (serialized as a VarInt),,
- // - A 16 bit QuicErrorCode, which is used in Google QUIC.
- union {
- QuicIetfTransportErrorCodes transport_error_code;
- uint64_t application_error_code;
- QuicErrorCode quic_error_code;
- };
+ // The error code on the wire. For Google QUIC frames, this has the same
+ // value as |quic_error_code|.
+ uint64_t wire_error_code = QUIC_NO_ERROR;
- // For IETF QUIC frames, this is the error code is extracted from, or added
- // to, the error details text. For received Google QUIC frames, the Google
- // QUIC error code from the frame's error code field is copied here (as well
- // as in quic_error_code, above).
- QuicErrorCode extracted_error_code;
+ // The underlying error. For Google QUIC frames, this has the same value as
+ // |wire_error_code|. For sent IETF QUIC frames, this is the error that
+ // triggered the closure of the connection. For received IETF QUIC frames,
+ // this is parsed from the Reason Phrase field of the CONNECTION_CLOSE frame,
+ // or QUIC_IETF_GQUIC_ERROR_MISSING.
+ QuicErrorCode quic_error_code = QUIC_NO_ERROR;
- // String with additional error details. "QuicErrorCode: 123" will be appended
- // to the error details when sending IETF QUIC Connection Close and
- // Application Close frames and parsed into extracted_error_code upon receipt,
- // when present.
+ // String with additional error details. |quic_error_code| and a colon will be
+ // prepended to the error details when sending IETF QUIC frames, and parsed
+ // into |quic_error_code| upon receipt, when present.
std::string error_details;
// The frame type present in the IETF transport connection close frame.
@@ -65,7 +57,7 @@ struct QUIC_EXPORT_PRIVATE QuicConnectionCloseFrame {
// Contains the type of frame that triggered the connection close. Made a
// uint64, as opposed to the QuicIetfFrameType, to support possible
// extensions as well as reporting invalid frame types received from the peer.
- uint64_t transport_close_frame_type;
+ uint64_t transport_close_frame_type = 0;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_crypto_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_crypto_frame.cc
index d750da76939..81b3e18a6b2 100644
--- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_crypto_frame.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_crypto_frame.cc
@@ -9,9 +9,6 @@
namespace quic {
-QuicCryptoFrame::QuicCryptoFrame()
- : QuicCryptoFrame(ENCRYPTION_INITIAL, 0, nullptr, 0) {}
-
QuicCryptoFrame::QuicCryptoFrame(EncryptionLevel level,
QuicStreamOffset offset,
QuicPacketLength data_length)
@@ -35,7 +32,7 @@ QuicCryptoFrame::~QuicCryptoFrame() {}
std::ostream& operator<<(std::ostream& os,
const QuicCryptoFrame& stream_frame) {
- os << "{ level: " << static_cast<int>(stream_frame.level)
+ os << "{ level: " << EncryptionLevelToString(stream_frame.level)
<< ", offset: " << stream_frame.offset
<< ", length: " << stream_frame.data_length << " }\n";
return os;
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_crypto_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_crypto_frame.h
index 28434cb6362..2bb7a08d68a 100644
--- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_crypto_frame.h
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_crypto_frame.h
@@ -16,7 +16,7 @@
namespace quic {
struct QUIC_EXPORT_PRIVATE QuicCryptoFrame {
- QuicCryptoFrame();
+ QuicCryptoFrame() = default;
QuicCryptoFrame(EncryptionLevel level,
QuicStreamOffset offset,
QuicPacketLength data_length);
@@ -31,12 +31,12 @@ struct QUIC_EXPORT_PRIVATE QuicCryptoFrame {
// When writing a crypto frame to a packet, the packet must be encrypted at
// |level|. When a crypto frame is read, the encryption level of the packet it
// was received in is put in |level|.
- EncryptionLevel level;
- QuicPacketLength data_length;
+ EncryptionLevel level = ENCRYPTION_INITIAL;
+ QuicPacketLength data_length = 0;
// When reading, |data_buffer| points to the data that was received in the
// frame. |data_buffer| is not used when writing.
- const char* data_buffer;
- QuicStreamOffset offset; // Location of this data in the stream.
+ const char* data_buffer = nullptr;
+ QuicStreamOffset offset = 0; // Location of this data in the stream.
QuicCryptoFrame(EncryptionLevel level,
QuicStreamOffset offset,
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 7450adb5d2c..22322ed8ee2 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
@@ -147,11 +147,9 @@ TEST_F(QuicFramesTest, ConnectionCloseFrameToString) {
// indicating that, in fact, no extended error code was available from the
// underlying frame.
EXPECT_EQ(
- "{ Close type: GOOGLE_QUIC_CONNECTION_CLOSE, error_code: 25, "
- "extracted_error_code: QUIC_NO_ERROR, "
- "error_details: 'No recent "
- "network activity.'"
- "}\n",
+ "{ Close type: GOOGLE_QUIC_CONNECTION_CLOSE, "
+ "quic_error_code: QUIC_NETWORK_IDLE_TIMEOUT, "
+ "error_details: 'No recent network activity.'}\n",
stream.str());
QuicFrame quic_frame(&frame);
EXPECT_FALSE(IsControlFrame(quic_frame.type));
@@ -160,16 +158,16 @@ TEST_F(QuicFramesTest, ConnectionCloseFrameToString) {
TEST_F(QuicFramesTest, TransportConnectionCloseFrameToString) {
QuicConnectionCloseFrame frame;
frame.close_type = IETF_QUIC_TRANSPORT_CONNECTION_CLOSE;
- frame.transport_error_code = FINAL_SIZE_ERROR;
- frame.extracted_error_code = QUIC_NETWORK_IDLE_TIMEOUT;
+ frame.wire_error_code = FINAL_SIZE_ERROR;
+ frame.quic_error_code = QUIC_NETWORK_IDLE_TIMEOUT;
frame.error_details = "No recent network activity.";
frame.transport_close_frame_type = IETF_STREAM;
std::ostringstream stream;
stream << frame;
EXPECT_EQ(
- "{ Close type: IETF_QUIC_TRANSPORT_CONNECTION_CLOSE, error_code: "
- "FINAL_SIZE_ERROR, "
- "extracted_error_code: QUIC_NETWORK_IDLE_TIMEOUT, "
+ "{ Close type: IETF_QUIC_TRANSPORT_CONNECTION_CLOSE, "
+ "wire_error_code: FINAL_SIZE_ERROR, "
+ "quic_error_code: QUIC_NETWORK_IDLE_TIMEOUT, "
"error_details: 'No recent "
"network activity.', "
"frame_type: IETF_STREAM"
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_goaway_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_goaway_frame.cc
index 3842f92690e..4c8848d1738 100644
--- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_goaway_frame.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_goaway_frame.cc
@@ -5,15 +5,9 @@
#include <string>
#include "net/third_party/quiche/src/quic/core/frames/quic_goaway_frame.h"
-#include "net/third_party/quiche/src/quic/core/quic_constants.h"
namespace quic {
-QuicGoAwayFrame::QuicGoAwayFrame()
- : control_frame_id(kInvalidControlFrameId),
- error_code(QUIC_NO_ERROR),
- last_good_stream_id(0) {}
-
QuicGoAwayFrame::QuicGoAwayFrame(QuicControlFrameId control_frame_id,
QuicErrorCode error_code,
QuicStreamId last_good_stream_id,
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_goaway_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_goaway_frame.h
index ecceee6fc0e..b642cfa0372 100644
--- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_goaway_frame.h
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_goaway_frame.h
@@ -8,13 +8,14 @@
#include <ostream>
#include <string>
+#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"
namespace quic {
struct QUIC_EXPORT_PRIVATE QuicGoAwayFrame {
- QuicGoAwayFrame();
+ QuicGoAwayFrame() = default;
QuicGoAwayFrame(QuicControlFrameId control_frame_id,
QuicErrorCode error_code,
QuicStreamId last_good_stream_id,
@@ -25,9 +26,9 @@ struct QUIC_EXPORT_PRIVATE QuicGoAwayFrame {
// A unique identifier of this control frame. 0 when this frame is received,
// and non-zero when sent.
- QuicControlFrameId control_frame_id;
- QuicErrorCode error_code;
- QuicStreamId last_good_stream_id;
+ QuicControlFrameId control_frame_id = kInvalidControlFrameId;
+ QuicErrorCode error_code = QUIC_NO_ERROR;
+ QuicStreamId last_good_stream_id = 0;
std::string reason_phrase;
};
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_handshake_done_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_handshake_done_frame.cc
index 6f411a50188..f4a97c1d2e6 100644
--- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_handshake_done_frame.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_handshake_done_frame.cc
@@ -7,8 +7,7 @@
namespace quic {
QuicHandshakeDoneFrame::QuicHandshakeDoneFrame()
- : QuicInlinedFrame(HANDSHAKE_DONE_FRAME),
- control_frame_id(kInvalidControlFrameId) {}
+ : QuicInlinedFrame(HANDSHAKE_DONE_FRAME) {}
QuicHandshakeDoneFrame::QuicHandshakeDoneFrame(
QuicControlFrameId control_frame_id)
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_handshake_done_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_handshake_done_frame.h
index 48aa3c774a3..c16c169f6a5 100644
--- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_handshake_done_frame.h
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_handshake_done_frame.h
@@ -25,7 +25,7 @@ struct QUIC_EXPORT_PRIVATE QuicHandshakeDoneFrame
// A unique identifier of this control frame. 0 when this frame is received,
// and non-zero when sent.
- QuicControlFrameId control_frame_id;
+ QuicControlFrameId control_frame_id = kInvalidControlFrameId;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_max_streams_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_max_streams_frame.cc
index 6301e72c28f..1726080e2e1 100644
--- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_max_streams_frame.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_max_streams_frame.cc
@@ -7,10 +7,7 @@
namespace quic {
QuicMaxStreamsFrame::QuicMaxStreamsFrame()
- : QuicInlinedFrame(MAX_STREAMS_FRAME),
- control_frame_id(kInvalidControlFrameId),
- stream_count(0),
- unidirectional(false) {}
+ : QuicInlinedFrame(MAX_STREAMS_FRAME) {}
QuicMaxStreamsFrame::QuicMaxStreamsFrame(QuicControlFrameId control_frame_id,
QuicStreamCount stream_count,
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_max_streams_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_max_streams_frame.h
index f8c78f9afd4..e1595c046b0 100644
--- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_max_streams_frame.h
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_max_streams_frame.h
@@ -30,12 +30,12 @@ struct QUIC_EXPORT_PRIVATE QuicMaxStreamsFrame
// A unique identifier of this control frame. 0 when this frame is received,
// and non-zero when sent.
- QuicControlFrameId control_frame_id;
+ QuicControlFrameId control_frame_id = kInvalidControlFrameId;
// The number of streams that may be opened.
- QuicStreamCount stream_count;
+ QuicStreamCount stream_count = 0;
// Whether uni- or bi-directional streams
- bool unidirectional;
+ bool unidirectional = false;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_message_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_message_frame.cc
index 196f6e90f95..45748ad0180 100644
--- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_message_frame.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_message_frame.cc
@@ -10,9 +10,6 @@
namespace quic {
-QuicMessageFrame::QuicMessageFrame()
- : message_id(0), data(nullptr), message_length(0) {}
-
QuicMessageFrame::QuicMessageFrame(QuicMessageId message_id)
: message_id(message_id), data(nullptr), message_length(0) {}
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_message_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_message_frame.h
index 5f285135e10..7f0179c95a9 100644
--- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_message_frame.h
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_message_frame.h
@@ -16,7 +16,7 @@ namespace quic {
typedef QuicInlinedVector<QuicMemSlice, 1> QuicMessageData;
struct QUIC_EXPORT_PRIVATE QuicMessageFrame {
- QuicMessageFrame();
+ QuicMessageFrame() = default;
explicit QuicMessageFrame(QuicMessageId message_id);
QuicMessageFrame(QuicMessageId message_id, QuicMemSliceSpan span);
QuicMessageFrame(const char* data, QuicPacketLength length);
@@ -35,11 +35,11 @@ struct QUIC_EXPORT_PRIVATE QuicMessageFrame {
// message_id is only used on the sender side and does not get serialized on
// wire.
- QuicMessageId message_id;
+ QuicMessageId message_id = 0;
// Not owned, only used on read path.
- const char* data;
+ const char* data = nullptr;
// Total length of message_data, must be fit into one packet.
- QuicPacketLength message_length;
+ QuicPacketLength message_length = 0;
// The actual message data which is reference counted, used on write path.
QuicMessageData message_data;
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_new_connection_id_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_new_connection_id_frame.cc
index f6c86617a67..d2e8cea2ad2 100644
--- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_new_connection_id_frame.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_new_connection_id_frame.cc
@@ -3,15 +3,9 @@
// found in the LICENSE file.
#include "net/third_party/quiche/src/quic/core/frames/quic_new_connection_id_frame.h"
-#include "net/third_party/quiche/src/quic/core/quic_constants.h"
namespace quic {
-QuicNewConnectionIdFrame::QuicNewConnectionIdFrame()
- : control_frame_id(kInvalidControlFrameId),
- connection_id(EmptyQuicConnectionId()),
- sequence_number(0) {}
-
QuicNewConnectionIdFrame::QuicNewConnectionIdFrame(
QuicControlFrameId control_frame_id,
QuicConnectionId connection_id,
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_new_connection_id_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_new_connection_id_frame.h
index 441ca1aaf4d..7bd45865f47 100644
--- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_new_connection_id_frame.h
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_new_connection_id_frame.h
@@ -7,6 +7,8 @@
#include <ostream>
+#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_error_codes.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_uint128.h"
@@ -14,7 +16,7 @@
namespace quic {
struct QUIC_EXPORT_PRIVATE QuicNewConnectionIdFrame {
- QuicNewConnectionIdFrame();
+ QuicNewConnectionIdFrame() = default;
QuicNewConnectionIdFrame(QuicControlFrameId control_frame_id,
QuicConnectionId connection_id,
QuicConnectionIdSequenceNumber sequence_number,
@@ -27,9 +29,9 @@ struct QUIC_EXPORT_PRIVATE QuicNewConnectionIdFrame {
// A unique identifier of this control frame. 0 when this frame is received,
// and non-zero when sent.
- QuicControlFrameId control_frame_id;
- QuicConnectionId connection_id;
- QuicConnectionIdSequenceNumber sequence_number;
+ QuicControlFrameId control_frame_id = kInvalidControlFrameId;
+ QuicConnectionId connection_id = EmptyQuicConnectionId();
+ QuicConnectionIdSequenceNumber sequence_number = 0;
QuicUint128 stateless_reset_token;
uint64_t retire_prior_to;
};
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_new_token_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_new_token_frame.cc
index 2dfb97f9017..0178422526c 100644
--- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_new_token_frame.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_new_token_frame.cc
@@ -4,15 +4,11 @@
#include "net/third_party/quiche/src/quic/core/frames/quic_new_token_frame.h"
-#include "net/third_party/quiche/src/quic/core/quic_constants.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_text_utils.h"
namespace quic {
-QuicNewTokenFrame::QuicNewTokenFrame()
- : control_frame_id(kInvalidControlFrameId) {}
-
QuicNewTokenFrame::QuicNewTokenFrame(QuicControlFrameId control_frame_id,
std::string token)
: control_frame_id(control_frame_id), token(token) {}
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_new_token_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_new_token_frame.h
index 0491477a2dd..abb0eecb2fb 100644
--- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_new_token_frame.h
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_new_token_frame.h
@@ -9,13 +9,14 @@
#include <ostream>
#include "net/third_party/quiche/src/quic/core/quic_buffer_allocator.h"
+#include "net/third_party/quiche/src/quic/core/quic_constants.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 QUIC_EXPORT_PRIVATE QuicNewTokenFrame {
- QuicNewTokenFrame();
+ QuicNewTokenFrame() = default;
QuicNewTokenFrame(QuicControlFrameId control_frame_id, std::string token);
friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(
@@ -24,7 +25,7 @@ struct QUIC_EXPORT_PRIVATE QuicNewTokenFrame {
// A unique identifier of this control frame. 0 when this frame is received,
// and non-zero when sent.
- QuicControlFrameId control_frame_id;
+ QuicControlFrameId control_frame_id = kInvalidControlFrameId;
std::string token;
};
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_padding_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_padding_frame.h
index 03e0a4041fe..0918f0f2463 100644
--- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_padding_frame.h
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_padding_frame.h
@@ -17,17 +17,17 @@ namespace quic {
// A padding frame contains no payload.
struct QUIC_EXPORT_PRIVATE QuicPaddingFrame
: public QuicInlinedFrame<QuicPaddingFrame> {
- QuicPaddingFrame() : QuicInlinedFrame(PADDING_FRAME), num_padding_bytes(-1) {}
+ QuicPaddingFrame() : QuicInlinedFrame(PADDING_FRAME) {}
explicit QuicPaddingFrame(int num_padding_bytes)
: QuicInlinedFrame(PADDING_FRAME), num_padding_bytes(num_padding_bytes) {}
friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(
std::ostream& os,
- const QuicPaddingFrame& s);
+ const QuicPaddingFrame& padding_frame);
// -1: full padding to the end of a max-sized packet
// otherwise: only pad up to num_padding_bytes bytes
- int num_padding_bytes;
+ int num_padding_bytes = -1;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_path_challenge_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_path_challenge_frame.cc
index 998ae483c07..4a8d1207b73 100644
--- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_path_challenge_frame.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_path_challenge_frame.cc
@@ -4,15 +4,11 @@
#include "net/third_party/quiche/src/quic/core/frames/quic_path_challenge_frame.h"
-#include "net/third_party/quiche/src/quic/core/quic_constants.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_text_utils.h"
namespace quic {
-QuicPathChallengeFrame::QuicPathChallengeFrame()
- : control_frame_id(kInvalidControlFrameId) {}
-
QuicPathChallengeFrame::QuicPathChallengeFrame(
QuicControlFrameId control_frame_id,
const QuicPathFrameBuffer& data_buff)
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_path_challenge_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_path_challenge_frame.h
index 46a010ae92b..e173117b581 100644
--- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_path_challenge_frame.h
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_path_challenge_frame.h
@@ -8,15 +8,13 @@
#include <memory>
#include <ostream>
+#include "net/third_party/quiche/src/quic/core/quic_constants.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
namespace quic {
-// Size of the entire IETF Quic Path Challenge frame.
-const size_t kQuicPathChallengeFrameSize = kQuicPathFrameBufferSize;
-
struct QUIC_EXPORT_PRIVATE QuicPathChallengeFrame {
- QuicPathChallengeFrame();
+ QuicPathChallengeFrame() = default;
QuicPathChallengeFrame(QuicControlFrameId control_frame_id,
const QuicPathFrameBuffer& data_buff);
~QuicPathChallengeFrame();
@@ -27,7 +25,7 @@ struct QUIC_EXPORT_PRIVATE QuicPathChallengeFrame {
// A unique identifier of this control frame. 0 when this frame is received,
// and non-zero when sent.
- QuicControlFrameId control_frame_id;
+ QuicControlFrameId control_frame_id = kInvalidControlFrameId;
QuicPathFrameBuffer data_buffer;
};
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_path_response_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_path_response_frame.cc
index e652698ab03..4779c6ad25f 100644
--- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_path_response_frame.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_path_response_frame.cc
@@ -4,15 +4,11 @@
#include "net/third_party/quiche/src/quic/core/frames/quic_path_response_frame.h"
-#include "net/third_party/quiche/src/quic/core/quic_constants.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_text_utils.h"
namespace quic {
-QuicPathResponseFrame::QuicPathResponseFrame()
- : control_frame_id(kInvalidControlFrameId) {}
-
QuicPathResponseFrame::QuicPathResponseFrame(
QuicControlFrameId control_frame_id,
const QuicPathFrameBuffer& data_buff)
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_path_response_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_path_response_frame.h
index e953ad8aa52..cdb0ba89e7c 100644
--- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_path_response_frame.h
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_path_response_frame.h
@@ -8,15 +8,13 @@
#include <memory>
#include <ostream>
+#include "net/third_party/quiche/src/quic/core/quic_constants.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
namespace quic {
-// Size of the entire IETF Quic Path Response frame.
-const size_t kQuicPathResponseFrameSize = kQuicPathFrameBufferSize;
-
struct QUIC_EXPORT_PRIVATE QuicPathResponseFrame {
- QuicPathResponseFrame();
+ QuicPathResponseFrame() = default;
QuicPathResponseFrame(QuicControlFrameId control_frame_id,
const QuicPathFrameBuffer& data_buff);
~QuicPathResponseFrame();
@@ -27,7 +25,7 @@ struct QUIC_EXPORT_PRIVATE QuicPathResponseFrame {
// A unique identifier of this control frame. 0 when this frame is received,
// and non-zero when sent.
- QuicControlFrameId control_frame_id;
+ QuicControlFrameId control_frame_id = kInvalidControlFrameId;
QuicPathFrameBuffer data_buffer;
};
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_ping_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_ping_frame.cc
index d31efb0aae9..064d9170303 100644
--- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_ping_frame.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_ping_frame.cc
@@ -6,8 +6,7 @@
namespace quic {
-QuicPingFrame::QuicPingFrame()
- : QuicInlinedFrame(PING_FRAME), control_frame_id(kInvalidControlFrameId) {}
+QuicPingFrame::QuicPingFrame() : QuicInlinedFrame(PING_FRAME) {}
QuicPingFrame::QuicPingFrame(QuicControlFrameId control_frame_id)
: QuicInlinedFrame(PING_FRAME), control_frame_id(control_frame_id) {}
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_ping_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_ping_frame.h
index 352d079951c..5cefdf9c805 100644
--- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_ping_frame.h
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_ping_frame.h
@@ -25,7 +25,7 @@ struct QUIC_EXPORT_PRIVATE QuicPingFrame
// A unique identifier of this control frame. 0 when this frame is received,
// and non-zero when sent.
- QuicControlFrameId control_frame_id;
+ QuicControlFrameId control_frame_id = kInvalidControlFrameId;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_retire_connection_id_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_retire_connection_id_frame.cc
index 6828ce41227..0da9e0cfc02 100644
--- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_retire_connection_id_frame.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_retire_connection_id_frame.cc
@@ -3,13 +3,9 @@
// found in the LICENSE file.
#include "net/third_party/quiche/src/quic/core/frames/quic_retire_connection_id_frame.h"
-#include "net/third_party/quiche/src/quic/core/quic_constants.h"
namespace quic {
-QuicRetireConnectionIdFrame::QuicRetireConnectionIdFrame()
- : control_frame_id(kInvalidControlFrameId), sequence_number(0) {}
-
QuicRetireConnectionIdFrame::QuicRetireConnectionIdFrame(
QuicControlFrameId control_frame_id,
QuicConnectionIdSequenceNumber sequence_number)
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_retire_connection_id_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_retire_connection_id_frame.h
index 79521f647a0..4451d319546 100644
--- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_retire_connection_id_frame.h
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_retire_connection_id_frame.h
@@ -7,6 +7,7 @@
#include <ostream>
+#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/platform/api/quic_uint128.h"
@@ -14,7 +15,7 @@
namespace quic {
struct QUIC_EXPORT_PRIVATE QuicRetireConnectionIdFrame {
- QuicRetireConnectionIdFrame();
+ QuicRetireConnectionIdFrame() = default;
QuicRetireConnectionIdFrame(QuicControlFrameId control_frame_id,
QuicConnectionIdSequenceNumber sequence_number);
@@ -24,8 +25,8 @@ struct QUIC_EXPORT_PRIVATE QuicRetireConnectionIdFrame {
// A unique identifier of this control frame. 0 when this frame is received,
// and non-zero when sent.
- QuicControlFrameId control_frame_id;
- QuicConnectionIdSequenceNumber sequence_number;
+ QuicControlFrameId control_frame_id = kInvalidControlFrameId;
+ QuicConnectionIdSequenceNumber sequence_number = 0;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_rst_stream_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_rst_stream_frame.cc
index 63cf6eaf6a3..41a1fd391fe 100644
--- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_rst_stream_frame.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_rst_stream_frame.cc
@@ -3,16 +3,9 @@
// found in the LICENSE file.
#include "net/third_party/quiche/src/quic/core/frames/quic_rst_stream_frame.h"
-#include "net/third_party/quiche/src/quic/core/quic_constants.h"
namespace quic {
-QuicRstStreamFrame::QuicRstStreamFrame()
- : control_frame_id(kInvalidControlFrameId),
- stream_id(0),
- error_code(QUIC_STREAM_NO_ERROR),
- byte_offset(0) {}
-
QuicRstStreamFrame::QuicRstStreamFrame(QuicControlFrameId control_frame_id,
QuicStreamId stream_id,
QuicRstStreamErrorCode error_code,
@@ -20,15 +13,7 @@ QuicRstStreamFrame::QuicRstStreamFrame(QuicControlFrameId control_frame_id,
: control_frame_id(control_frame_id),
stream_id(stream_id),
error_code(error_code),
- byte_offset(bytes_written) {}
-
-QuicRstStreamFrame::QuicRstStreamFrame(QuicControlFrameId control_frame_id,
- QuicStreamId stream_id,
- uint16_t ietf_error_code,
- QuicStreamOffset bytes_written)
- : control_frame_id(control_frame_id),
- stream_id(stream_id),
- ietf_error_code(ietf_error_code),
+ ietf_error_code(RstStreamErrorCodeToIetfResetStreamErrorCode(error_code)),
byte_offset(bytes_written) {}
std::ostream& operator<<(std::ostream& os,
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_rst_stream_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_rst_stream_frame.h
index 9a9ed56abb0..691a868cbee 100644
--- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_rst_stream_frame.h
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_rst_stream_frame.h
@@ -7,21 +7,18 @@
#include <ostream>
+#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"
namespace quic {
struct QUIC_EXPORT_PRIVATE QuicRstStreamFrame {
- QuicRstStreamFrame();
+ QuicRstStreamFrame() = default;
QuicRstStreamFrame(QuicControlFrameId control_frame_id,
QuicStreamId stream_id,
QuicRstStreamErrorCode error_code,
QuicStreamOffset bytes_written);
- QuicRstStreamFrame(QuicControlFrameId control_frame_id,
- QuicStreamId stream_id,
- uint16_t ietf_error_code,
- QuicStreamOffset bytes_written);
friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(
std::ostream& os,
@@ -29,25 +26,25 @@ struct QUIC_EXPORT_PRIVATE QuicRstStreamFrame {
// A unique identifier of this control frame. 0 when this frame is received,
// and non-zero when sent.
- QuicControlFrameId control_frame_id;
+ QuicControlFrameId control_frame_id = kInvalidControlFrameId;
+
+ QuicStreamId stream_id = 0;
- QuicStreamId stream_id;
+ // When using Google QUIC: the RST_STREAM error code on the wire.
+ // When using IETF QUIC: for an outgoing RESET_STREAM frame, the error code
+ // generated by the application that determines |ietf_error_code| to be sent
+ // on the wire; for an incoming RESET_STREAM frame, the error code inferred
+ // from the |ietf_error_code| received on the wire.
+ QuicRstStreamErrorCode error_code = QUIC_STREAM_NO_ERROR;
- // Caller must know whether IETF- or Google- QUIC is in use and
- // set the appropriate error code.
- union {
- QuicRstStreamErrorCode error_code;
- // In IETF QUIC the code is up to the app on top of quic, so is
- // more general than QuicRstStreamErrorCode allows.
- // TODO(fkastenholz): Upgrade to uint64_t
- uint16_t ietf_error_code;
- };
+ // Application error code of RESET_STREAM frame. Used for IETF QUIC only.
+ uint64_t ietf_error_code = 0;
// Used to update flow control windows. On termination of a stream, both
// endpoints must inform the peer of the number of bytes they have sent on
// that stream. This can be done through normal termination (data packet with
// FIN) or through a RST.
- QuicStreamOffset byte_offset;
+ QuicStreamOffset byte_offset = 0;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_stop_sending_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_stop_sending_frame.cc
index 1afd512150a..c4d732ed44d 100644
--- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_stop_sending_frame.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_stop_sending_frame.cc
@@ -3,15 +3,9 @@
// found in the LICENSE file.
#include "net/third_party/quiche/src/quic/core/frames/quic_stop_sending_frame.h"
-#include "net/third_party/quiche/src/quic/core/quic_constants.h"
namespace quic {
-QuicStopSendingFrame::QuicStopSendingFrame()
- : control_frame_id(kInvalidControlFrameId),
- stream_id(0),
- application_error_code(0) {}
-
QuicStopSendingFrame::QuicStopSendingFrame(
QuicControlFrameId control_frame_id,
QuicStreamId stream_id,
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_stop_sending_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_stop_sending_frame.h
index 7ca639d2eb3..8222067d276 100644
--- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_stop_sending_frame.h
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_stop_sending_frame.h
@@ -7,13 +7,14 @@
#include <ostream>
+#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"
namespace quic {
struct QUIC_EXPORT_PRIVATE QuicStopSendingFrame {
- QuicStopSendingFrame();
+ QuicStopSendingFrame() = default;
QuicStopSendingFrame(QuicControlFrameId control_frame_id,
QuicStreamId stream_id,
QuicApplicationErrorCode application_error_code);
@@ -24,9 +25,9 @@ struct QUIC_EXPORT_PRIVATE QuicStopSendingFrame {
// A unique identifier of this control frame. 0 when this frame is received,
// and non-zero when sent.
- QuicControlFrameId control_frame_id;
- QuicStreamId stream_id;
- QuicApplicationErrorCode application_error_code;
+ QuicControlFrameId control_frame_id = kInvalidControlFrameId;
+ QuicStreamId stream_id = 0;
+ QuicApplicationErrorCode application_error_code = 0;
};
} // namespace quic
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 54a5252bb7d..db199998860 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
@@ -9,8 +9,7 @@
namespace quic {
-QuicStreamFrame::QuicStreamFrame()
- : QuicStreamFrame(-1, false, 0, nullptr, 0) {}
+QuicStreamFrame::QuicStreamFrame() : QuicInlinedFrame(STREAM_FRAME) {}
QuicStreamFrame::QuicStreamFrame(QuicStreamId stream_id,
bool fin,
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 fc78ff9df7f..f807ee1e4c9 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
@@ -35,11 +35,13 @@ struct QUIC_EXPORT_PRIVATE QuicStreamFrame
bool operator!=(const QuicStreamFrame& rhs) const;
- bool fin;
- QuicPacketLength data_length;
- QuicStreamId stream_id;
- const char* data_buffer; // Not owned.
- QuicStreamOffset offset; // Location of this data in the stream.
+ bool fin = false;
+ QuicPacketLength data_length = 0;
+ // TODO(wub): Change to a QuicUtils::GetInvalidStreamId when it is not version
+ // dependent.
+ QuicStreamId stream_id = -1;
+ const char* data_buffer = nullptr; // Not owned.
+ QuicStreamOffset offset = 0; // Location of this data in the stream.
QuicStreamFrame(QuicStreamId stream_id,
bool fin,
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_streams_blocked_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_streams_blocked_frame.cc
index f0579c55b68..9300ce32e51 100644
--- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_streams_blocked_frame.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_streams_blocked_frame.cc
@@ -7,9 +7,7 @@
namespace quic {
QuicStreamsBlockedFrame::QuicStreamsBlockedFrame()
- : QuicInlinedFrame(STREAMS_BLOCKED_FRAME),
- control_frame_id(kInvalidControlFrameId),
- unidirectional(false) {}
+ : QuicInlinedFrame(STREAMS_BLOCKED_FRAME) {}
QuicStreamsBlockedFrame::QuicStreamsBlockedFrame(
QuicControlFrameId control_frame_id,
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_streams_blocked_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_streams_blocked_frame.h
index ff7c7f44621..91c7ac91a84 100644
--- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_streams_blocked_frame.h
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_streams_blocked_frame.h
@@ -30,13 +30,13 @@ struct QUIC_EXPORT_PRIVATE QuicStreamsBlockedFrame
// A unique identifier of this control frame. 0 when this frame is received,
// and non-zero when sent.
- QuicControlFrameId control_frame_id;
+ QuicControlFrameId control_frame_id = kInvalidControlFrameId;
// The number of streams that the sender wishes to exceed
QuicStreamCount stream_count;
// Whether uni- or bi-directional streams
- bool unidirectional;
+ bool unidirectional = false;
};
} // namespace quic
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 81ca125b64c..a4f3ec32c01 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
@@ -3,13 +3,9 @@
// found in the LICENSE file.
#include "net/third_party/quiche/src/quic/core/frames/quic_window_update_frame.h"
-#include "net/third_party/quiche/src/quic/core/quic_constants.h"
namespace quic {
-QuicWindowUpdateFrame::QuicWindowUpdateFrame()
- : control_frame_id(kInvalidControlFrameId) {}
-
QuicWindowUpdateFrame::QuicWindowUpdateFrame(
QuicControlFrameId control_frame_id,
QuicStreamId stream_id,
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 ff4478528dd..74181f5f1d2 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
@@ -7,6 +7,7 @@
#include <ostream>
+#include "net/third_party/quiche/src/quic/core/quic_constants.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
namespace quic {
@@ -15,7 +16,7 @@ namespace quic {
// 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() = default;
QuicWindowUpdateFrame(QuicControlFrameId control_frame_id,
QuicStreamId stream_id,
QuicByteCount max_data);
@@ -26,7 +27,7 @@ struct QUIC_EXPORT_PRIVATE QuicWindowUpdateFrame {
// A unique identifier of this control frame. 0 when this frame is received,
// and non-zero when sent.
- QuicControlFrameId control_frame_id;
+ QuicControlFrameId control_frame_id = kInvalidControlFrameId;
// The stream this frame applies to. 0 is a special case meaning the overall
// connection rather than a specific stream.
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 cec0ceb9fff..782394427f4 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
@@ -81,108 +81,40 @@ const float kSessionToStreamRatio = 1.5;
// Run all tests with the cross products of all versions.
struct TestParams {
- TestParams(const ParsedQuicVersionVector& client_supported_versions,
- const ParsedQuicVersionVector& server_supported_versions,
- ParsedQuicVersion negotiated_version,
- QuicTag congestion_control_tag)
- : client_supported_versions(client_supported_versions),
- server_supported_versions(server_supported_versions),
- negotiated_version(negotiated_version),
- congestion_control_tag(congestion_control_tag) {}
+ TestParams(const ParsedQuicVersion& version, QuicTag congestion_control_tag)
+ : version(version), congestion_control_tag(congestion_control_tag) {}
friend std::ostream& operator<<(std::ostream& os, const TestParams& p) {
- os << "{ server_supported_versions: "
- << ParsedQuicVersionVectorToString(p.server_supported_versions);
- os << " client_supported_versions: "
- << ParsedQuicVersionVectorToString(p.client_supported_versions);
- os << " negotiated_version: "
- << ParsedQuicVersionToString(p.negotiated_version);
+ os << "{ version: " << ParsedQuicVersionToString(p.version);
os << " congestion_control_tag: "
<< QuicTagToString(p.congestion_control_tag) << " }";
return os;
}
- ParsedQuicVersionVector client_supported_versions;
- ParsedQuicVersionVector server_supported_versions;
- ParsedQuicVersion negotiated_version;
+ ParsedQuicVersion version;
QuicTag congestion_control_tag;
};
// Used by ::testing::PrintToStringParamName().
std::string PrintToString(const TestParams& p) {
- std::string rv = quiche::QuicheStrCat(
- ParsedQuicVersionToString(p.negotiated_version), "_Server_",
- ParsedQuicVersionVectorToString(p.server_supported_versions), "_Client_",
- ParsedQuicVersionVectorToString(p.client_supported_versions), "_",
- QuicTagToString(p.congestion_control_tag));
+ std::string rv =
+ quiche::QuicheStrCat(ParsedQuicVersionToString(p.version), "_",
+ QuicTagToString(p.congestion_control_tag));
std::replace(rv.begin(), rv.end(), ',', '_');
std::replace(rv.begin(), rv.end(), ' ', '_');
return rv;
}
// Constructs various test permutations.
-std::vector<TestParams> GetTestParams(bool use_tls_handshake) {
- // Divide the versions into buckets in which the intra-frame format
- // is compatible. When clients encounter QUIC version negotiation
- // they simply retransmit all packets using the new version's
- // QUIC framing. However, they are unable to change the intra-frame
- // layout (for example to change HTTP/2 headers to SPDY/3, or a change in the
- // handshake protocol). So these tests need to ensure that clients are never
- // attempting to do 0-RTT across incompatible versions. Chromium only
- // supports a single version at a time anyway. :)
- ParsedQuicVersionVector all_supported_versions =
- FilterSupportedVersions(AllSupportedVersions());
-
- // Buckets are separated by versions: versions without crypto frames use
- // STREAM frames for the handshake, and only have QUIC crypto as the handshake
- // 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) {
- if (!use_tls_handshake && version.handshake_protocol == PROTOCOL_TLS1_3) {
- continue;
- }
- if (!QuicVersionUsesCryptoFrames(version.transport_version)) {
- version_buckets[0].push_back(version);
- } else if (version.handshake_protocol == PROTOCOL_QUIC_CRYPTO) {
- version_buckets[1].push_back(version);
- } else {
- version_buckets[2].push_back(version);
- }
- }
-
+std::vector<TestParams> GetTestParams() {
std::vector<TestParams> params;
for (const QuicTag congestion_control_tag : {kRENO, kTBBR, kQBIC, kB2ON}) {
if (!GetQuicReloadableFlag(quic_allow_client_enabled_bbr_v2) &&
congestion_control_tag == kB2ON) {
continue;
}
- for (const ParsedQuicVersionVector& client_versions : version_buckets) {
- if (FilterSupportedVersions(client_versions).empty()) {
- continue;
- }
- // Add an entry for server and client supporting all versions.
- params.push_back(TestParams(client_versions, all_supported_versions,
- client_versions.front(),
- congestion_control_tag));
- // Test client supporting all versions and server supporting
- // 1 version. Simulate an old server and exercise version
- // downgrade in the client. Protocol negotiation should
- // occur. Skip the i = 0 case because it is essentially the
- // same as the default case.
- for (size_t i = 1; i < client_versions.size(); ++i) {
- ParsedQuicVersionVector server_supported_versions;
- server_supported_versions.push_back(client_versions[i]);
- if (FilterSupportedVersions(server_supported_versions).empty()) {
- continue;
- }
- params.push_back(TestParams(client_versions, server_supported_versions,
- server_supported_versions.front(),
- congestion_control_tag));
- } // End of inner version loop.
+ for (const ParsedQuicVersion& version : CurrentSupportedVersions()) {
+ params.push_back(TestParams(version, congestion_control_tag));
} // End of outer version loop.
} // End of congestion_control_tag loop.
@@ -231,14 +163,12 @@ class EndToEndTest : public QuicTestWithParam<TestParams> {
server_hostname_("test.example.com"),
client_writer_(nullptr),
server_writer_(nullptr),
- negotiated_version_(UnsupportedQuicVersion()),
+ version_(GetParam().version),
+ client_supported_versions_({version_}),
+ server_supported_versions_(CurrentSupportedVersions()),
chlo_multiplier_(0),
stream_factory_(nullptr),
expected_server_connection_id_length_(kQuicDefaultConnectionIdLength) {
- client_supported_versions_ = GetParam().client_supported_versions;
- server_supported_versions_ = GetParam().server_supported_versions;
- negotiated_version_ = GetParam().negotiated_version;
-
QUIC_LOG(INFO) << "Using Configuration: " << GetParam();
// Use different flow control windows for client/server.
@@ -377,7 +307,7 @@ class EndToEndTest : public QuicTestWithParam<TestParams> {
// client as well according to the test parameter.
copt.push_back(GetParam().congestion_control_tag);
copt.push_back(k2PTO);
- if (VersionHasIetfQuicFrames(negotiated_version_.transport_version)) {
+ if (VersionHasIetfQuicFrames(version_.transport_version)) {
copt.push_back(kILD0);
}
copt.push_back(kPLE1);
@@ -496,12 +426,12 @@ class EndToEndTest : public QuicTestWithParam<TestParams> {
if (!ServerSendsVersionNegotiation()) {
EXPECT_EQ(0u, client_stats.packets_dropped);
}
- if (!ClientSupportsIetfQuicNotSupportedByServer()) {
- // In this case, if client sends 0-RTT POST with v99, receives IETF
- // version negotiation packet and speaks a GQUIC version. Server processes
- // this connection in time wait list and keeps sending IETF version
- // negotiation packet for incoming packets. But these version negotiation
- // packets cannot be processed by the client speaking GQUIC.
+ if (!version_.UsesTls()) {
+ // Only enforce this for QUIC crypto because accounting of number of
+ // packets received, processed gets complicated with packets coalescing
+ // and key dropping. For example, a received undecryptable coalesced
+ // packet can be processed later and each sub-packet increases
+ // packets_processed.
EXPECT_EQ(client_stats.packets_received, client_stats.packets_processed);
}
@@ -517,19 +447,10 @@ class EndToEndTest : public QuicTestWithParam<TestParams> {
server_thread_->Resume();
}
- // Client supports IETF QUIC, while it is not supported by server.
- bool ClientSupportsIetfQuicNotSupportedByServer() {
- return VersionHasIetfInvariantHeader(
- client_supported_versions_[0].transport_version) &&
- !VersionHasIetfInvariantHeader(
- FilterSupportedVersions(GetParam().server_supported_versions)[0]
- .transport_version);
- }
-
// Returns true when client starts with an unsupported version, and client
// closes connection when version negotiation is received.
bool ServerSendsVersionNegotiation() {
- return client_supported_versions_[0] != GetParam().negotiated_version;
+ return client_supported_versions_[0] != version_;
}
bool SupportsIetfQuicWithTls(ParsedQuicVersion version) {
@@ -587,10 +508,10 @@ class EndToEndTest : public QuicTestWithParam<TestParams> {
PacketDroppingTestWriter* server_writer_;
QuicConfig client_config_;
QuicConfig server_config_;
+ ParsedQuicVersion version_;
ParsedQuicVersionVector client_supported_versions_;
ParsedQuicVersionVector server_supported_versions_;
QuicTagVector client_extra_copts_;
- ParsedQuicVersion negotiated_version_;
size_t chlo_multiplier_;
QuicTestServer::StreamFactory* stream_factory_;
std::string pre_shared_key_client_;
@@ -603,27 +524,13 @@ class EndToEndTest : public QuicTestWithParam<TestParams> {
// Run all end to end tests with all supported versions.
INSTANTIATE_TEST_SUITE_P(EndToEndTests,
EndToEndTest,
- ::testing::ValuesIn(GetTestParams(false)),
+ ::testing::ValuesIn(GetTestParams()),
::testing::PrintToStringParamName());
-class EndToEndTestWithTls : public EndToEndTest {};
-
-INSTANTIATE_TEST_SUITE_P(EndToEndTestsWithTls,
- EndToEndTestWithTls,
- ::testing::ValuesIn(GetTestParams(true)),
- ::testing::PrintToStringParamName());
-
-TEST_P(EndToEndTestWithTls, HandshakeSuccessful) {
+TEST_P(EndToEndTest, HandshakeSuccessful) {
ASSERT_TRUE(Initialize());
EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
server_thread_->WaitForCryptoHandshakeConfirmed();
- // There have been occasions where it seemed that negotiated_version_ and the
- // version in the connection are not in sync. If it is happening, it has not
- // been recreatable; this assert is here just to check and raise a flag if it
- // happens.
- ASSERT_EQ(GetClientConnection()->transport_version(),
- negotiated_version_.transport_version);
-
QuicCryptoStream* crypto_stream =
QuicSessionPeer::GetMutableCryptoStream(GetClientSession());
QuicStreamSequencer* sequencer = QuicStreamPeer::sequencer(crypto_stream);
@@ -632,6 +539,14 @@ TEST_P(EndToEndTestWithTls, HandshakeSuccessful) {
crypto_stream = QuicSessionPeer::GetMutableCryptoStream(GetServerSession());
sequencer = QuicStreamPeer::sequencer(crypto_stream);
EXPECT_FALSE(QuicStreamSequencerPeer::IsUnderlyingBufferAllocated(sequencer));
+
+ // We've had bugs in the past where the connections could end up on the wrong
+ // version. This was never diagnosed but could have been due to in-connection
+ // version negotiation back when that existed. At this point in time, our test
+ // setup ensures that connections here always use |version_|, but we add this
+ // sanity check out of paranoia to catch a regression of this type.
+ EXPECT_EQ(GetClientConnection()->version(), version_);
+ EXPECT_EQ(GetServerConnection()->version(), version_);
}
TEST_P(EndToEndTest, SimpleRequestResponse) {
@@ -651,15 +566,9 @@ TEST_P(EndToEndTest, SimpleRequestResponse) {
}
}
-TEST_P(EndToEndTestWithTls, SimpleRequestResponse) {
- ASSERT_TRUE(Initialize());
- EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
- EXPECT_EQ("200", client_->response_headers()->find(":status")->second);
-}
-
-TEST_P(EndToEndTestWithTls, HandshakeConfirmed) {
+TEST_P(EndToEndTest, HandshakeConfirmed) {
ASSERT_TRUE(Initialize());
- if (!GetParam().negotiated_version.HasHandshakeDone()) {
+ if (!version_.HasHandshakeDone()) {
return;
}
EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
@@ -672,7 +581,7 @@ TEST_P(EndToEndTestWithTls, HandshakeConfirmed) {
client_->Disconnect();
}
-TEST_P(EndToEndTestWithTls, SendAndReceiveCoalescedPackets) {
+TEST_P(EndToEndTest, SendAndReceiveCoalescedPackets) {
ASSERT_TRUE(Initialize());
if (!GetClientConnection()->version().CanSendCoalescedPackets()) {
return;
@@ -690,6 +599,11 @@ TEST_P(EndToEndTestWithTls, SendAndReceiveCoalescedPackets) {
// Simple transaction, but set a non-default ack delay at the client
// and ensure it gets to the server.
TEST_P(EndToEndTest, SimpleRequestResponseWithAckDelayChange) {
+ if (version_.UsesTls()) {
+ // TODO(b/155316241): Enable this test for TLS.
+ Initialize();
+ return;
+ }
// Force the ACK delay to be something other than the default.
// Note that it is sent only if doing IETF QUIC.
client_config_.SetMaxAckDelayToSendMs(kDefaultDelayedAckTimeMs + 100u);
@@ -715,6 +629,11 @@ TEST_P(EndToEndTest, SimpleRequestResponseWithAckDelayChange) {
// Simple transaction, but set a non-default ack exponent at the client
// and ensure it gets to the server.
TEST_P(EndToEndTest, SimpleRequestResponseWithAckExponentChange) {
+ if (version_.UsesTls()) {
+ // TODO(b/155316241): Enable this test for TLS.
+ Initialize();
+ return;
+ }
const uint32_t kClientAckDelayExponent = kDefaultAckDelayExponent + 100u;
// Force the ACK exponent to be something other than the default.
// Note that it is sent only if doing IETF QUIC.
@@ -726,8 +645,7 @@ TEST_P(EndToEndTest, SimpleRequestResponseWithAckExponentChange) {
EXPECT_FALSE(client_->client()->EarlyDataAccepted());
EXPECT_FALSE(client_->client()->ReceivedInchoateReject());
- if (VersionHasIetfQuicFrames(
- GetParam().negotiated_version.transport_version)) {
+ if (VersionHasIetfQuicFrames(version_.transport_version)) {
// Should be only for IETF QUIC.
EXPECT_EQ(kClientAckDelayExponent,
GetServerConnection()->framer().peer_ack_delay_exponent());
@@ -757,7 +675,7 @@ TEST_P(EndToEndTest, SimpleRequestResponseForcedVersionNegotiation) {
EXPECT_FALSE(client_->client()->ReceivedInchoateReject());
}
-TEST_P(EndToEndTestWithTls, ForcedVersionNegotiation) {
+TEST_P(EndToEndTest, ForcedVersionNegotiation) {
client_supported_versions_.insert(client_supported_versions_.begin(),
QuicVersionReservedForNegotiation());
ASSERT_TRUE(Initialize());
@@ -768,7 +686,7 @@ TEST_P(EndToEndTestWithTls, ForcedVersionNegotiation) {
}
TEST_P(EndToEndTest, SimpleRequestResponseZeroConnectionID) {
- if (!GetParam().negotiated_version.AllowsVariableLengthConnectionIds()) {
+ if (!version_.AllowsVariableLengthConnectionIds()) {
ASSERT_TRUE(Initialize());
return;
}
@@ -781,12 +699,11 @@ TEST_P(EndToEndTest, SimpleRequestResponseZeroConnectionID) {
EXPECT_FALSE(client_->client()->EarlyDataAccepted());
EXPECT_FALSE(client_->client()->ReceivedInchoateReject());
EXPECT_EQ(GetClientConnection()->connection_id(),
- QuicUtils::CreateZeroConnectionId(
- GetParam().negotiated_version.transport_version));
+ QuicUtils::CreateZeroConnectionId(version_.transport_version));
}
-TEST_P(EndToEndTestWithTls, ZeroConnectionID) {
- if (!GetParam().negotiated_version.AllowsVariableLengthConnectionIds()) {
+TEST_P(EndToEndTest, ZeroConnectionID) {
+ if (!version_.AllowsVariableLengthConnectionIds()) {
ASSERT_TRUE(Initialize());
return;
}
@@ -797,12 +714,11 @@ TEST_P(EndToEndTestWithTls, ZeroConnectionID) {
EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
EXPECT_EQ("200", client_->response_headers()->find(":status")->second);
EXPECT_EQ(GetClientConnection()->connection_id(),
- QuicUtils::CreateZeroConnectionId(
- GetParam().negotiated_version.transport_version));
+ QuicUtils::CreateZeroConnectionId(version_.transport_version));
}
-TEST_P(EndToEndTestWithTls, BadConnectionIdLength) {
- if (!GetParam().negotiated_version.AllowsVariableLengthConnectionIds()) {
+TEST_P(EndToEndTest, BadConnectionIdLength) {
+ if (!version_.AllowsVariableLengthConnectionIds()) {
ASSERT_TRUE(Initialize());
return;
}
@@ -819,8 +735,8 @@ TEST_P(EndToEndTestWithTls, BadConnectionIdLength) {
// Tests a very long (16-byte) initial destination connection ID to make
// sure the dispatcher properly replaces it with an 8-byte one.
-TEST_P(EndToEndTestWithTls, LongBadConnectionIdLength) {
- if (!GetParam().negotiated_version.AllowsVariableLengthConnectionIds()) {
+TEST_P(EndToEndTest, LongBadConnectionIdLength) {
+ if (!version_.AllowsVariableLengthConnectionIds()) {
ASSERT_TRUE(Initialize());
return;
}
@@ -835,8 +751,8 @@ TEST_P(EndToEndTestWithTls, LongBadConnectionIdLength) {
.length());
}
-TEST_P(EndToEndTestWithTls, ClientConnectionId) {
- if (!GetParam().negotiated_version.SupportsClientConnectionIds()) {
+TEST_P(EndToEndTest, ClientConnectionId) {
+ if (!version_.SupportsClientConnectionIds()) {
ASSERT_TRUE(Initialize());
return;
}
@@ -851,8 +767,8 @@ TEST_P(EndToEndTestWithTls, ClientConnectionId) {
.length());
}
-TEST_P(EndToEndTestWithTls, ForcedVersionNegotiationAndClientConnectionId) {
- if (!GetParam().negotiated_version.SupportsClientConnectionIds()) {
+TEST_P(EndToEndTest, ForcedVersionNegotiationAndClientConnectionId) {
+ if (!version_.SupportsClientConnectionIds()) {
ASSERT_TRUE(Initialize());
return;
}
@@ -870,8 +786,8 @@ TEST_P(EndToEndTestWithTls, ForcedVersionNegotiationAndClientConnectionId) {
.length());
}
-TEST_P(EndToEndTestWithTls, ForcedVersionNegotiationAndBadConnectionIdLength) {
- if (!GetParam().negotiated_version.AllowsVariableLengthConnectionIds()) {
+TEST_P(EndToEndTest, ForcedVersionNegotiationAndBadConnectionIdLength) {
+ if (!version_.AllowsVariableLengthConnectionIds()) {
ASSERT_TRUE(Initialize());
return;
}
@@ -891,9 +807,9 @@ TEST_P(EndToEndTestWithTls, ForcedVersionNegotiationAndBadConnectionIdLength) {
// Forced Version Negotiation with a client connection ID and a long
// connection ID.
-TEST_P(EndToEndTestWithTls, ForcedVersNegoAndClientCIDAndLongCID) {
- if (!GetParam().negotiated_version.SupportsClientConnectionIds() ||
- !GetParam().negotiated_version.AllowsVariableLengthConnectionIds()) {
+TEST_P(EndToEndTest, ForcedVersNegoAndClientCIDAndLongCID) {
+ if (!version_.SupportsClientConnectionIds() ||
+ !version_.AllowsVariableLengthConnectionIds()) {
ASSERT_TRUE(Initialize());
return;
}
@@ -918,7 +834,7 @@ TEST_P(EndToEndTestWithTls, ForcedVersNegoAndClientCIDAndLongCID) {
}
TEST_P(EndToEndTest, MixGoodAndBadConnectionIdLengths) {
- if (!GetParam().negotiated_version.AllowsVariableLengthConnectionIds()) {
+ if (!version_.AllowsVariableLengthConnectionIds()) {
ASSERT_TRUE(Initialize());
return;
}
@@ -957,8 +873,8 @@ TEST_P(EndToEndTest, MixGoodAndBadConnectionIdLengths) {
.length());
}
-TEST_P(EndToEndTestWithTls, SimpleRequestResponseWithIetfDraftSupport) {
- if (!GetParam().negotiated_version.HasIetfQuicFrames()) {
+TEST_P(EndToEndTest, SimpleRequestResponseWithIetfDraftSupport) {
+ if (!version_.HasIetfQuicFrames()) {
ASSERT_TRUE(Initialize());
return;
}
@@ -976,10 +892,15 @@ TEST_P(EndToEndTest, SimpleRequestResponseWithLargeReject) {
EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
EXPECT_EQ("200", client_->response_headers()->find(":status")->second);
EXPECT_FALSE(client_->client()->EarlyDataAccepted());
- EXPECT_TRUE(client_->client()->ReceivedInchoateReject());
+ if (version_.UsesTls()) {
+ // REJ messages are a QUIC crypto feature, so TLS always returns false.
+ EXPECT_FALSE(client_->client()->ReceivedInchoateReject());
+ } else {
+ EXPECT_TRUE(client_->client()->ReceivedInchoateReject());
+ }
}
-TEST_P(EndToEndTestWithTls, SimpleRequestResponsev6) {
+TEST_P(EndToEndTest, SimpleRequestResponsev6) {
server_address_ =
QuicSocketAddress(QuicIpAddress::Loopback6(), server_address_.port());
ASSERT_TRUE(Initialize());
@@ -988,7 +909,7 @@ TEST_P(EndToEndTestWithTls, SimpleRequestResponsev6) {
EXPECT_EQ("200", client_->response_headers()->find(":status")->second);
}
-TEST_P(EndToEndTestWithTls,
+TEST_P(EndToEndTest,
ClientDoesNotAllowServerDataOnServerInitiatedBidirectionalStreams) {
set_client_initial_max_stream_data_incoming_bidirectional(0);
ASSERT_TRUE(Initialize());
@@ -996,7 +917,7 @@ TEST_P(EndToEndTestWithTls,
EXPECT_EQ("200", client_->response_headers()->find(":status")->second);
}
-TEST_P(EndToEndTestWithTls,
+TEST_P(EndToEndTest,
ServerDoesNotAllowClientDataOnServerInitiatedBidirectionalStreams) {
set_server_initial_max_stream_data_outgoing_bidirectional(0);
ASSERT_TRUE(Initialize());
@@ -1004,7 +925,7 @@ TEST_P(EndToEndTestWithTls,
EXPECT_EQ("200", client_->response_headers()->find(":status")->second);
}
-TEST_P(EndToEndTestWithTls,
+TEST_P(EndToEndTest,
BothEndpointsDisallowDataOnServerInitiatedBidirectionalStreams) {
set_client_initial_max_stream_data_incoming_bidirectional(0);
set_server_initial_max_stream_data_outgoing_bidirectional(0);
@@ -1017,7 +938,7 @@ TEST_P(EndToEndTestWithTls,
// initial packet. Undecryptable packets can be seen after the handshake
// is complete due to dropping the initial keys at that point, so we only test
// for undecryptable packets before then.
-TEST_P(EndToEndTestWithTls, NoUndecryptablePacketsBeforeHandshakeComplete) {
+TEST_P(EndToEndTest, NoUndecryptablePacketsBeforeHandshakeComplete) {
ASSERT_TRUE(Initialize());
EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
@@ -1036,7 +957,7 @@ TEST_P(EndToEndTestWithTls, NoUndecryptablePacketsBeforeHandshakeComplete) {
server_thread_->Resume();
}
-TEST_P(EndToEndTestWithTls, SeparateFinPacket) {
+TEST_P(EndToEndTest, SeparateFinPacket) {
ASSERT_TRUE(Initialize());
// Send a request in two parts: the request and then an empty packet with FIN.
@@ -1060,7 +981,7 @@ TEST_P(EndToEndTestWithTls, SeparateFinPacket) {
EXPECT_EQ("200", client_->response_headers()->find(":status")->second);
}
-TEST_P(EndToEndTestWithTls, MultipleRequestResponse) {
+TEST_P(EndToEndTest, MultipleRequestResponse) {
ASSERT_TRUE(Initialize());
EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
@@ -1070,7 +991,7 @@ TEST_P(EndToEndTestWithTls, MultipleRequestResponse) {
}
TEST_P(EndToEndTest, MultipleRequestResponseZeroConnectionID) {
- if (!GetParam().negotiated_version.AllowsVariableLengthConnectionIds()) {
+ if (!version_.AllowsVariableLengthConnectionIds()) {
ASSERT_TRUE(Initialize());
return;
}
@@ -1084,7 +1005,7 @@ TEST_P(EndToEndTest, MultipleRequestResponseZeroConnectionID) {
EXPECT_EQ("200", client_->response_headers()->find(":status")->second);
}
-TEST_P(EndToEndTestWithTls, MultipleStreams) {
+TEST_P(EndToEndTest, MultipleStreams) {
// Verifies quic_test_client can track responses of all active streams.
ASSERT_TRUE(Initialize());
@@ -1109,7 +1030,7 @@ TEST_P(EndToEndTestWithTls, MultipleStreams) {
}
}
-TEST_P(EndToEndTestWithTls, MultipleClients) {
+TEST_P(EndToEndTest, MultipleClients) {
ASSERT_TRUE(Initialize());
std::unique_ptr<QuicTestClient> client2(CreateQuicClient(nullptr));
@@ -1134,7 +1055,7 @@ TEST_P(EndToEndTestWithTls, MultipleClients) {
EXPECT_EQ("200", client2->response_headers()->find(":status")->second);
}
-TEST_P(EndToEndTestWithTls, RequestOverMultiplePackets) {
+TEST_P(EndToEndTest, RequestOverMultiplePackets) {
// Send a large enough request to guarantee fragmentation.
std::string huge_request =
"/some/path?query=" + std::string(kMaxOutgoingPacketSize, '.');
@@ -1146,7 +1067,7 @@ TEST_P(EndToEndTestWithTls, RequestOverMultiplePackets) {
EXPECT_EQ("200", client_->response_headers()->find(":status")->second);
}
-TEST_P(EndToEndTestWithTls, MultiplePacketsRandomOrder) {
+TEST_P(EndToEndTest, MultiplePacketsRandomOrder) {
// Send a large enough request to guarantee fragmentation.
std::string huge_request =
"/some/path?query=" + std::string(kMaxOutgoingPacketSize, '.');
@@ -1160,7 +1081,7 @@ TEST_P(EndToEndTestWithTls, MultiplePacketsRandomOrder) {
EXPECT_EQ("200", client_->response_headers()->find(":status")->second);
}
-TEST_P(EndToEndTestWithTls, PostMissingBytes) {
+TEST_P(EndToEndTest, PostMissingBytes) {
ASSERT_TRUE(Initialize());
// Add a content length header with no body.
@@ -1317,6 +1238,11 @@ TEST_P(EndToEndTest, LargePostNoPacketLossWithDelayAndReordering) {
}
TEST_P(EndToEndTest, LargePostZeroRTTFailure) {
+ if (version_.UsesTls()) {
+ // TODO(b/152551499): Re-enable this test when TLS supports 0-RTT.
+ Initialize();
+ return;
+ }
// Send a request and then disconnect. This prepares the client to attempt
// a 0-RTT handshake for the next request.
ASSERT_TRUE(Initialize());
@@ -1368,6 +1294,11 @@ TEST_P(EndToEndTest, LargePostZeroRTTFailure) {
}
TEST_P(EndToEndTest, SynchronousRequestZeroRTTFailure) {
+ if (version_.UsesTls()) {
+ // TODO(b/152551499): Re-enable this test when TLS supports 0-RTT.
+ Initialize();
+ return;
+ }
// Send a request and then disconnect. This prepares the client to attempt
// a 0-RTT handshake for the next request.
ASSERT_TRUE(Initialize());
@@ -1429,6 +1360,10 @@ TEST_P(EndToEndTest, LargePostSynchronousRequest) {
EXPECT_FALSE(client_->client()->ReceivedInchoateReject());
client_->Disconnect();
+ if (version_.UsesTls()) {
+ // TODO(b/152551499): remove this when TLS supports 0-RTT.
+ return;
+ }
// The 0-RTT handshake should succeed.
client_->Connect();
@@ -1520,7 +1455,7 @@ TEST_P(EndToEndTest, LargePostSmallBandwidthLargeBuffer) {
VerifyCleanConnection(true);
}
-TEST_P(EndToEndTestWithTls, DoNotSetSendAlarmIfConnectionFlowControlBlocked) {
+TEST_P(EndToEndTest, DoNotSetSendAlarmIfConnectionFlowControlBlocked) {
// Regression test for b/14677858.
// Test that the resume write alarm is not set in QuicConnection::OnCanWrite
// if currently connection level flow control blocked. If set, this results in
@@ -1561,8 +1496,6 @@ TEST_P(EndToEndTestWithTls, DoNotSetSendAlarmIfConnectionFlowControlBlocked) {
EXPECT_FALSE(send_alarm->IsSet());
}
-// TODO(nharper): Needs to get turned back to EndToEndTestWithTls
-// when we figure out why the test doesn't work on chrome.
TEST_P(EndToEndTest, InvalidStream) {
ASSERT_TRUE(Initialize());
EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
@@ -1586,8 +1519,8 @@ TEST_P(EndToEndTest, InvalidStream) {
EXPECT_THAT(client_->connection_error(), IsError(QUIC_INVALID_STREAM_ID));
}
-// Test that if the server will close the connection if the client attempts
-// to send a request with overly large headers.
+// Test that the server resets the stream if the client sends a request
+// with overly large headers.
TEST_P(EndToEndTest, LargeHeaders) {
ASSERT_TRUE(Initialize());
EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
@@ -1604,16 +1537,17 @@ TEST_P(EndToEndTest, LargeHeaders) {
client_->SendCustomSynchronousRequest(headers, body);
- if (VersionUsesHttp3(client_->client()
- ->client_session()
- ->connection()
- ->transport_version())) {
- EXPECT_THAT(client_->connection_error(),
- IsError(QUIC_HEADERS_STREAM_DATA_DECOMPRESS_FAILURE));
+ if (VersionUsesHttp3(GetClientConnection()->transport_version())) {
+ // QuicSpdyStream::OnHeadersTooLarge() resets the stream with
+ // QUIC_HEADERS_TOO_LARGE. This is sent as H3_EXCESSIVE_LOAD, the closest
+ // HTTP/3 error code, and translated back to QUIC_STREAM_EXCESSIVE_LOAD on
+ // the receiving side.
+ EXPECT_THAT(client_->stream_error(),
+ IsStreamError(QUIC_STREAM_EXCESSIVE_LOAD));
} else {
EXPECT_THAT(client_->stream_error(), IsStreamError(QUIC_HEADERS_TOO_LARGE));
- EXPECT_THAT(client_->connection_error(), IsQuicNoError());
}
+ EXPECT_THAT(client_->connection_error(), IsQuicNoError());
}
TEST_P(EndToEndTest, EarlyResponseWithQuicStreamNoError) {
@@ -1638,7 +1572,7 @@ TEST_P(EndToEndTest, EarlyResponseWithQuicStreamNoError) {
}
// TODO(rch): this test seems to cause net_unittests timeouts :|
-TEST_P(EndToEndTestWithTls, QUIC_TEST_DISABLED_IN_CHROME(MultipleTermination)) {
+TEST_P(EndToEndTest, QUIC_TEST_DISABLED_IN_CHROME(MultipleTermination)) {
ASSERT_TRUE(Initialize());
// Set the offset so we won't frame. Otherwise when we pick up termination
@@ -1658,11 +1592,8 @@ TEST_P(EndToEndTestWithTls, QUIC_TEST_DISABLED_IN_CHROME(MultipleTermination)) {
EXPECT_QUIC_BUG(client_->SendData("eep", true), "Fin already buffered");
}
-// TODO(nharper): Needs to get turned back to EndToEndTestWithTls
-// when we figure out why the test doesn't work on chrome.
TEST_P(EndToEndTest, Timeout) {
- client_config_.SetIdleNetworkTimeout(QuicTime::Delta::FromMicroseconds(500),
- QuicTime::Delta::FromMicroseconds(500));
+ client_config_.SetIdleNetworkTimeout(QuicTime::Delta::FromMicroseconds(500));
// Note: we do NOT ASSERT_TRUE: we may time out during initial handshake:
// that's enough to validate timeout in this case.
Initialize();
@@ -1671,14 +1602,13 @@ TEST_P(EndToEndTest, Timeout) {
}
}
-TEST_P(EndToEndTestWithTls, MaxDynamicStreamsLimitRespected) {
+TEST_P(EndToEndTest, MaxDynamicStreamsLimitRespected) {
// Set a limit on maximum number of incoming dynamic streams.
// Make sure the limit is respected by the peer.
const uint32_t kServerMaxDynamicStreams = 1;
server_config_.SetMaxBidirectionalStreamsToSend(kServerMaxDynamicStreams);
ASSERT_TRUE(Initialize());
- if (VersionHasIetfQuicFrames(
- GetParam().negotiated_version.transport_version)) {
+ if (VersionHasIetfQuicFrames(version_.transport_version)) {
// 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
@@ -1746,7 +1676,7 @@ TEST_P(EndToEndTest, SetIndependentMaxDynamicStreamsLimits) {
client_session->connection()->transport_version())
? QuicSessionPeer::v99_streamid_manager(client_session)
->max_outgoing_unidirectional_streams() -
- client_session->num_expected_unidirectional_static_streams()
+ kHttp3StaticUnidirectionalStreamCount
: QuicSessionPeer::GetStreamIdManager(client_session)
->max_open_outgoing_streams();
EXPECT_EQ(kServerMaxDynamicStreams,
@@ -1767,7 +1697,7 @@ TEST_P(EndToEndTest, SetIndependentMaxDynamicStreamsLimits) {
server_session->connection()->transport_version())
? QuicSessionPeer::v99_streamid_manager(server_session)
->max_outgoing_unidirectional_streams() -
- server_session->num_expected_unidirectional_static_streams()
+ kHttp3StaticUnidirectionalStreamCount
: QuicSessionPeer::GetStreamIdManager(server_session)
->max_open_outgoing_streams();
EXPECT_EQ(kClientMaxDynamicStreams,
@@ -1921,8 +1851,7 @@ TEST_P(EndToEndTest, MinInitialRTT) {
}
TEST_P(EndToEndTest, 0ByteConnectionId) {
- if (VersionHasIetfInvariantHeader(
- GetParam().negotiated_version.transport_version)) {
+ if (VersionHasIetfInvariantHeader(version_.transport_version)) {
// SetBytesForConnectionIdToSend only applies to Google QUIC encoding.
ASSERT_TRUE(Initialize());
return;
@@ -1938,9 +1867,8 @@ TEST_P(EndToEndTest, 0ByteConnectionId) {
EXPECT_EQ(CONNECTION_ID_ABSENT, header->source_connection_id_included);
}
-TEST_P(EndToEndTestWithTls, 8ByteConnectionId) {
- if (VersionHasIetfInvariantHeader(
- GetParam().negotiated_version.transport_version)) {
+TEST_P(EndToEndTest, 8ByteConnectionId) {
+ if (VersionHasIetfInvariantHeader(version_.transport_version)) {
// SetBytesForConnectionIdToSend only applies to Google QUIC encoding.
ASSERT_TRUE(Initialize());
return;
@@ -1956,9 +1884,8 @@ TEST_P(EndToEndTestWithTls, 8ByteConnectionId) {
EXPECT_EQ(CONNECTION_ID_PRESENT, header->destination_connection_id_included);
}
-TEST_P(EndToEndTestWithTls, 15ByteConnectionId) {
- if (VersionHasIetfInvariantHeader(
- GetParam().negotiated_version.transport_version)) {
+TEST_P(EndToEndTest, 15ByteConnectionId) {
+ if (VersionHasIetfInvariantHeader(version_.transport_version)) {
// SetBytesForConnectionIdToSend only applies to Google QUIC encoding.
ASSERT_TRUE(Initialize());
return;
@@ -1975,7 +1902,7 @@ TEST_P(EndToEndTestWithTls, 15ByteConnectionId) {
EXPECT_EQ(CONNECTION_ID_PRESENT, header->destination_connection_id_included);
}
-TEST_P(EndToEndTestWithTls, ResetConnection) {
+TEST_P(EndToEndTest, ResetConnection) {
ASSERT_TRUE(Initialize());
EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
@@ -1986,8 +1913,6 @@ TEST_P(EndToEndTestWithTls, ResetConnection) {
EXPECT_EQ("200", client_->response_headers()->find(":status")->second);
}
-// TODO(nharper): Needs to get turned back to EndToEndTestWithTls
-// when we figure out why the test doesn't work on chrome.
TEST_P(EndToEndTest, MaxStreamsUberTest) {
// Connect with lower fake packet loss than we'd like to test. Until
// b/10126687 is fixed, losing handshake packets is pretty brutal.
@@ -2011,7 +1936,7 @@ TEST_P(EndToEndTest, MaxStreamsUberTest) {
}
}
-TEST_P(EndToEndTestWithTls, StreamCancelErrorTest) {
+TEST_P(EndToEndTest, StreamCancelErrorTest) {
ASSERT_TRUE(Initialize());
std::string small_body(256, 'a');
@@ -2027,7 +1952,11 @@ TEST_P(EndToEndTestWithTls, StreamCancelErrorTest) {
// Transmit the cancel, and ensure the connection is torn down properly.
SetPacketLossPercentage(0);
QuicStreamId stream_id = GetNthClientInitiatedBidirectionalId(0);
- session->SendRstStream(stream_id, QUIC_STREAM_CANCELLED, 0);
+ if (session->break_close_loop()) {
+ session->ResetStream(stream_id, QUIC_STREAM_CANCELLED, 0);
+ } else {
+ session->SendRstStream(stream_id, QUIC_STREAM_CANCELLED, 0);
+ }
// WaitForEvents waits 50ms and returns true if there are outstanding
// requests.
@@ -2131,6 +2060,11 @@ TEST_P(EndToEndTest, NegotiatedInitialCongestionWindow) {
}
TEST_P(EndToEndTest, DifferentFlowControlWindows) {
+ if (version_.UsesTls()) {
+ // TODO(b/155316241): Enable this test for TLS.
+ Initialize();
+ return;
+ }
// Client and server can set different initial flow control receive windows.
// These are sent in CHLO/SHLO. Tests that these values are exchanged properly
// in the crypto handshake.
@@ -2185,6 +2119,11 @@ TEST_P(EndToEndTest, DifferentFlowControlWindows) {
// Test negotiation of IFWA connection option.
TEST_P(EndToEndTest, NegotiatedServerInitialFlowControlWindow) {
+ if (version_.UsesTls()) {
+ // TODO(b/155316241): Enable this test for TLS.
+ Initialize();
+ return;
+ }
const uint32_t kClientStreamIFCW = 123456;
const uint32_t kClientSessionIFCW = 234567;
set_client_initial_stream_flow_control_receive_window(kClientStreamIFCW);
@@ -2395,7 +2334,7 @@ TEST_P(EndToEndTest, FlowControlsSynced) {
server_thread_->Resume();
}
-TEST_P(EndToEndTestWithTls, RequestWithNoBodyWillNeverSendStreamFrameWithFIN) {
+TEST_P(EndToEndTest, RequestWithNoBodyWillNeverSendStreamFrameWithFIN) {
// A stream created on receipt of a simple request with no body will never get
// a stream frame with a FIN. Verify that we don't keep track of the stream in
// the locally closed streams map: it will never be removed if so.
@@ -2414,8 +2353,8 @@ TEST_P(EndToEndTestWithTls, RequestWithNoBodyWillNeverSendStreamFrameWithFIN) {
server_thread_->Resume();
}
-// A TestAckListener verifies that its OnAckNotification method has been
-// called exactly once on destruction.
+// A TestAckListener verifies that exactly |bytes_to_ack| bytes are acked during
+// its lifetime.
class TestAckListener : public QuicAckListenerInterface {
public:
explicit TestAckListener(int bytes_to_ack) : bytes_to_ack_(bytes_to_ack) {}
@@ -2449,12 +2388,14 @@ class TestResponseListener : public QuicSpdyClientBase::ResponseListener {
}
};
-TEST_P(EndToEndTest, AckNotifierWithPacketLossAndBlockedSocket) {
+// TODO(dschinazi) Fix this test's flakiness in Chrome.
+TEST_P(
+ EndToEndTest,
+ QUIC_TEST_DISABLED_IN_CHROME(AckNotifierWithPacketLossAndBlockedSocket)) {
// Verify that even in the presence of packet loss and occasionally blocked
// socket, an AckNotifierDelegate will get informed that the data it is
// interested in has been ACKed. This tests end-to-end ACK notification, and
// demonstrates that retransmissions do not break this functionality.
-
SetPacketLossPercentage(5);
ASSERT_TRUE(Initialize());
@@ -2485,6 +2426,12 @@ TEST_P(EndToEndTest, AckNotifierWithPacketLossAndBlockedSocket) {
QpackEncoder qpack_encoder(&decoder_stream_error_delegate);
qpack_encoder.set_qpack_stream_sender_delegate(
&encoder_stream_sender_delegate);
+
+ qpack_encoder.SetMaximumDynamicTableCapacity(
+ kDefaultQpackMaxDynamicTableCapacity);
+ qpack_encoder.SetDynamicTableCapacity(kDefaultQpackMaxDynamicTableCapacity);
+ qpack_encoder.SetMaximumBlockedStreams(kDefaultMaximumBlockedStreams);
+
std::string encoded_headers =
qpack_encoder.EncodeHeaderList(/* stream_id = */ 0, headers, nullptr);
header_size = encoded_headers.size();
@@ -2516,7 +2463,7 @@ TEST_P(EndToEndTest, AckNotifierWithPacketLossAndBlockedSocket) {
}
// Send a public reset from the server.
-TEST_P(EndToEndTestWithTls, ServerSendPublicReset) {
+TEST_P(EndToEndTest, ServerSendPublicReset) {
ASSERT_TRUE(Initialize());
EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
@@ -2554,7 +2501,7 @@ TEST_P(EndToEndTestWithTls, ServerSendPublicReset) {
// Send a public reset from the server for a different connection ID.
// It should be ignored.
-TEST_P(EndToEndTestWithTls, ServerSendPublicResetWithDifferentConnectionId) {
+TEST_P(EndToEndTest, ServerSendPublicResetWithDifferentConnectionId) {
ASSERT_TRUE(Initialize());
EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
@@ -2607,7 +2554,7 @@ TEST_P(EndToEndTestWithTls, ServerSendPublicResetWithDifferentConnectionId) {
// Send a public reset from the client for a different connection ID.
// It should be ignored.
-TEST_P(EndToEndTestWithTls, ClientSendPublicResetWithDifferentConnectionId) {
+TEST_P(EndToEndTest, ClientSendPublicResetWithDifferentConnectionId) {
ASSERT_TRUE(Initialize());
// Send the public reset.
@@ -2631,8 +2578,7 @@ TEST_P(EndToEndTestWithTls, ClientSendPublicResetWithDifferentConnectionId) {
// Send a version negotiation packet from the server for a different
// connection ID. It should be ignored.
-TEST_P(EndToEndTestWithTls,
- ServerSendVersionNegotiationWithDifferentConnectionId) {
+TEST_P(EndToEndTest, ServerSendVersionNegotiationWithDifferentConnectionId) {
ASSERT_TRUE(Initialize());
EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
@@ -2668,7 +2614,7 @@ TEST_P(EndToEndTestWithTls,
// A bad header shouldn't tear down the connection, because the receiver can't
// tell the connection ID.
-TEST_P(EndToEndTestWithTls, BadPacketHeaderTruncated) {
+TEST_P(EndToEndTest, BadPacketHeaderTruncated) {
ASSERT_TRUE(Initialize());
// Start the connection.
@@ -2699,7 +2645,7 @@ TEST_P(EndToEndTestWithTls, BadPacketHeaderTruncated) {
// A bad header shouldn't tear down the connection, because the receiver can't
// tell the connection ID.
-TEST_P(EndToEndTestWithTls, BadPacketHeaderFlags) {
+TEST_P(EndToEndTest, BadPacketHeaderFlags) {
ASSERT_TRUE(Initialize());
// Start the connection.
@@ -2749,7 +2695,7 @@ TEST_P(EndToEndTestWithTls, BadPacketHeaderFlags) {
// Send a packet from the client with bad encrypted data. The server should not
// tear down the connection.
-TEST_P(EndToEndTestWithTls, BadEncryptedData) {
+TEST_P(EndToEndTest, BadEncryptedData) {
ASSERT_TRUE(Initialize());
// Start the connection.
@@ -2785,7 +2731,7 @@ TEST_P(EndToEndTestWithTls, BadEncryptedData) {
EXPECT_EQ("200", client_->response_headers()->find(":status")->second);
}
-TEST_P(EndToEndTestWithTls, CanceledStreamDoesNotBecomeZombie) {
+TEST_P(EndToEndTest, CanceledStreamDoesNotBecomeZombie) {
ASSERT_TRUE(Initialize());
EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
// Lose the request.
@@ -3033,7 +2979,7 @@ TEST_P(EndToEndTest, EarlyResponseFinRecording) {
server_thread_->Resume();
}
-TEST_P(EndToEndTestWithTls, Trailers) {
+TEST_P(EndToEndTest, Trailers) {
// Test sending and receiving HTTP/2 Trailers (trailing HEADERS frames).
ASSERT_TRUE(Initialize());
EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
@@ -3117,7 +3063,7 @@ class EndToEndTestServerPush : public EndToEndTest {
// Run all server push end to end tests with all supported versions.
INSTANTIATE_TEST_SUITE_P(EndToEndTestsServerPush,
EndToEndTestServerPush,
- ::testing::ValuesIn(GetTestParams(false)),
+ ::testing::ValuesIn(GetTestParams()),
::testing::PrintToStringParamName());
TEST_P(EndToEndTestServerPush, ServerPush) {
@@ -3177,6 +3123,11 @@ TEST_P(EndToEndTestServerPush, ServerPush) {
}
TEST_P(EndToEndTestServerPush, ServerPushUnderLimit) {
+ if (version_.UsesTls()) {
+ // TODO(b/155316241): Enable this test for TLS.
+ Initialize();
+ return;
+ }
// 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.
@@ -3226,6 +3177,11 @@ TEST_P(EndToEndTestServerPush, ServerPushUnderLimit) {
}
TEST_P(EndToEndTestServerPush, ServerPushOverLimitNonBlocking) {
+ if (version_.UsesTls()) {
+ // TODO(b/155316241): Enable this test for TLS.
+ Initialize();
+ return;
+ }
// Tests that when streams are not blocked by flow control or congestion
// control, pushing even more resources than max number of open outgoing
// streams should still work because all response streams get closed
@@ -3284,6 +3240,11 @@ TEST_P(EndToEndTestServerPush, ServerPushOverLimitNonBlocking) {
}
TEST_P(EndToEndTestServerPush, ServerPushOverLimitWithBlocking) {
+ if (version_.UsesTls()) {
+ // TODO(b/155316241): Enable this test for TLS.
+ Initialize();
+ return;
+ }
// Tests that when server tries to send more large resources(large enough to
// be blocked by flow control window or congestion control window) than max
// open outgoing streams , server can open upto max number of outgoing
@@ -3495,16 +3456,17 @@ TEST_P(EndToEndTest, WayTooLongRequestHeaders) {
headers[":path"] = "/foo";
headers[":scheme"] = "https";
headers[":authority"] = server_hostname_;
- headers["key"] = std::string(64 * 1024, 'a');
+ headers["key"] = std::string(64 * 1024 * 1024, 'a');
client_->SendMessage(headers, "");
client_->WaitForResponse();
-
- QuicErrorCode expected_error =
- GetQuicReloadableFlag(spdy_enable_granular_decompress_errors)
- ? QUIC_HPACK_INDEX_VARINT_ERROR
- : QUIC_HEADERS_STREAM_DATA_DECOMPRESS_FAILURE;
- EXPECT_THAT(client_->connection_error(), IsError(expected_error));
+ if (VersionUsesHttp3(version_.transport_version)) {
+ EXPECT_THAT(client_->connection_error(),
+ IsError(QUIC_QPACK_DECOMPRESSION_FAILED));
+ } else {
+ EXPECT_THAT(client_->connection_error(),
+ IsError(QUIC_HPACK_INDEX_VARINT_ERROR));
+ }
}
class WindowUpdateObserver : public QuicConnectionDebugVisitor {
@@ -3550,7 +3512,7 @@ TEST_P(EndToEndTest, WindowUpdateInAck) {
EXPECT_EQ(0u, observer.num_ping_frames());
}
-TEST_P(EndToEndTestWithTls, SendStatelessResetTokenInShlo) {
+TEST_P(EndToEndTest, SendStatelessResetTokenInShlo) {
ASSERT_TRUE(Initialize());
EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
QuicConfig* config = client_->client()->session()->config();
@@ -3564,6 +3526,10 @@ TEST_P(EndToEndTestWithTls, SendStatelessResetTokenInShlo) {
// Regression test for b/116200989.
TEST_P(EndToEndTest,
SendStatelessResetIfServerConnectionClosedLocallyDuringHandshake) {
+ if (!GetQuicReloadableFlag(quic_notify_handshaker_on_connection_close)) {
+ ASSERT_TRUE(Initialize());
+ return;
+ }
connect_to_server_on_initialize_ = false;
ASSERT_TRUE(Initialize());
@@ -3668,6 +3634,16 @@ TEST_P(EndToEndTest, PreSharedKey) {
QuicTime::Delta::FromSeconds(5));
pre_shared_key_client_ = "foobar";
pre_shared_key_server_ = "foobar";
+
+ if (version_.UsesTls()) {
+ // TODO(b/154162689) add PSK support to QUIC+TLS.
+ bool ok;
+ EXPECT_QUIC_BUG(ok = Initialize(),
+ "QUIC client pre-shared keys not yet supported with TLS");
+ EXPECT_FALSE(ok);
+ return;
+ }
+
ASSERT_TRUE(Initialize());
ASSERT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
@@ -3682,6 +3658,16 @@ TEST_P(EndToEndTest, QUIC_TEST_DISABLED_IN_CHROME(PreSharedKeyMismatch)) {
QuicTime::Delta::FromSeconds(1));
pre_shared_key_client_ = "foo";
pre_shared_key_server_ = "bar";
+
+ if (version_.UsesTls()) {
+ // TODO(b/154162689) add PSK support to QUIC+TLS.
+ bool ok;
+ EXPECT_QUIC_BUG(ok = Initialize(),
+ "QUIC client pre-shared keys not yet supported with TLS");
+ EXPECT_FALSE(ok);
+ return;
+ }
+
// One of two things happens when Initialize() returns:
// 1. Crypto handshake has completed, and it is unsuccessful. Initialize()
// returns false.
@@ -3700,6 +3686,16 @@ TEST_P(EndToEndTest, QUIC_TEST_DISABLED_IN_CHROME(PreSharedKeyNoClient)) {
client_config_.set_max_idle_time_before_crypto_handshake(
QuicTime::Delta::FromSeconds(1));
pre_shared_key_server_ = "foobar";
+
+ if (version_.UsesTls()) {
+ // TODO(b/154162689) add PSK support to QUIC+TLS.
+ bool ok;
+ EXPECT_QUIC_BUG(ok = Initialize(),
+ "QUIC server pre-shared keys not yet supported with TLS");
+ EXPECT_FALSE(ok);
+ return;
+ }
+
ASSERT_FALSE(Initialize() &&
client_->client()->WaitForCryptoHandshakeConfirmed());
EXPECT_THAT(client_->connection_error(), IsError(QUIC_HANDSHAKE_TIMEOUT));
@@ -3712,6 +3708,16 @@ TEST_P(EndToEndTest, QUIC_TEST_DISABLED_IN_CHROME(PreSharedKeyNoServer)) {
client_config_.set_max_idle_time_before_crypto_handshake(
QuicTime::Delta::FromSeconds(1));
pre_shared_key_client_ = "foobar";
+
+ if (version_.UsesTls()) {
+ // TODO(b/154162689) add PSK support to QUIC+TLS.
+ bool ok;
+ EXPECT_QUIC_BUG(ok = Initialize(),
+ "QUIC client pre-shared keys not yet supported with TLS");
+ EXPECT_FALSE(ok);
+ return;
+ }
+
ASSERT_FALSE(Initialize() &&
client_->client()->WaitForCryptoHandshakeConfirmed());
EXPECT_THAT(client_->connection_error(), IsError(QUIC_HANDSHAKE_TIMEOUT));
@@ -3770,13 +3776,14 @@ TEST_P(EndToEndTest, ResetStreamOnTtlExpires) {
}
TEST_P(EndToEndTest, SendMessages) {
+ if (!VersionSupportsMessageFrames(version_.transport_version)) {
+ Initialize();
+ return;
+ }
ASSERT_TRUE(Initialize());
EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
QuicSession* client_session = GetClientSession();
QuicConnection* client_connection = client_session->connection();
- if (!VersionSupportsMessageFrames(client_connection->transport_version())) {
- return;
- }
SetPacketLossPercentage(30);
ASSERT_GT(kMaxOutgoingPacketSize,
@@ -3806,7 +3813,7 @@ TEST_P(EndToEndTest, SendMessages) {
for (size_t i = 2; i <= kTestMaxNumberOfMessages; ++i) {
size_t message_length =
random->RandUint64() %
- client_session->GetCurrentLargestMessagePayload() +
+ client_session->GetGuaranteedLargestMessagePayload() +
1;
MessageResult result = client_session->SendMessage(MakeSpan(
client_session->connection()
@@ -3856,11 +3863,16 @@ class EndToEndPacketReorderingTest : public EndToEndTest {
INSTANTIATE_TEST_SUITE_P(EndToEndPacketReorderingTests,
EndToEndPacketReorderingTest,
- ::testing::ValuesIn(GetTestParams(false)),
+ ::testing::ValuesIn(GetTestParams()),
::testing::PrintToStringParamName());
TEST_P(EndToEndPacketReorderingTest, ReorderedConnectivityProbing) {
ASSERT_TRUE(Initialize());
+ if (version_.HasIetfQuicFrames()) {
+ // TODO(b/143909619): Reenable this test when supporting IETF connection
+ // migration.
+ return;
+ }
// Finish one request to make sure handshake established.
EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
@@ -3904,6 +3916,11 @@ TEST_P(EndToEndPacketReorderingTest, ReorderedConnectivityProbing) {
}
TEST_P(EndToEndPacketReorderingTest, Buffer0RttRequest) {
+ if (version_.UsesTls()) {
+ // TODO(b/152551499): Re-enable this test when TLS supports 0-RTT.
+ Initialize();
+ return;
+ }
ASSERT_TRUE(Initialize());
// Finish one request to make sure handshake established.
client_->SendSynchronousRequest("/foo");
@@ -3930,22 +3947,59 @@ TEST_P(EndToEndPacketReorderingTest, Buffer0RttRequest) {
client_->WaitForResponse();
EXPECT_EQ(kBarResponseBody, client_->response_body());
QuicConnectionStats client_stats = GetClientConnection()->GetStats();
- EXPECT_EQ(0u, client_stats.packets_lost);
+ if (GetQuicReloadableFlag(quic_advance_ack_timeout_update)) {
+ // Client sends CHLO in packet 1 and retransmitted in packet 2. Because of
+ // the delay, server processes packet 2 and later drops packet 1. ACK is
+ // bundled with SHLO, such that 1 can be detected loss by time threshold.
+ EXPECT_LE(0u, client_stats.packets_lost);
+ } else {
+ EXPECT_EQ(0u, client_stats.packets_lost);
+ }
EXPECT_TRUE(client_->client()->EarlyDataAccepted());
}
+// This observer is used to check whether stream write side is closed when
+// receiving STOP_SENDING (which ends up as noop).
+class StopSendingObserver : public QuicConnectionDebugVisitor {
+ public:
+ explicit StopSendingObserver(QuicTestClient* client)
+ : num_stop_sending_frames_(0),
+ client_(client),
+ stream_write_side_closed_before_receiving_stop_sending_(false) {}
+
+ void OnStopSendingFrame(const QuicStopSendingFrame& /*frame*/) override {
+ ++num_stop_sending_frames_;
+ stream_write_side_closed_before_receiving_stop_sending_ =
+ static_cast<QuicSimpleClientStream*>(client_->latest_created_stream())
+ ->write_side_closed();
+ }
+
+ size_t num_stop_sending_frames() const { return num_stop_sending_frames_; }
+
+ bool stream_write_side_closed_before_receiving_stop_sending() const {
+ return stream_write_side_closed_before_receiving_stop_sending_;
+ }
+
+ private:
+ size_t num_stop_sending_frames_;
+ QuicTestClient* client_;
+ bool stream_write_side_closed_before_receiving_stop_sending_;
+};
+
// Test that STOP_SENDING makes it to the peer. Create a stream and send a
// STOP_SENDING. The receiver should get a call to QuicStream::OnStopSending.
TEST_P(EndToEndTest, SimpleStopSendingTest) {
const uint16_t kStopSendingTestCode = 123;
ASSERT_TRUE(Initialize());
- if (!VersionHasIetfQuicFrames(negotiated_version_.transport_version)) {
+ if (!VersionHasIetfQuicFrames(version_.transport_version)) {
return;
}
QuicSession* client_session = GetClientSession();
ASSERT_NE(nullptr, client_session);
+ StopSendingObserver observer(client_.get());
QuicConnection* client_connection = client_session->connection();
ASSERT_NE(nullptr, client_connection);
+ client_connection->set_debug_visitor(&observer);
std::string response_body(1305, 'a');
SpdyHeaderBlock response_headers;
@@ -3960,16 +4014,9 @@ TEST_P(EndToEndTest, SimpleStopSendingTest) {
client_->WaitForDelayedAcks();
QuicSession* session = GetClientSession();
- const QuicPacketCount packets_sent_before =
- session->connection()->GetStats().packets_sent;
QuicStreamId stream_id = session->next_outgoing_bidirectional_stream_id();
client_->SendRequest("/test_url");
-
- // Expect exactly one packet is sent from the block above.
- ASSERT_EQ(packets_sent_before + 1,
- session->connection()->GetStats().packets_sent);
-
// Wait for the connection to become idle.
client_->WaitForDelayedAcks();
@@ -3980,8 +4027,12 @@ TEST_P(EndToEndTest, SimpleStopSendingTest) {
// Ensure the stream has been write closed upon receiving STOP_SENDING.
EXPECT_EQ(stream_id, client_stream->id());
EXPECT_TRUE(client_stream->write_side_closed());
- EXPECT_EQ(kStopSendingTestCode,
- static_cast<uint16_t>(client_stream->stream_error()));
+ client_->WaitUntil(
+ -1, [&observer]() { return observer.num_stop_sending_frames() > 0; });
+ if (!observer.stream_write_side_closed_before_receiving_stop_sending()) {
+ EXPECT_EQ(kStopSendingTestCode,
+ static_cast<uint16_t>(client_stream->stream_error()));
+ }
}
TEST_P(EndToEndTest, SimpleStopSendingRstStreamTest) {
@@ -4036,15 +4087,18 @@ class BadShloPacketWriter : public QuicPacketWriterWrapper {
};
TEST_P(EndToEndTest, ZeroRttProtectedConnectionClose) {
+ if (version_.UsesTls() ||
+ !VersionHasIetfInvariantHeader(version_.transport_version)) {
+ // TODO(b/152551499): Re-enable this test when TLS supports 0-RTT.
+ // Only runs for IETF QUIC header.
+ Initialize();
+ return;
+ }
// This test ensures ZERO_RTT_PROTECTED connection close could close a client
// which has switched to forward secure.
connect_to_server_on_initialize_ =
- !VersionHasIetfInvariantHeader(negotiated_version_.transport_version);
+ !VersionHasIetfInvariantHeader(version_.transport_version);
ASSERT_TRUE(Initialize());
- if (!VersionHasIetfInvariantHeader(negotiated_version_.transport_version)) {
- // Only runs for IETF QUIC header.
- return;
- }
server_thread_->Pause();
QuicDispatcher* dispatcher =
QuicServerPeer::GetDispatcher(server_thread_->server());
@@ -4100,9 +4154,9 @@ TEST_P(EndToEndTest, ForwardSecureConnectionClose) {
// This test ensures ZERO_RTT_PROTECTED connection close is sent to a client
// which has ZERO_RTT_PROTECTED encryption level.
connect_to_server_on_initialize_ =
- !VersionHasIetfInvariantHeader(negotiated_version_.transport_version);
+ !VersionHasIetfInvariantHeader(version_.transport_version);
ASSERT_TRUE(Initialize());
- if (!VersionHasIetfInvariantHeader(negotiated_version_.transport_version)) {
+ if (!VersionHasIetfInvariantHeader(version_.transport_version)) {
// Only runs for IETF QUIC header.
return;
}
@@ -4130,7 +4184,7 @@ TEST_P(EndToEndTest, ForwardSecureConnectionClose) {
TEST_P(EndToEndTest, TooBigStreamIdClosesConnection) {
// Has to be before version test, see EndToEndTest::TearDown()
ASSERT_TRUE(Initialize());
- if (!VersionHasIetfQuicFrames(negotiated_version_.transport_version)) {
+ if (!VersionHasIetfQuicFrames(version_.transport_version)) {
// Only runs for IETF QUIC.
return;
}
@@ -4162,12 +4216,15 @@ TEST_P(EndToEndTest, TooBigStreamIdClosesConnection) {
}
TEST_P(EndToEndTest, TestMaxPushId) {
- // Has to be before version test, see EndToEndTest::TearDown()
- ASSERT_TRUE(Initialize());
- if (!VersionHasIetfQuicFrames(negotiated_version_.transport_version)) {
+ if (version_.UsesTls() ||
+ !VersionHasIetfQuicFrames(version_.transport_version)) {
+ // TODO(b/155316241): Enable this test for TLS.
// Only runs for IETF QUIC.
+ Initialize();
return;
}
+ // Has to be before version test, see EndToEndTest::TearDown()
+ ASSERT_TRUE(Initialize());
EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
static_cast<QuicSpdySession*>(client_->client()->session())
@@ -4182,12 +4239,8 @@ TEST_P(EndToEndTest, TestMaxPushId) {
->CanCreatePushStreamWithId(kMaxQuicStreamId));
}
-TEST_P(EndToEndTest, CustomTransportParameters) {
- if (GetParam().negotiated_version.handshake_protocol != PROTOCOL_TLS1_3) {
- Initialize();
- return;
- }
-
+TEST_P(EndToEndTest, DISABLED_CustomTransportParameters) {
+ // TODO(b/155316241): Enable this test.
constexpr auto kCustomParameter =
static_cast<TransportParameters::TransportParameterId>(0xff34);
client_config_.custom_transport_parameters_to_send()[kCustomParameter] =
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/http_constants.h b/chromium/net/third_party/quiche/src/quic/core/http/http_constants.h
index fbf30696de7..17afe1bea19 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/http_constants.h
+++ b/chromium/net/third_party/quiche/src/quic/core/http/http_constants.h
@@ -20,6 +20,9 @@ const uint64_t kServerPushStream = 0x01;
const uint64_t kQpackEncoderStream = 0x02;
const uint64_t kQpackDecoderStream = 0x03;
+// This includes control stream, QPACK encoder stream, and QPACK decoder stream.
+const QuicStreamCount kHttp3StaticUnidirectionalStreamCount = 3;
+
// HTTP/3 and QPACK settings identifiers.
// https://quicwg.org/base-drafts/draft-ietf-quic-http.html#settings-parameters
// https://quicwg.org/base-drafts/draft-ietf-quic-qpack.html#configuration
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/http_decoder.cc b/chromium/net/third_party/quiche/src/quic/core/http/http_decoder.cc
index 87f9919d296..d6c97ee7add 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/http_decoder.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/http_decoder.cc
@@ -11,6 +11,7 @@
#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_fallthrough.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
namespace quic {
@@ -34,6 +35,50 @@ HttpDecoder::HttpDecoder(Visitor* visitor)
HttpDecoder::~HttpDecoder() {}
+// static
+bool HttpDecoder::DecodeSettings(const char* data,
+ QuicByteCount len,
+ SettingsFrame* frame) {
+ QuicDataReader reader(data, len);
+ uint64_t frame_type;
+ if (!reader.ReadVarInt62(&frame_type)) {
+ QUIC_DLOG(ERROR) << "Unable to read frame type.";
+ return false;
+ }
+
+ if (frame_type != static_cast<uint64_t>(HttpFrameType::SETTINGS)) {
+ QUIC_DLOG(ERROR) << "Invalid frame type " << frame_type;
+ return false;
+ }
+
+ quiche::QuicheStringPiece frame_contents;
+ if (!reader.ReadStringPieceVarInt62(&frame_contents)) {
+ QUIC_DLOG(ERROR) << "Failed to read SETTINGS frame contents";
+ return false;
+ }
+
+ QuicDataReader frame_reader(frame_contents);
+
+ while (!frame_reader.IsDoneReading()) {
+ uint64_t id;
+ if (!frame_reader.ReadVarInt62(&id)) {
+ QUIC_DLOG(ERROR) << "Unable to read setting identifier.";
+ return false;
+ }
+ uint64_t content;
+ if (!frame_reader.ReadVarInt62(&content)) {
+ QUIC_DLOG(ERROR) << "Unable to read setting value.";
+ return false;
+ }
+ auto result = frame->values.insert({id, content});
+ if (!result.second) {
+ QUIC_DLOG(ERROR) << "Duplicate setting identifier.";
+ return false;
+ }
+ }
+ return true;
+}
+
QuicByteCount HttpDecoder::ProcessInput(const char* data, QuicByteCount len) {
DCHECK_EQ(QUIC_NO_ERROR, error_);
DCHECK_NE(STATE_ERROR, state_);
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/http_decoder.h b/chromium/net/third_party/quiche/src/quic/core/http/http_decoder.h
index 3650bef572e..1551aa7d275 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/http_decoder.h
+++ b/chromium/net/third_party/quiche/src/quic/core/http/http_decoder.h
@@ -131,6 +131,13 @@ class QUIC_EXPORT_PRIVATE HttpDecoder {
// occurred.
QuicByteCount ProcessInput(const char* data, QuicByteCount len);
+ // Decode settings frame from |data|.
+ // Upon successful decoding, |frame| will be populated, and returns true.
+ // This method is not used for regular processing of incoming data.
+ static bool DecodeSettings(const char* data,
+ QuicByteCount len,
+ SettingsFrame* frame);
+
// Returns an error code other than QUIC_NO_ERROR if and only if
// Visitor::OnError() has been called.
QuicErrorCode error() const { return error_; }
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 2e8885c9dd7..86a1b6932ec 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
@@ -39,42 +39,79 @@ class MockVisitor : public HttpDecoder::Visitor {
~MockVisitor() override = default;
// Called if an error is detected.
- MOCK_METHOD1(OnError, void(HttpDecoder* decoder));
-
- MOCK_METHOD1(OnCancelPushFrame, bool(const CancelPushFrame& frame));
- MOCK_METHOD1(OnMaxPushIdFrame, bool(const MaxPushIdFrame& frame));
- MOCK_METHOD1(OnGoAwayFrame, bool(const GoAwayFrame& frame));
- MOCK_METHOD1(OnSettingsFrameStart, bool(QuicByteCount header_length));
- MOCK_METHOD1(OnSettingsFrame, bool(const SettingsFrame& frame));
-
- MOCK_METHOD2(OnDataFrameStart,
- bool(QuicByteCount header_length, QuicByteCount payload_length));
- MOCK_METHOD1(OnDataFramePayload, bool(quiche::QuicheStringPiece payload));
- MOCK_METHOD0(OnDataFrameEnd, bool());
-
- MOCK_METHOD2(OnHeadersFrameStart,
- bool(QuicByteCount header_length, QuicByteCount payload_length));
- MOCK_METHOD1(OnHeadersFramePayload, bool(quiche::QuicheStringPiece payload));
- MOCK_METHOD0(OnHeadersFrameEnd, bool());
-
- MOCK_METHOD1(OnPushPromiseFrameStart, bool(QuicByteCount header_length));
- MOCK_METHOD3(OnPushPromiseFramePushId,
- bool(PushId push_id,
- QuicByteCount push_id_length,
- QuicByteCount header_block_length));
- MOCK_METHOD1(OnPushPromiseFramePayload,
- bool(quiche::QuicheStringPiece payload));
- MOCK_METHOD0(OnPushPromiseFrameEnd, bool());
-
- MOCK_METHOD1(OnPriorityUpdateFrameStart, bool(QuicByteCount header_length));
- MOCK_METHOD1(OnPriorityUpdateFrame, bool(const PriorityUpdateFrame& frame));
-
- MOCK_METHOD3(OnUnknownFrameStart,
- bool(uint64_t frame_type,
- QuicByteCount header_length,
- QuicByteCount payload_length));
- MOCK_METHOD1(OnUnknownFramePayload, bool(quiche::QuicheStringPiece payload));
- MOCK_METHOD0(OnUnknownFrameEnd, bool());
+ MOCK_METHOD(void, OnError, (HttpDecoder*), (override));
+
+ MOCK_METHOD(bool,
+ OnCancelPushFrame,
+ (const CancelPushFrame& frame),
+ (override));
+ MOCK_METHOD(bool,
+ OnMaxPushIdFrame,
+ (const MaxPushIdFrame& frame),
+ (override));
+ MOCK_METHOD(bool, OnGoAwayFrame, (const GoAwayFrame& frame), (override));
+ MOCK_METHOD(bool,
+ OnSettingsFrameStart,
+ (QuicByteCount header_length),
+ (override));
+ MOCK_METHOD(bool, OnSettingsFrame, (const SettingsFrame& frame), (override));
+
+ MOCK_METHOD(bool,
+ OnDataFrameStart,
+ (QuicByteCount header_length, QuicByteCount payload_length),
+ (override));
+ MOCK_METHOD(bool,
+ OnDataFramePayload,
+ (quiche::QuicheStringPiece payload),
+ (override));
+ MOCK_METHOD(bool, OnDataFrameEnd, (), (override));
+
+ MOCK_METHOD(bool,
+ OnHeadersFrameStart,
+ (QuicByteCount header_length, QuicByteCount payload_length),
+ (override));
+ MOCK_METHOD(bool,
+ OnHeadersFramePayload,
+ (quiche::QuicheStringPiece payload),
+ (override));
+ MOCK_METHOD(bool, OnHeadersFrameEnd, (), (override));
+
+ MOCK_METHOD(bool,
+ OnPushPromiseFrameStart,
+ (QuicByteCount header_length),
+ (override));
+ MOCK_METHOD(bool,
+ OnPushPromiseFramePushId,
+ (PushId push_id,
+ QuicByteCount push_id_length,
+ QuicByteCount header_block_length),
+ (override));
+ MOCK_METHOD(bool,
+ OnPushPromiseFramePayload,
+ (quiche::QuicheStringPiece payload),
+ (override));
+ MOCK_METHOD(bool, OnPushPromiseFrameEnd, (), (override));
+
+ MOCK_METHOD(bool,
+ OnPriorityUpdateFrameStart,
+ (QuicByteCount header_length),
+ (override));
+ MOCK_METHOD(bool,
+ OnPriorityUpdateFrame,
+ (const PriorityUpdateFrame& frame),
+ (override));
+
+ MOCK_METHOD(bool,
+ OnUnknownFrameStart,
+ (uint64_t frame_type,
+ QuicByteCount header_length,
+ QuicByteCount payload_length),
+ (override));
+ MOCK_METHOD(bool,
+ OnUnknownFramePayload,
+ (quiche::QuicheStringPiece payload),
+ (override));
+ MOCK_METHOD(bool, OnUnknownFrameEnd, (), (override));
};
class HttpDecoderTest : public QuicTest {
@@ -1035,6 +1072,43 @@ TEST_F(HttpDecoderTest, CorruptPriorityUpdateFrame) {
}
}
+TEST_F(HttpDecoderTest, DecodeSettings) {
+ std::string input = quiche::QuicheTextUtils::HexDecode(
+ "04" // type (SETTINGS)
+ "07" // length
+ "01" // identifier (SETTINGS_QPACK_MAX_TABLE_CAPACITY)
+ "02" // content
+ "06" // identifier (SETTINGS_MAX_HEADER_LIST_SIZE)
+ "05" // content
+ "4100" // identifier, encoded on 2 bytes (0x40), value is 256 (0x100)
+ "04"); // content
+
+ SettingsFrame frame;
+ frame.values[1] = 2;
+ frame.values[6] = 5;
+ frame.values[256] = 4;
+
+ SettingsFrame out;
+ EXPECT_TRUE(HttpDecoder::DecodeSettings(input.data(), input.size(), &out));
+ EXPECT_EQ(frame, out);
+
+ // non-settings frame.
+ input = quiche::QuicheTextUtils::HexDecode(
+ "0D" // type (MAX_PUSH_ID)
+ "01" // length
+ "01"); // Push Id
+
+ EXPECT_FALSE(HttpDecoder::DecodeSettings(input.data(), input.size(), &out));
+
+ // Corrupt SETTINGS.
+ input = quiche::QuicheTextUtils::HexDecode(
+ "04" // type (SETTINGS)
+ "01" // length
+ "42"); // First byte of setting identifier, indicating a 2-byte varint62.
+
+ EXPECT_FALSE(HttpDecoder::DecodeSettings(input.data(), input.size(), &out));
+}
+
} // namespace test
} // namespace quic
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 27d9fe89630..a5996260d23 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_client_promised_info_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_client_promised_info_test.cc
@@ -52,7 +52,7 @@ class MockQuicSpdyClientSession : public QuicSpdyClientSession {
void set_authorized(bool authorized) { authorized_ = authorized; }
- MOCK_METHOD1(CloseStream, void(QuicStreamId stream_id));
+ MOCK_METHOD(void, CloseStream, (QuicStreamId stream_id), (override));
private:
QuicCryptoClientConfig crypto_config_;
@@ -227,7 +227,9 @@ TEST_F(QuicClientPromisedInfoTest, PushPromiseMismatch) {
EXPECT_CALL(*connection_, SendControlFrame(_));
EXPECT_CALL(*connection_,
OnStreamReset(promise_id_, QUIC_PROMISE_VARY_MISMATCH));
- EXPECT_CALL(session_, CloseStream(promise_id_));
+ if (!session_.break_close_loop()) {
+ EXPECT_CALL(session_, CloseStream(promise_id_));
+ }
promised->HandleClientRequest(client_request_, &delegate);
}
@@ -303,7 +305,9 @@ TEST_F(QuicClientPromisedInfoTest, PushPromiseWaitCancels) {
session_.GetOrCreateStream(promise_id_);
// Cancel the promised stream.
- EXPECT_CALL(session_, CloseStream(promise_id_));
+ if (!session_.break_close_loop()) {
+ EXPECT_CALL(session_, CloseStream(promise_id_));
+ }
EXPECT_CALL(*connection_, SendControlFrame(_));
EXPECT_CALL(*connection_, OnStreamReset(promise_id_, QUIC_STREAM_CANCELLED));
promised->Cancel();
@@ -327,11 +331,17 @@ TEST_F(QuicClientPromisedInfoTest, PushPromiseDataClosed) {
promise_stream->OnStreamHeaderList(false, headers.uncompressed_header_bytes(),
headers);
- EXPECT_CALL(session_, CloseStream(promise_id_));
+ if (!session_.break_close_loop()) {
+ EXPECT_CALL(session_, CloseStream(promise_id_));
+ }
EXPECT_CALL(*connection_, SendControlFrame(_));
EXPECT_CALL(*connection_,
OnStreamReset(promise_id_, QUIC_STREAM_PEER_GOING_AWAY));
- session_.SendRstStream(promise_id_, QUIC_STREAM_PEER_GOING_AWAY, 0);
+ if (session_.break_close_loop()) {
+ session_.ResetStream(promise_id_, QUIC_STREAM_PEER_GOING_AWAY, 0);
+ } else {
+ session_.SendRstStream(promise_id_, QUIC_STREAM_PEER_GOING_AWAY, 0);
+ }
// Now initiate rendezvous.
TestPushPromiseDelegate delegate(/*match=*/true);
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 3ca377eb729..0fc903a7283 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_client_push_promise_index_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_client_push_promise_index_test.cc
@@ -40,7 +40,7 @@ class MockQuicSpdyClientSession : public QuicSpdyClientSession {
delete;
~MockQuicSpdyClientSession() override {}
- MOCK_METHOD1(CloseStream, void(QuicStreamId stream_id));
+ MOCK_METHOD(void, CloseStream, (QuicStreamId stream_id), (override));
private:
QuicCryptoClientConfig crypto_config_;
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_header_list.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_header_list.cc
index cbf60ceb252..cbfc2e9f73b 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
@@ -7,10 +7,10 @@
#include <limits>
#include <string>
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_header_table.h"
#include "net/third_party/quiche/src/quic/core/quic_packets.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
-#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h"
namespace quic {
@@ -43,7 +43,7 @@ void QuicHeaderList::OnHeader(quiche::QuicheStringPiece name,
if (current_header_list_size_ < max_header_list_size_) {
current_header_list_size_ += name.size();
current_header_list_size_ += value.size();
- current_header_list_size_ += spdy::kPerHeaderOverhead;
+ current_header_list_size_ += QpackEntry::kSizeOverhead;
header_list_.emplace_back(std::string(name), std::string(value));
}
}
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 9395a708225..d9e1c8e8107 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
@@ -78,66 +78,90 @@ class MockQuicHpackDebugVisitor : public QuicHpackDebugVisitor {
MockQuicHpackDebugVisitor& operator=(const MockQuicHpackDebugVisitor&) =
delete;
- MOCK_METHOD1(OnUseEntry, void(QuicTime::Delta elapsed));
+ MOCK_METHOD(void, OnUseEntry, (QuicTime::Delta elapsed), (override));
};
namespace {
class MockVisitor : public SpdyFramerVisitorInterface {
public:
- MOCK_METHOD1(OnError,
- void(http2::Http2DecoderAdapter::SpdyFramerError error));
- MOCK_METHOD3(OnDataFrameHeader,
- void(SpdyStreamId stream_id, size_t length, bool fin));
- MOCK_METHOD3(OnStreamFrameData,
- void(SpdyStreamId stream_id, const char* data, size_t len));
- MOCK_METHOD1(OnStreamEnd, void(SpdyStreamId stream_id));
- MOCK_METHOD2(OnStreamPadding, void(SpdyStreamId stream_id, size_t len));
- MOCK_METHOD1(OnHeaderFrameStart,
- SpdyHeadersHandlerInterface*(SpdyStreamId stream_id));
- MOCK_METHOD1(OnHeaderFrameEnd, void(SpdyStreamId stream_id));
- MOCK_METHOD3(OnControlFrameHeaderData,
- bool(SpdyStreamId stream_id,
- const char* header_data,
- size_t len));
- MOCK_METHOD2(OnRstStream,
- void(SpdyStreamId stream_id, SpdyErrorCode error_code));
- MOCK_METHOD0(OnSettings, void());
- MOCK_METHOD2(OnSetting, void(SpdySettingsId id, uint32_t value));
- MOCK_METHOD0(OnSettingsAck, void());
- MOCK_METHOD0(OnSettingsEnd, void());
- MOCK_METHOD2(OnPing, void(SpdyPingId unique_id, bool is_ack));
- MOCK_METHOD2(OnGoAway,
- void(SpdyStreamId last_accepted_stream_id,
- SpdyErrorCode error_code));
- MOCK_METHOD7(OnHeaders,
- void(SpdyStreamId stream_id,
- bool has_priority,
- int weight,
- SpdyStreamId parent_stream_id,
- bool exclusive,
- bool fin,
- bool end));
- MOCK_METHOD2(OnWindowUpdate,
- void(SpdyStreamId stream_id, int delta_window_size));
- MOCK_METHOD1(OnBlocked, void(SpdyStreamId stream_id));
- MOCK_METHOD3(OnPushPromise,
- void(SpdyStreamId stream_id,
- SpdyStreamId promised_stream_id,
- bool end));
- MOCK_METHOD2(OnContinuation, void(SpdyStreamId stream_id, bool end));
- MOCK_METHOD3(OnAltSvc,
- void(SpdyStreamId stream_id,
- quiche::QuicheStringPiece origin,
- const SpdyAltSvcWireFormat::AlternativeServiceVector&
- altsvc_vector));
- MOCK_METHOD4(OnPriority,
- void(SpdyStreamId stream_id,
- SpdyStreamId parent_stream_id,
- int weight,
- bool exclusive));
- MOCK_METHOD2(OnUnknownFrame,
- bool(SpdyStreamId stream_id, uint8_t frame_type));
+ MOCK_METHOD(void,
+ OnError,
+ (http2::Http2DecoderAdapter::SpdyFramerError error),
+ (override));
+ MOCK_METHOD(void,
+ OnDataFrameHeader,
+ (SpdyStreamId stream_id, size_t length, bool fin),
+ (override));
+ MOCK_METHOD(void,
+ OnStreamFrameData,
+ (SpdyStreamId stream_id, const char*, size_t len),
+ (override));
+ MOCK_METHOD(void, OnStreamEnd, (SpdyStreamId stream_id), (override));
+ MOCK_METHOD(void,
+ OnStreamPadding,
+ (SpdyStreamId stream_id, size_t len),
+ (override));
+ MOCK_METHOD(SpdyHeadersHandlerInterface*,
+ OnHeaderFrameStart,
+ (SpdyStreamId stream_id),
+ (override));
+ MOCK_METHOD(void, OnHeaderFrameEnd, (SpdyStreamId stream_id), (override));
+ MOCK_METHOD(void,
+ OnRstStream,
+ (SpdyStreamId stream_id, SpdyErrorCode error_code),
+ (override));
+ MOCK_METHOD(void, OnSettings, (), (override));
+ MOCK_METHOD(void, OnSetting, (SpdySettingsId id, uint32_t value), (override));
+ MOCK_METHOD(void, OnSettingsAck, (), (override));
+ MOCK_METHOD(void, OnSettingsEnd, (), (override));
+ MOCK_METHOD(void, OnPing, (SpdyPingId unique_id, bool is_ack), (override));
+ MOCK_METHOD(void,
+ OnGoAway,
+ (SpdyStreamId last_accepted_stream_id, SpdyErrorCode error_code),
+ (override));
+ MOCK_METHOD(void,
+ OnHeaders,
+ (SpdyStreamId stream_id,
+ bool has_priority,
+ int weight,
+ SpdyStreamId parent_stream_id,
+ bool exclusive,
+ bool fin,
+ bool end),
+ (override));
+ MOCK_METHOD(void,
+ OnWindowUpdate,
+ (SpdyStreamId stream_id, int delta_window_size),
+ (override));
+ MOCK_METHOD(void,
+ OnPushPromise,
+ (SpdyStreamId stream_id,
+ SpdyStreamId promised_stream_id,
+ bool end),
+ (override));
+ MOCK_METHOD(void,
+ OnContinuation,
+ (SpdyStreamId stream_id, bool end),
+ (override));
+ MOCK_METHOD(
+ void,
+ OnAltSvc,
+ (SpdyStreamId stream_id,
+ quiche::QuicheStringPiece origin,
+ const SpdyAltSvcWireFormat::AlternativeServiceVector& altsvc_vector),
+ (override));
+ MOCK_METHOD(void,
+ OnPriority,
+ (SpdyStreamId stream_id,
+ SpdyStreamId parent_stream_id,
+ int weight,
+ bool exclusive),
+ (override));
+ MOCK_METHOD(bool,
+ OnUnknownFrame,
+ (SpdyStreamId stream_id, uint8_t frame_type),
+ (override));
};
struct TestParams {
@@ -350,8 +374,8 @@ class QuicHeadersStreamTest : public QuicTestWithParam<TestParams> {
return next_promised_stream_id_ += next_stream_id_;
}
- static const bool kFrameComplete = true;
- static const bool kHasPriority = true;
+ static constexpr bool kFrameComplete = true;
+ static constexpr bool kHasPriority = true;
MockQuicConnectionHelper helper_;
MockAlarmFactory alarm_factory_;
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 17c6ecc55cc..d24e3ddaa88 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
@@ -91,10 +91,7 @@ bool QuicReceiveControlStream::OnMaxPushIdFrame(const MaxPushIdFrame& frame) {
return false;
}
- // TODO(b/124216424): Signal error if received push ID is smaller than a
- // previously received value.
- spdy_session()->OnMaxPushIdFrame(frame.push_id);
- return true;
+ return spdy_session()->OnMaxPushIdFrame(frame.push_id);
}
bool QuicReceiveControlStream::OnGoAwayFrame(const GoAwayFrame& frame) {
@@ -134,12 +131,7 @@ bool QuicReceiveControlStream::OnSettingsFrameStart(
bool QuicReceiveControlStream::OnSettingsFrame(const SettingsFrame& frame) {
QUIC_DVLOG(1) << "Control Stream " << id()
<< " received settings frame: " << frame;
- if (spdy_session_->debug_visitor() != nullptr) {
- spdy_session_->debug_visitor()->OnSettingsFrameReceived(frame);
- }
- for (const auto& setting : frame.values) {
- spdy_session_->OnSetting(setting.first, setting.second);
- }
+ spdy_session_->OnSettingsFrame(frame);
return true;
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base.cc
index 759c5a55a89..27db719fccd 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base.cc
@@ -201,15 +201,10 @@ bool QuicServerSessionBase::ShouldCreateIncomingStream(QuicStreamId id) {
return false;
}
- if (GetQuicReloadableFlag(quic_create_incoming_stream_bug)) {
- if (QuicUtils::IsServerInitiatedStreamId(transport_version(), id)) {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_create_incoming_stream_bug, 1, 2);
- QUIC_BUG << "ShouldCreateIncomingStream called with server initiated "
- "stream ID.";
- return false;
- } else {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_create_incoming_stream_bug, 2, 2);
- }
+ if (QuicUtils::IsServerInitiatedStreamId(transport_version(), id)) {
+ QUIC_BUG << "ShouldCreateIncomingStream called with server initiated "
+ "stream ID.";
+ return false;
}
if (QuicUtils::IsServerInitiatedStreamId(transport_version(), id)) {
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 98cdf4927fc..c482856b61b 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
@@ -236,7 +236,7 @@ TEST_P(QuicServerSessionBaseTest, CloseStreamDueToReset) {
QuicStreamFrame data1(GetNthClientInitiatedBidirectionalId(0), false, 0,
quiche::QuicheStringPiece("HT"));
session_->OnStreamFrame(data1);
- EXPECT_EQ(1u, session_->GetNumOpenIncomingStreams());
+ EXPECT_EQ(1u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get()));
// Send a reset (and expect the peer to send a RST in response).
QuicRstStreamFrame rst1(kInvalidControlFrameId,
@@ -258,13 +258,12 @@ TEST_P(QuicServerSessionBaseTest, CloseStreamDueToReset) {
InjectStopSendingFrame(GetNthClientInitiatedBidirectionalId(0),
QUIC_ERROR_PROCESSING_STREAM);
- EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams());
-
+ EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get()));
// Send the same two bytes of payload in a new packet.
session_->OnStreamFrame(data1);
// The stream should not be re-opened.
- EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams());
+ EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get()));
EXPECT_TRUE(connection_->connected());
}
@@ -289,15 +288,14 @@ TEST_P(QuicServerSessionBaseTest, NeverOpenStreamDueToReset) {
InjectStopSendingFrame(GetNthClientInitiatedBidirectionalId(0),
QUIC_ERROR_PROCESSING_STREAM);
- EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams());
-
+ EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get()));
// Send two bytes of payload.
QuicStreamFrame data1(GetNthClientInitiatedBidirectionalId(0), false, 0,
quiche::QuicheStringPiece("HT"));
session_->OnStreamFrame(data1);
// The stream should never be opened, now that the reset is received.
- EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams());
+ EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get()));
EXPECT_TRUE(connection_->connected());
}
@@ -309,7 +307,7 @@ TEST_P(QuicServerSessionBaseTest, AcceptClosedStream) {
quiche::QuicheStringPiece("\2\0\0\0\0\0\0\0HT"));
session_->OnStreamFrame(frame1);
session_->OnStreamFrame(frame2);
- EXPECT_EQ(2u, session_->GetNumOpenIncomingStreams());
+ EXPECT_EQ(2u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get()));
// Send a reset (and expect the peer to send a RST in response).
QuicRstStreamFrame rst(kInvalidControlFrameId,
@@ -341,7 +339,7 @@ TEST_P(QuicServerSessionBaseTest, AcceptClosedStream) {
session_->OnStreamFrame(frame3);
session_->OnStreamFrame(frame4);
// The stream should never be opened, now that the reset is received.
- EXPECT_EQ(1u, session_->GetNumOpenIncomingStreams());
+ EXPECT_EQ(1u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get()));
EXPECT_TRUE(connection_->connected());
}
@@ -361,7 +359,7 @@ TEST_P(QuicServerSessionBaseTest, MaxOpenStreams) {
EXPECT_EQ(kMaxStreamsForTest + kMaxStreamsMinimumIncrement,
session_->max_open_incoming_bidirectional_streams());
}
- EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams());
+ EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get()));
QuicStreamId stream_id = GetNthClientInitiatedBidirectionalId(0);
// Open the max configured number of streams, should be no problem.
for (size_t i = 0; i < kMaxStreamsForTest; ++i) {
@@ -407,7 +405,7 @@ TEST_P(QuicServerSessionBaseTest, MaxAvailableBidirectionalStreams) {
const size_t kAvailableStreamLimit =
session_->MaxAvailableBidirectionalStreams();
- EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams());
+ EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get()));
EXPECT_TRUE(QuicServerSessionBasePeer::GetOrCreateStream(
session_.get(), GetNthClientInitiatedBidirectionalId(0)));
@@ -477,22 +475,25 @@ class MockQuicCryptoServerStream : public QuicCryptoServerStream {
delete;
~MockQuicCryptoServerStream() override {}
- MOCK_METHOD1(SendServerConfigUpdate,
- void(const CachedNetworkParameters* cached_network_parameters));
+ MOCK_METHOD(void,
+ SendServerConfigUpdate,
+ (const CachedNetworkParameters*),
+ (override));
};
class MockTlsServerHandshaker : public TlsServerHandshaker {
public:
explicit MockTlsServerHandshaker(QuicServerSessionBase* session,
- SSL_CTX* ssl_ctx,
- ProofSource* proof_source)
- : TlsServerHandshaker(session, ssl_ctx, proof_source) {}
+ const QuicCryptoServerConfig& crypto_config)
+ : TlsServerHandshaker(session, crypto_config) {}
MockTlsServerHandshaker(const MockTlsServerHandshaker&) = delete;
MockTlsServerHandshaker& operator=(const MockTlsServerHandshaker&) = delete;
~MockTlsServerHandshaker() override {}
- MOCK_METHOD1(SendServerConfigUpdate,
- void(const CachedNetworkParameters* cached_network_parameters));
+ MOCK_METHOD(void,
+ SendServerConfigUpdate,
+ (const CachedNetworkParameters*),
+ (override));
};
TEST_P(QuicServerSessionBaseTest, BandwidthEstimates) {
@@ -532,8 +533,7 @@ TEST_P(QuicServerSessionBaseTest, BandwidthEstimates) {
quic_crypto_stream);
} else {
tls_server_stream =
- new MockTlsServerHandshaker(session_.get(), crypto_config_.ssl_ctx(),
- crypto_config_.proof_source());
+ new MockTlsServerHandshaker(session_.get(), crypto_config_);
QuicServerSessionBasePeer::SetCryptoStream(session_.get(),
tls_server_stream);
}
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 07b9c7aac84..6127e1b682e 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
@@ -136,15 +136,10 @@ bool QuicSpdyClientSession::ShouldCreateIncomingStream(QuicStreamId id) {
return false;
}
- if (GetQuicReloadableFlag(quic_create_incoming_stream_bug)) {
- if (QuicUtils::IsClientInitiatedStreamId(transport_version(), id)) {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_create_incoming_stream_bug, 1, 2);
- QUIC_BUG << "ShouldCreateIncomingStream called with client initiated "
- "stream ID.";
- return false;
- } else {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_create_incoming_stream_bug, 2, 2);
- }
+ if (QuicUtils::IsClientInitiatedStreamId(transport_version(), id)) {
+ QUIC_BUG << "ShouldCreateIncomingStream called with client initiated "
+ "stream ID.";
+ return false;
}
if (QuicUtils::IsClientInitiatedStreamId(transport_version(), id)) {
@@ -191,7 +186,7 @@ QuicSpdyClientSession::CreateQuicCryptoStream() {
return std::make_unique<QuicCryptoClientStream>(
server_id_, this,
crypto_config_->proof_verifier()->CreateDefaultContext(), crypto_config_,
- this);
+ this, /*has_application_state = */ true);
}
bool QuicSpdyClientSession::IsAuthorized(const std::string& /*authority*/) {
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 b8dae4903b2..63de57c31bc 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
@@ -105,6 +105,8 @@ void QuicSpdyClientSessionBase::OnPromiseHeaderList(
bool QuicSpdyClientSessionBase::HandlePromised(QuicStreamId /* associated_id */,
QuicStreamId promised_id,
const SpdyHeaderBlock& headers) {
+ // TODO(b/136295430): Do not treat |promised_id| as a stream ID when using
+ // IETF QUIC.
// Due to pathalogical packet re-ordering, it is possible that
// frames for the promised stream have already arrived, and the
// promised stream could be active or closed.
@@ -202,7 +204,11 @@ void QuicSpdyClientSessionBase::ResetPromised(
QuicStreamId id,
QuicRstStreamErrorCode error_code) {
DCHECK(QuicUtils::IsServerInitiatedStreamId(transport_version(), id));
- SendRstStream(id, error_code, 0);
+ if (break_close_loop()) {
+ ResetStream(id, error_code, 0);
+ } else {
+ SendRstStream(id, error_code, 0);
+ }
if (!IsOpenStream(id) && !IsClosedStream(id)) {
MaybeIncreaseLargestPeerStreamId(id);
}
@@ -216,8 +222,27 @@ void QuicSpdyClientSessionBase::CloseStreamInner(QuicStreamId stream_id,
}
}
+void QuicSpdyClientSessionBase::OnStreamClosed(QuicStreamId stream_id) {
+ DCHECK(break_close_loop());
+ QuicSpdySession::OnStreamClosed(stream_id);
+ if (!VersionUsesHttp3(transport_version())) {
+ headers_stream()->MaybeReleaseSequencerBuffer();
+ }
+}
+
bool QuicSpdyClientSessionBase::ShouldReleaseHeadersStreamSequencerBuffer() {
return !HasActiveRequestStreams() && promised_by_id_.empty();
}
+void QuicSpdyClientSessionBase::OnSettingsFrame(const SettingsFrame& frame) {
+ QuicSpdySession::OnSettingsFrame(frame);
+ std::unique_ptr<char[]> buffer;
+ QuicByteCount frame_length =
+ HttpEncoder::SerializeSettingsFrame(frame, &buffer);
+ auto serialized_data = std::make_unique<ApplicationState>(
+ buffer.get(), buffer.get() + frame_length);
+ static_cast<QuicCryptoClientStreamBase*>(GetMutableCryptoStream())
+ ->OnApplicationState(std::move(serialized_data));
+}
+
} // namespace quic
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 7d4ba01141a..a109d185a46 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
@@ -24,8 +24,7 @@ class QuicSpdyClientStream;
// to authority constraints). Clients should use this map to enforce
// session affinity for requests corresponding to cross-origin push
// promised streams.
-using QuicPromisedByUrlMap =
- QuicUnorderedMap<std::string, QuicClientPromisedInfo*>;
+using QuicPromisedByUrlMap = QuicHashMap<std::string, QuicClientPromisedInfo*>;
// The maximum time a promises stream can be reserved without being
// claimed by a client request.
@@ -105,6 +104,9 @@ class QUIC_EXPORT_PRIVATE QuicSpdyClientSessionBase
// Release headers stream's sequencer buffer if it's empty.
void CloseStreamInner(QuicStreamId stream_id, bool rst_sent) override;
+ // Release headers stream's sequencer buffer if it's empty.
+ void OnStreamClosed(QuicStreamId stream_id) override;
+
// Returns true if there are no active requests and no promised streams.
bool ShouldReleaseHeadersStreamSequencerBuffer() override;
@@ -117,11 +119,14 @@ class QUIC_EXPORT_PRIVATE QuicSpdyClientSessionBase
return push_promise_index_;
}
+ // Override to serialize the settings and pass it down to the handshaker.
+ void OnSettingsFrame(const SettingsFrame& frame) override;
+
private:
// For QuicSpdyClientStream to detect that a response corresponds to a
// promise.
using QuicPromisedByIdMap =
- QuicUnorderedMap<QuicStreamId, std::unique_ptr<QuicClientPromisedInfo>>;
+ QuicHashMap<QuicStreamId, std::unique_ptr<QuicClientPromisedInfo>>;
// As per rfc7540, section 10.5: track promise streams in "reserved
// (remote)". The primary key is URL from the promise request
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 da05a15f6d6..7d4ae810115 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
@@ -11,9 +11,14 @@
#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/http/http_constants.h"
+#include "net/third_party/quiche/src/quic/core/http/http_frames.h"
#include "net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream.h"
#include "net/third_party/quiche/src/quic/core/http/spdy_server_push_utils.h"
+#include "net/third_party/quiche/src/quic/core/quic_constants.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/core/tls_client_handshaker.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_socket_address.h"
@@ -27,6 +32,7 @@
#include "net/third_party/quiche/src/quic/test_tools/quic_session_peer.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_spdy_session_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_session_cache.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_arraysize.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
@@ -81,11 +87,14 @@ class TestQuicSpdyClientSession : public QuicSpdyClientSession {
class QuicSpdyClientSessionTest : public QuicTestWithParam<ParsedQuicVersion> {
protected:
QuicSpdyClientSessionTest()
- : crypto_config_(crypto_test_utils::ProofVerifierForTesting()),
- promised_stream_id_(
+ : promised_stream_id_(
QuicUtils::GetInvalidStreamId(GetParam().transport_version)),
associated_stream_id_(
QuicUtils::GetInvalidStreamId(GetParam().transport_version)) {
+ auto client_cache = std::make_unique<test::SimpleSessionCache>();
+ client_session_cache_ = client_cache.get();
+ crypto_config_ = std::make_unique<QuicCryptoClientConfig>(
+ crypto_test_utils::ProofVerifierForTesting(), std::move(client_cache));
Initialize();
// Advance the time, because timers do not like uninitialized times.
connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
@@ -103,7 +112,7 @@ class QuicSpdyClientSessionTest : public QuicTestWithParam<ParsedQuicVersion> {
SupportedVersions(GetParam()));
session_ = std::make_unique<TestQuicSpdyClientSession>(
DefaultQuicConfig(), SupportedVersions(GetParam()), connection_,
- QuicServerId(kServerHostname, kPort, false), &crypto_config_,
+ QuicServerId(kServerHostname, kPort, false), crypto_config_.get(),
&push_promise_index_);
session_->Initialize();
push_promise_[":path"] = "/bar";
@@ -157,13 +166,13 @@ class QuicSpdyClientSessionTest : public QuicTestWithParam<ParsedQuicVersion> {
session_->GetMutableCryptoStream());
QuicConfig config = DefaultQuicConfig();
if (VersionHasIetfQuicFrames(connection_->transport_version())) {
- config.SetMaxUnidirectionalStreamsToSend(
- server_max_incoming_streams +
- session_->num_expected_unidirectional_static_streams());
+ config.SetMaxUnidirectionalStreamsToSend(server_max_incoming_streams);
config.SetMaxBidirectionalStreamsToSend(server_max_incoming_streams);
} else {
config.SetMaxBidirectionalStreamsToSend(server_max_incoming_streams);
}
+ SetQuicReloadableFlag(quic_enable_tls_resumption, true);
+ SetQuicReloadableFlag(quic_enable_zero_rtt_for_tls, true);
std::unique_ptr<QuicCryptoServerConfig> crypto_config =
crypto_test_utils::CryptoServerConfigForTesting();
crypto_test_utils::HandshakeWithFakeServer(
@@ -171,7 +180,20 @@ class QuicSpdyClientSessionTest : public QuicTestWithParam<ParsedQuicVersion> {
stream, AlpnForVersion(connection_->version()));
}
- QuicCryptoClientConfig crypto_config_;
+ void CreateConnection() {
+ connection_ = new PacketSavingConnection(&helper_, &alarm_factory_,
+ Perspective::IS_CLIENT,
+ SupportedVersions(GetParam()));
+ // Advance the time, because timers do not like uninitialized times.
+ connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
+ session_ = std::make_unique<TestQuicSpdyClientSession>(
+ DefaultQuicConfig(), SupportedVersions(GetParam()), connection_,
+ QuicServerId(kServerHostname, kPort, false), crypto_config_.get(),
+ &push_promise_index_);
+ session_->Initialize();
+ }
+
+ std::unique_ptr<QuicCryptoClientConfig> crypto_config_;
MockQuicConnectionHelper helper_;
MockAlarmFactory alarm_factory_;
PacketSavingConnection* connection_;
@@ -181,6 +203,7 @@ class QuicSpdyClientSessionTest : public QuicTestWithParam<ParsedQuicVersion> {
std::string promise_url_;
QuicStreamId promised_stream_id_;
QuicStreamId associated_stream_id_;
+ test::SimpleSessionCache* client_session_cache_;
};
INSTANTIATE_TEST_SUITE_P(Tests,
@@ -239,13 +262,6 @@ TEST_P(QuicSpdyClientSessionTest, NoEncryptionAfterInitialEncryption) {
}
TEST_P(QuicSpdyClientSessionTest, MaxNumStreamsWithNoFinOrRst) {
- if (GetParam().handshake_protocol == PROTOCOL_TLS1_3) {
- // This test relies on the MIDS transport parameter, which is not yet
- // supported in TLS 1.3.
- // TODO(nharper): Add support for Transport Parameters in the TLS handshake.
- return;
- }
-
uint32_t kServerMaxIncomingStreams = 1;
CompleteCryptoHandshake(kServerMaxIncomingStreams);
@@ -256,26 +272,13 @@ TEST_P(QuicSpdyClientSessionTest, MaxNumStreamsWithNoFinOrRst) {
// Close the stream, but without having received a FIN or a RST_STREAM
// or MAX_STREAMS (V99) and check that a new one can not be created.
session_->CloseStream(stream->id());
- EXPECT_EQ(1u, session_->GetNumOpenOutgoingStreams());
+ EXPECT_EQ(1u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get()));
stream = session_->CreateOutgoingBidirectionalStream();
EXPECT_FALSE(stream);
-
- if (VersionHasIetfQuicFrames(GetParam().transport_version)) {
- EXPECT_EQ(1u,
- QuicSessionPeer::v99_bidirectional_stream_id_manager(&*session_)
- ->outgoing_stream_count());
- }
}
TEST_P(QuicSpdyClientSessionTest, MaxNumStreamsWithRst) {
- if (GetParam().handshake_protocol == PROTOCOL_TLS1_3) {
- // This test relies on the MIDS transport parameter, which is not yet
- // supported in TLS 1.3.
- // TODO(nharper): Add support for Transport Parameters in the TLS handshake.
- return;
- }
-
uint32_t kServerMaxIncomingStreams = 1;
CompleteCryptoHandshake(kServerMaxIncomingStreams);
@@ -288,7 +291,7 @@ TEST_P(QuicSpdyClientSessionTest, MaxNumStreamsWithRst) {
session_->OnRstStream(QuicRstStreamFrame(kInvalidControlFrameId, stream->id(),
QUIC_RST_ACKNOWLEDGEMENT, 0));
// Check that a new one can be created.
- EXPECT_EQ(0u, session_->GetNumOpenOutgoingStreams());
+ EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get()));
if (VersionHasIetfQuicFrames(GetParam().transport_version)) {
// In V99 the stream limit increases only if we get a MAX_STREAMS
// frame; pretend we got one.
@@ -309,12 +312,6 @@ TEST_P(QuicSpdyClientSessionTest, MaxNumStreamsWithRst) {
}
TEST_P(QuicSpdyClientSessionTest, ResetAndTrailers) {
- if (GetParam().handshake_protocol == PROTOCOL_TLS1_3) {
- // This test relies on the MIDS transport parameter, which is not yet
- // supported in TLS 1.3.
- // TODO(nharper): Add support for Transport Parameters in the TLS handshake.
- return;
- }
// Tests the situation in which the client sends a RST at the same time that
// the server sends trailing headers (trailers). Receipt of the trailers by
// the client should result in all outstanding stream state being tidied up
@@ -346,11 +343,15 @@ TEST_P(QuicSpdyClientSessionTest, ResetAndTrailers) {
.Times(AtLeast(1))
.WillRepeatedly(Invoke(&ClearControlFrame));
EXPECT_CALL(*connection_, OnStreamReset(_, _)).Times(1);
- session_->SendRstStream(stream_id, QUIC_STREAM_PEER_GOING_AWAY, 0);
+ if (session_->break_close_loop()) {
+ session_->ResetStream(stream_id, QUIC_STREAM_PEER_GOING_AWAY, 0);
+ } else {
+ session_->SendRstStream(stream_id, QUIC_STREAM_PEER_GOING_AWAY, 0);
+ }
// A new stream cannot be created as the reset stream still counts as an open
// outgoing stream until closed by the server.
- EXPECT_EQ(1u, session_->GetNumOpenOutgoingStreams());
+ EXPECT_EQ(1u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get()));
stream = session_->CreateOutgoingBidirectionalStream();
EXPECT_EQ(nullptr, stream);
@@ -365,7 +366,7 @@ TEST_P(QuicSpdyClientSessionTest, ResetAndTrailers) {
// The stream is now complete from the client's perspective, and it should
// be able to create a new outgoing stream.
- EXPECT_EQ(0u, session_->GetNumOpenOutgoingStreams());
+ EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get()));
if (VersionHasIetfQuicFrames(GetParam().transport_version)) {
QuicMaxStreamsFrame frame(0, 2,
/*unidirectional=*/false);
@@ -398,7 +399,11 @@ TEST_P(QuicSpdyClientSessionTest, ReceivedMalformedTrailersAfterSendingRst) {
.Times(AtLeast(1))
.WillRepeatedly(Invoke(&ClearControlFrame));
EXPECT_CALL(*connection_, OnStreamReset(_, _)).Times(1);
- session_->SendRstStream(stream_id, QUIC_STREAM_PEER_GOING_AWAY, 0);
+ if (session_->break_close_loop()) {
+ session_->ResetStream(stream_id, QUIC_STREAM_PEER_GOING_AWAY, 0);
+ } else {
+ session_->SendRstStream(stream_id, QUIC_STREAM_PEER_GOING_AWAY, 0);
+ }
// The stream receives trailers with final byte offset, but the header value
// is non-numeric and should be treated as malformed.
@@ -534,11 +539,6 @@ TEST_P(QuicSpdyClientSessionTest, InvalidPacketReceived) {
// A packet with invalid framing should cause a connection to be closed.
TEST_P(QuicSpdyClientSessionTest, InvalidFramedPacketReceived) {
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 (version.KnowsWhichDecrypterToUse()) {
@@ -584,8 +584,7 @@ TEST_P(QuicSpdyClientSessionTest, PushPromiseOnPromiseHeaders) {
CompleteCryptoHandshake();
if (VersionHasIetfQuicFrames(connection_->transport_version())) {
- session_->SetMaxPushId(GetNthServerInitiatedUnidirectionalStreamId(
- connection_->transport_version(), 10));
+ session_->SetMaxPushId(10);
}
MockQuicSpdyClientStream* stream = static_cast<MockQuicSpdyClientStream*>(
@@ -605,25 +604,28 @@ TEST_P(QuicSpdyClientSessionTest, PushPromiseStreamIdTooHigh) {
session_.get(), std::make_unique<QuicSpdyClientStream>(
stream_id, session_.get(), BIDIRECTIONAL));
+ QuicHeaderList headers;
+ headers.OnHeaderBlockStart();
+ headers.OnHeader(":path", "/bar");
+ headers.OnHeader(":authority", "www.google.com");
+ headers.OnHeader(":method", "GET");
+ headers.OnHeader(":scheme", "https");
+ headers.OnHeaderBlockEnd(0, 0);
+
if (VersionHasIetfQuicFrames(connection_->transport_version())) {
- session_->SetMaxPushId(GetNthServerInitiatedUnidirectionalStreamId(
- connection_->transport_version(), 10));
+ session_->SetMaxPushId(10);
// TODO(b/136295430) Use PushId to represent Push IDs instead of
// QuicStreamId.
EXPECT_CALL(
*connection_,
CloseConnection(QUIC_INVALID_STREAM_ID,
"Received push stream id higher than MAX_PUSH_ID.", _));
+ const PushId promise_id = 11;
+ session_->OnPromiseHeaderList(stream_id, promise_id, 0, headers);
+ return;
}
- auto promise_id = GetNthServerInitiatedUnidirectionalStreamId(
+ const QuicStreamId promise_id = GetNthServerInitiatedUnidirectionalStreamId(
connection_->transport_version(), 11);
- auto headers = QuicHeaderList();
- headers.OnHeaderBlockStart();
- headers.OnHeader(":path", "/bar");
- headers.OnHeader(":authority", "www.google.com");
- headers.OnHeader(":method", "GET");
- headers.OnHeader(":scheme", "https");
- headers.OnHeaderBlockEnd(0, 0);
session_->OnPromiseHeaderList(stream_id, promise_id, 0, headers);
}
@@ -647,8 +649,7 @@ TEST_P(QuicSpdyClientSessionTest, PushPromiseOutOfOrder) {
CompleteCryptoHandshake();
if (VersionHasIetfQuicFrames(connection_->transport_version())) {
- session_->SetMaxPushId(GetNthServerInitiatedUnidirectionalStreamId(
- connection_->transport_version(), 10));
+ session_->SetMaxPushId(10);
}
MockQuicSpdyClientStream* stream = static_cast<MockQuicSpdyClientStream*>(
@@ -852,7 +853,12 @@ TEST_P(QuicSpdyClientSessionTest, ResetPromised) {
EXPECT_CALL(*connection_, SendControlFrame(_));
EXPECT_CALL(*connection_,
OnStreamReset(promised_stream_id_, QUIC_STREAM_PEER_GOING_AWAY));
- session_->SendRstStream(promised_stream_id_, QUIC_STREAM_PEER_GOING_AWAY, 0);
+ if (session_->break_close_loop()) {
+ session_->ResetStream(promised_stream_id_, QUIC_STREAM_PEER_GOING_AWAY, 0);
+ } else {
+ session_->SendRstStream(promised_stream_id_, QUIC_STREAM_PEER_GOING_AWAY,
+ 0);
+ }
QuicClientPromisedInfo* promised =
session_->GetPromisedById(promised_stream_id_);
EXPECT_NE(promised, nullptr);
@@ -939,6 +945,108 @@ TEST_P(QuicSpdyClientSessionTest, TooManyPushPromises) {
}
}
+// Test that upon receiving HTTP/3 SETTINGS, the settings are serialized and
+// stored into client session cache.
+TEST_P(QuicSpdyClientSessionTest, OnSettingsFrame) {
+ // This feature is HTTP/3 only
+ if (!VersionUsesHttp3(session_->transport_version())) {
+ return;
+ }
+ CompleteCryptoHandshake();
+ SettingsFrame settings;
+ settings.values[SETTINGS_QPACK_MAX_TABLE_CAPACITY] = 2;
+ settings.values[SETTINGS_MAX_HEADER_LIST_SIZE] = 5;
+ settings.values[256] = 4; // unknown setting
+ char application_state[] = {// type (SETTINGS)
+ 0x04,
+ // length
+ 0x07,
+ // identifier (SETTINGS_QPACK_MAX_TABLE_CAPACITY)
+ 0x01,
+ // content
+ 0x02,
+ // identifier (SETTINGS_MAX_HEADER_LIST_SIZE)
+ 0x06,
+ // content
+ 0x05,
+ // identifier (256 in variable length integer)
+ 0x40 + 0x01, 0x00,
+ // content
+ 0x04};
+ ApplicationState expected(std::begin(application_state),
+ std::end(application_state));
+ session_->OnSettingsFrame(settings);
+ EXPECT_EQ(expected,
+ *client_session_cache_
+ ->Lookup(QuicServerId(kServerHostname, kPort, false), nullptr)
+ ->application_state);
+}
+
+TEST_P(QuicSpdyClientSessionTest, IetfZeroRttSetup) {
+ // This feature is HTTP/3 only
+ if (!VersionUsesHttp3(session_->transport_version())) {
+ return;
+ }
+ CompleteCryptoHandshake();
+ EXPECT_FALSE(session_->GetCryptoStream()->IsResumption());
+ SettingsFrame settings;
+ settings.values[SETTINGS_QPACK_MAX_TABLE_CAPACITY] = 2;
+ settings.values[SETTINGS_MAX_HEADER_LIST_SIZE] = 5;
+ settings.values[256] = 4; // unknown setting
+ session_->OnSettingsFrame(settings);
+
+ CreateConnection();
+ // Session configs should be in initial state.
+ EXPECT_EQ(0u, session_->flow_controller()->send_window_offset());
+ EXPECT_EQ(std::numeric_limits<size_t>::max(),
+ session_->max_outbound_header_list_size());
+ session_->CryptoConnect();
+
+ // The client session should have a basic setup ready before the handshake
+ // succeeds.
+ EXPECT_EQ(kInitialSessionFlowControlWindowForTest,
+ session_->flow_controller()->send_window_offset());
+ auto* id_manager = QuicSessionPeer::v99_streamid_manager(session_.get());
+ EXPECT_EQ(kDefaultMaxStreamsPerConnection,
+ id_manager->max_outgoing_bidirectional_streams());
+ EXPECT_EQ(
+ kDefaultMaxStreamsPerConnection + kHttp3StaticUnidirectionalStreamCount,
+ id_manager->max_outgoing_unidirectional_streams());
+ auto* control_stream =
+ QuicSpdySessionPeer::GetSendControlStream(session_.get());
+ EXPECT_EQ(kInitialStreamFlowControlWindowForTest,
+ control_stream->flow_controller()->send_window_offset());
+ EXPECT_EQ(5u, session_->max_outbound_header_list_size());
+
+ // Complete the handshake with a different config.
+ QuicCryptoClientStream* stream =
+ static_cast<QuicCryptoClientStream*>(session_->GetMutableCryptoStream());
+ QuicConfig config = DefaultQuicConfig();
+ config.SetInitialMaxStreamDataBytesUnidirectionalToSend(
+ kInitialStreamFlowControlWindowForTest + 1);
+ config.SetInitialSessionFlowControlWindowToSend(
+ kInitialSessionFlowControlWindowForTest + 1);
+ config.SetMaxBidirectionalStreamsToSend(kDefaultMaxStreamsPerConnection + 1);
+ config.SetMaxUnidirectionalStreamsToSend(kDefaultMaxStreamsPerConnection + 1);
+ SetQuicReloadableFlag(quic_enable_tls_resumption, true);
+ std::unique_ptr<QuicCryptoServerConfig> crypto_config =
+ crypto_test_utils::CryptoServerConfigForTesting();
+ crypto_test_utils::HandshakeWithFakeServer(
+ &config, crypto_config.get(), &helper_, &alarm_factory_, connection_,
+ stream, AlpnForVersion(connection_->version()));
+
+ EXPECT_TRUE(session_->GetCryptoStream()->IsResumption());
+ EXPECT_EQ(kInitialSessionFlowControlWindowForTest + 1,
+ session_->flow_controller()->send_window_offset());
+ EXPECT_EQ(kDefaultMaxStreamsPerConnection + 1,
+ id_manager->max_outgoing_bidirectional_streams());
+ EXPECT_EQ(kDefaultMaxStreamsPerConnection +
+ kHttp3StaticUnidirectionalStreamCount + 1,
+ id_manager->max_outgoing_unidirectional_streams());
+ EXPECT_EQ(kInitialStreamFlowControlWindowForTest + 1,
+ control_stream->flow_controller()->send_window_offset());
+}
+
} // namespace
} // namespace test
} // namespace quic
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 50224cbde29..fdc0e298371 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream_test.cc
@@ -46,7 +46,7 @@ class MockQuicSpdyClientSession : public QuicSpdyClientSession {
delete;
~MockQuicSpdyClientSession() override = default;
- MOCK_METHOD1(CloseStream, void(QuicStreamId stream_id));
+ MOCK_METHOD(void, CloseStream, (QuicStreamId stream_id), (override));
private:
QuicCryptoClientConfig crypto_config_;
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_server_stream_base_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_server_stream_base_test.cc
index 1a8eef2935f..b3cc147b59f 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
@@ -7,6 +7,7 @@
#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_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"
using testing::_;
@@ -50,7 +51,7 @@ TEST_F(QuicSpdyServerStreamBaseTest,
SendQuicRstStreamNoErrorWithEarlyResponse) {
stream_->StopReading();
EXPECT_CALL(session_, SendRstStream(_, QUIC_STREAM_NO_ERROR, _)).Times(1);
- stream_->set_fin_sent(true);
+ QuicStreamPeer::SetFinSent(stream_);
stream_->CloseWriteSide();
}
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 11351438f3c..27643c87294 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
@@ -376,7 +376,9 @@ QuicSpdySession::QuicSpdySession(
config,
supported_versions,
/*num_expected_unidirectional_static_streams = */
- VersionUsesHttp3(connection->transport_version()) ? 3 : 0),
+ VersionUsesHttp3(connection->transport_version())
+ ? kHttp3StaticUnidirectionalStreamCount
+ : 0),
send_control_stream_(nullptr),
receive_control_stream_(nullptr),
qpack_encoder_receive_stream_(nullptr),
@@ -397,7 +399,8 @@ QuicSpdySession::QuicSpdySession(
spdy_framer_(SpdyFramer::ENABLE_COMPRESSION),
spdy_framer_visitor_(new SpdyFramerVisitor(this)),
server_push_enabled_(true),
- ietf_server_push_enabled_(false),
+ ietf_server_push_enabled_(
+ GetQuicFlag(FLAGS_quic_enable_http3_server_push)),
destruction_indicator_(123456789),
debug_visitor_(nullptr),
http3_goaway_received_(false),
@@ -447,8 +450,6 @@ void QuicSpdySession::Initialize() {
headers_stream_ = headers_stream.get();
ActivateStream(std::move(headers_stream));
} else {
- ConfigureMaxDynamicStreamsToSend(
- config()->GetMaxUnidirectionalStreamsToSend());
qpack_encoder_ = std::make_unique<QpackEncoder>(this);
qpack_decoder_ =
std::make_unique<QpackDecoder>(qpack_maximum_dynamic_table_capacity_,
@@ -739,8 +740,6 @@ void QuicSpdySession::SendInitialData() {
SendMaxPushId();
http3_max_push_id_sent_ = true;
}
- qpack_decoder_send_stream_->MaybeSendStreamType();
- qpack_encoder_send_stream_->MaybeSendStreamType();
}
QpackEncoder* QuicSpdySession::qpack_encoder() {
@@ -785,24 +784,8 @@ void QuicSpdySession::OnNewEncryptionKeyAvailable(
EncryptionLevel level,
std::unique_ptr<QuicEncrypter> encrypter) {
QuicSession::OnNewEncryptionKeyAvailable(level, std::move(encrypter));
- if (GetQuicRestartFlag(quic_send_settings_on_write_key_available) &&
- IsEncryptionEstablished()) {
+ if (IsEncryptionEstablished()) {
// Send H3 SETTINGs once encryption is established.
- QUIC_RESTART_FLAG_COUNT_N(quic_send_settings_on_write_key_available, 2, 2);
- SendInitialData();
- }
-}
-
-void QuicSpdySession::SetDefaultEncryptionLevel(quic::EncryptionLevel level) {
- QuicSession::SetDefaultEncryptionLevel(level);
- if (!GetQuicRestartFlag(quic_send_settings_on_write_key_available)) {
- SendInitialData();
- }
-}
-
-void QuicSpdySession::OnOneRttKeysAvailable() {
- QuicSession::OnOneRttKeysAvailable();
- if (!GetQuicRestartFlag(quic_send_settings_on_write_key_available)) {
SendInitialData();
}
}
@@ -873,6 +856,34 @@ void QuicSpdySession::OnPromiseHeaderList(
ConnectionCloseBehavior::SILENT_CLOSE);
}
+bool QuicSpdySession::SetApplicationState(ApplicationState* cached_state) {
+ DCHECK_EQ(perspective(), Perspective::IS_CLIENT);
+ DCHECK(VersionUsesHttp3(transport_version()));
+
+ SettingsFrame out;
+ if (!HttpDecoder::DecodeSettings(
+ reinterpret_cast<char*>(cached_state->data()), cached_state->size(),
+ &out)) {
+ return false;
+ }
+
+ // TODO(b/153726130): Add OnSettingsFrameResumed() in debug visitor.
+ for (const auto& setting : out.values) {
+ OnSetting(setting.first, setting.second);
+ }
+ return true;
+}
+
+void QuicSpdySession::OnSettingsFrame(const SettingsFrame& frame) {
+ DCHECK(VersionUsesHttp3(transport_version()));
+ if (debug_visitor_ != nullptr) {
+ debug_visitor_->OnSettingsFrameReceived(frame);
+ }
+ for (const auto& setting : frame.values) {
+ OnSetting(setting.first, setting.second);
+ }
+}
+
void QuicSpdySession::OnSetting(uint64_t id, uint64_t value) {
if (VersionUsesHttp3(transport_version())) {
// SETTINGS frame received on the control stream.
@@ -1153,10 +1164,9 @@ bool QuicSpdySession::ProcessPendingStream(PendingStream* pending) {
return true;
}
default:
- SendStopSending(
- static_cast<QuicApplicationErrorCode>(
- QuicHttp3ErrorCode::IETF_QUIC_HTTP3_STREAM_CREATION_ERROR),
- pending->id());
+ SendStopSending(static_cast<QuicApplicationErrorCode>(
+ QuicHttp3ErrorCode::STREAM_CREATION_ERROR),
+ pending->id());
pending->StopReading();
}
return false;
@@ -1211,7 +1221,7 @@ void QuicSpdySession::OnCanCreateNewOutgoingStream(bool unidirectional) {
}
}
-void QuicSpdySession::SetMaxPushId(QuicStreamId max_push_id) {
+void QuicSpdySession::SetMaxPushId(PushId max_push_id) {
DCHECK(VersionUsesHttp3(transport_version()));
DCHECK_EQ(Perspective::IS_CLIENT, perspective());
if (max_push_id_.has_value()) {
@@ -1234,7 +1244,7 @@ void QuicSpdySession::SetMaxPushId(QuicStreamId max_push_id) {
}
}
-bool QuicSpdySession::OnMaxPushIdFrame(QuicStreamId max_push_id) {
+bool QuicSpdySession::OnMaxPushIdFrame(PushId max_push_id) {
DCHECK(VersionUsesHttp3(transport_version()));
DCHECK_EQ(Perspective::IS_SERVER, perspective());
@@ -1245,17 +1255,26 @@ bool QuicSpdySession::OnMaxPushIdFrame(QuicStreamId max_push_id) {
QUIC_DVLOG(1) << "Setting max_push_id to: " << max_push_id
<< " from unset";
}
- quiche::QuicheOptional<QuicStreamId> old_max_push_id = max_push_id_;
+ quiche::QuicheOptional<PushId> old_max_push_id = max_push_id_;
max_push_id_ = max_push_id;
- if (!old_max_push_id.has_value() ||
- max_push_id_.value() > old_max_push_id.value()) {
+ if (!old_max_push_id.has_value() || max_push_id > old_max_push_id.value()) {
OnCanCreateNewOutgoingStream(true);
return true;
}
// Equal value is not considered an error.
- return max_push_id_.value() >= old_max_push_id.value();
+ if (max_push_id < old_max_push_id.value()) {
+ CloseConnectionWithDetails(
+ QUIC_HTTP_INVALID_MAX_PUSH_ID,
+ quiche::QuicheStrCat(
+ "MAX_PUSH_ID received with value ", max_push_id,
+ " which is smaller that previously received value ",
+ old_max_push_id.value()));
+ return false;
+ }
+
+ return true;
}
void QuicSpdySession::SendMaxPushId() {
@@ -1274,7 +1293,7 @@ void QuicSpdySession::EnableServerPush() {
ietf_server_push_enabled_ = true;
}
-bool QuicSpdySession::CanCreatePushStreamWithId(QuicStreamId push_id) {
+bool QuicSpdySession::CanCreatePushStreamWithId(PushId push_id) {
DCHECK(VersionUsesHttp3(transport_version()));
return ietf_server_push_enabled_ && max_push_id_.has_value() &&
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 93fa09d9762..703dffaf41e 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
@@ -246,6 +246,9 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession
// client.
bool server_push_enabled() const;
+ // Called when the control stream receives HTTP/3 SETTINGS.
+ virtual void OnSettingsFrame(const SettingsFrame& frame);
+
// Called when a setting is parsed from an incoming SETTINGS frame.
void OnSetting(uint64_t id, uint64_t value);
@@ -308,14 +311,14 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession
// This method must only be called if protocol is IETF QUIC and perspective is
// client. |max_push_id| must be greater than or equal to current
// |max_push_id_|.
- void SetMaxPushId(QuicStreamId max_push_id);
+ void SetMaxPushId(PushId max_push_id);
// Sets |max_push_id_|.
// This method must only be called if protocol is IETF QUIC and perspective is
// server. It must only be called if a MAX_PUSH_ID frame is received.
// Returns whether |max_push_id| is greater than or equal to current
// |max_push_id_|.
- bool OnMaxPushIdFrame(QuicStreamId max_push_id);
+ bool OnMaxPushIdFrame(PushId max_push_id);
// Enables server push.
// Must only be called when using IETF QUIC, for which server push is disabled
@@ -332,8 +335,7 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession
// For a client this means that SetMaxPushId() has been called with
// |max_push_id| greater than or equal to |push_id|.
// Must only be called when using IETF QUIC.
- // TODO(b/136295430): Use sequential PUSH IDs instead of stream IDs.
- bool CanCreatePushStreamWithId(QuicStreamId push_id);
+ bool CanCreatePushStreamWithId(PushId push_id);
int32_t destruction_indicator() const { return destruction_indicator_; }
@@ -375,6 +377,9 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession
void OnStreamCreated(QuicSpdyStream* stream);
+ // Decode SETTINGS from |cached_state| and apply it to the session.
+ bool SetApplicationState(ApplicationState* cached_state) override;
+
protected:
// Override CreateIncomingStream(), CreateOutgoingBidirectionalStream() and
// CreateOutgoingUnidirectionalStream() with QuicSpdyStream return type to
@@ -418,9 +423,6 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession
EncryptionLevel level,
std::unique_ptr<QuicEncrypter> encrypter) override;
- void SetDefaultEncryptionLevel(quic::EncryptionLevel level) override;
- void OnOneRttKeysAvailable() override;
-
// Optional, enables instrumentation related to go/quic-hpack.
void SetHpackEncoderDebugVisitor(
std::unique_ptr<QuicHpackDebugVisitor> visitor);
@@ -444,9 +446,6 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession
// Initializes HTTP/3 unidirectional streams if not yet initialzed.
virtual void MaybeInitializeHttp3UnidirectionalStreams();
- void set_max_uncompressed_header_bytes(
- size_t set_max_uncompressed_header_bytes);
-
void SendMaxPushId();
private:
@@ -540,7 +539,7 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession
// initial MAX_PUSH_ID frame.
// For a client after 1-RTT keys are available, the push ID in the most
// recently sent MAX_PUSH_ID frame.
- quiche::QuicheOptional<QuicStreamId> max_push_id_;
+ quiche::QuicheOptional<PushId> max_push_id_;
// An integer used for live check. The indicator is assigned a value in
// constructor. As long as it is not the assigned value, that would indicate
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 20078062e94..8b78d7f0883 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
@@ -97,7 +97,8 @@ class TestCryptoStream : public QuicCryptoStream, public QuicCryptoHandshaker {
EXPECT_TRUE(
session()->config()->FillTransportParameters(&transport_parameters));
error = session()->config()->ProcessTransportParameters(
- transport_parameters, CLIENT, &error_details);
+ transport_parameters, CLIENT, /* is_resumption = */ false,
+ &error_details);
} else {
CryptoHandshakeMessage msg;
session()->config()->ToHandshakeMessage(&msg, transport_version());
@@ -137,13 +138,14 @@ class TestCryptoStream : public QuicCryptoStream, public QuicCryptoHandshaker {
}
void OnPacketDecrypted(EncryptionLevel /*level*/) override {}
void OnOneRttPacketAcknowledged() override {}
+ void OnHandshakePacketSent() override {}
void OnHandshakeDoneReceived() override {}
- MOCK_METHOD0(OnCanWrite, void());
+ MOCK_METHOD(void, OnCanWrite, (), (override));
bool HasPendingCryptoRetransmission() const override { return false; }
- MOCK_CONST_METHOD0(HasPendingRetransmission, bool());
+ MOCK_METHOD(bool, HasPendingRetransmission, (), (const, override));
private:
using QuicCryptoStream::session;
@@ -158,7 +160,7 @@ class TestHeadersStream : public QuicHeadersStream {
explicit TestHeadersStream(QuicSpdySession* session)
: QuicHeadersStream(session) {}
- MOCK_METHOD0(OnCanWrite, void());
+ MOCK_METHOD(void, OnCanWrite, (), (override));
};
class TestStream : public QuicSpdyStream {
@@ -173,11 +175,13 @@ class TestStream : public QuicSpdyStream {
void OnBodyAvailable() override {}
- MOCK_METHOD0(OnCanWrite, void());
- MOCK_METHOD4(RetransmitStreamData,
- bool(QuicStreamOffset, QuicByteCount, bool, TransmissionType));
+ MOCK_METHOD(void, OnCanWrite, (), (override));
+ MOCK_METHOD(bool,
+ RetransmitStreamData,
+ (QuicStreamOffset, QuicByteCount, bool, TransmissionType),
+ (override));
- MOCK_CONST_METHOD0(HasPendingRetransmission, bool());
+ MOCK_METHOD(bool, HasPendingRetransmission, (), (const, override));
};
class TestSession : public QuicSpdySession {
@@ -221,9 +225,9 @@ class TestSession : public QuicSpdySession {
TestStream* CreateIncomingStream(QuicStreamId id) override {
// Enforce the limit on the number of open streams.
- if (GetNumOpenIncomingStreams() + 1 >
- max_open_incoming_bidirectional_streams() &&
- !VersionHasIetfQuicFrames(connection()->transport_version())) {
+ if (!VersionHasIetfQuicFrames(connection()->transport_version()) &&
+ GetNumOpenIncomingStreams() + 1 >
+ max_open_incoming_bidirectional_streams()) {
connection()->CloseConnection(
QUIC_TOO_MANY_OPEN_STREAMS, "Too many streams!",
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
@@ -343,8 +347,7 @@ class QuicSpdySessionTestBase : public QuicTestWithParam<ParsedQuicVersion> {
kInitialSessionFlowControlWindowForTest);
if (VersionUsesHttp3(transport_version())) {
QuicConfigPeer::SetReceivedMaxUnidirectionalStreams(
- session_.config(),
- session_.num_expected_unidirectional_static_streams());
+ session_.config(), kHttp3StaticUnidirectionalStreamCount);
}
QuicConfigPeer::SetReceivedInitialSessionFlowControlWindow(
session_.config(), kMinimumFlowControlSendWindow);
@@ -424,6 +427,15 @@ class QuicSpdySessionTestBase : public QuicTestWithParam<ParsedQuicVersion> {
return std::string(priority_buffer.get(), priority_frame_length);
}
+ std::string SerializeMaxPushIdFrame(PushId push_id) {
+ MaxPushIdFrame max_push_id_frame;
+ max_push_id_frame.push_id = push_id;
+ std::unique_ptr<char[]> buffer;
+ QuicByteCount frame_length =
+ HttpEncoder::SerializeMaxPushIdFrame(max_push_id_frame, &buffer);
+ return std::string(buffer.get(), frame_length);
+ }
+
QuicStreamId StreamCountToId(QuicStreamCount stream_count,
Perspective perspective,
bool bidirectional) {
@@ -1115,7 +1127,7 @@ TEST_P(QuicSpdySessionTestServer, RstStreamBeforeHeadersDecompressed) {
QuicStreamFrame data1(GetNthClientInitiatedBidirectionalId(0), false, 0,
quiche::QuicheStringPiece("HT"));
session_.OnStreamFrame(data1);
- EXPECT_EQ(1u, session_.GetNumOpenIncomingStreams());
+ EXPECT_EQ(1u, QuicSessionPeer::GetNumOpenDynamicStreams(&session_));
if (!VersionHasIetfQuicFrames(transport_version())) {
// For version99, OnStreamReset gets called because of the STOP_SENDING,
@@ -1152,7 +1164,7 @@ TEST_P(QuicSpdySessionTestServer, RstStreamBeforeHeadersDecompressed) {
session_.OnStopSendingFrame(stop_sending);
}
- EXPECT_EQ(0u, session_.GetNumOpenIncomingStreams());
+ EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(&session_));
// Connection should remain alive.
EXPECT_TRUE(connection_->connected());
}
@@ -1590,7 +1602,8 @@ TEST_P(QuicSpdySessionTestServer, TooLowUnidirectionalStreamLimitHttp3) {
EXPECT_CALL(
*connection_,
- CloseConnection(_, "New unidirectional stream limit is too low.", _));
+ CloseConnection(
+ _, "new unidirectional limit 2 decreases the current limit: 3", _));
session_.OnConfigNegotiated();
}
@@ -1764,10 +1777,59 @@ TEST_P(QuicSpdySessionTestServer, DrainingStreamsDoNotCountAsOpened) {
for (QuicStreamId i = kFirstStreamId; i < kFinalStreamId; i += IdDelta()) {
QuicStreamFrame data1(i, true, 0, quiche::QuicheStringPiece("HT"));
session_.OnStreamFrame(data1);
- EXPECT_EQ(1u, session_.GetNumOpenIncomingStreams());
- session_.StreamDraining(i);
- EXPECT_EQ(0u, session_.GetNumOpenIncomingStreams());
+ EXPECT_EQ(1u, QuicSessionPeer::GetNumOpenDynamicStreams(&session_));
+ session_.StreamDraining(i, /*unidirectional=*/false);
+ EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(&session_));
+ }
+}
+
+TEST_P(QuicSpdySessionTestServer, ReduceMaxPushId) {
+ if (!VersionUsesHttp3(transport_version())) {
+ return;
}
+
+ StrictMock<MockHttp3DebugVisitor> debug_visitor;
+ session_.set_debug_visitor(&debug_visitor);
+
+ // Use an arbitrary stream id for incoming control stream.
+ QuicStreamId stream_id =
+ GetNthClientInitiatedUnidirectionalStreamId(transport_version(), 3);
+ char type[] = {kControlStream};
+ quiche::QuicheStringPiece stream_type(type, 1);
+
+ QuicStreamOffset offset = 0;
+ QuicStreamFrame data1(stream_id, false, offset, stream_type);
+ offset += stream_type.length();
+ EXPECT_CALL(debug_visitor, OnPeerControlStreamCreated(stream_id));
+ session_.OnStreamFrame(data1);
+ EXPECT_EQ(stream_id,
+ QuicSpdySessionPeer::GetReceiveControlStream(&session_)->id());
+
+ SettingsFrame settings;
+ std::string settings_frame = EncodeSettings(settings);
+ QuicStreamFrame data2(stream_id, false, offset, settings_frame);
+ offset += settings_frame.length();
+
+ EXPECT_CALL(debug_visitor, OnSettingsFrameReceived(settings));
+ session_.OnStreamFrame(data2);
+
+ std::string max_push_id_frame1 = SerializeMaxPushIdFrame(/* push_id = */ 3);
+ QuicStreamFrame data3(stream_id, false, offset, max_push_id_frame1);
+ offset += max_push_id_frame1.length();
+
+ EXPECT_CALL(debug_visitor, OnMaxPushIdFrameReceived(_));
+ session_.OnStreamFrame(data3);
+
+ std::string max_push_id_frame2 = SerializeMaxPushIdFrame(/* push_id = */ 1);
+ QuicStreamFrame data4(stream_id, false, offset, max_push_id_frame2);
+
+ EXPECT_CALL(debug_visitor, OnMaxPushIdFrameReceived(_));
+ EXPECT_CALL(*connection_,
+ CloseConnection(QUIC_HTTP_INVALID_MAX_PUSH_ID,
+ "MAX_PUSH_ID received with value 1 which is "
+ "smaller that previously received value 3",
+ _));
+ session_.OnStreamFrame(data4);
}
class QuicSpdySessionTestClient : public QuicSpdySessionTestBase {
@@ -1794,7 +1856,7 @@ TEST_P(QuicSpdySessionTestClient, BadStreamFramePendingStream) {
return;
}
- EXPECT_EQ(0u, session_.GetNumOpenIncomingStreams());
+ EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(&session_));
QuicStreamId stream_id1 =
GetNthServerInitiatedUnidirectionalStreamId(transport_version(), 0);
// A bad stream frame with no data and no fin.
@@ -1941,7 +2003,7 @@ TEST_P(QuicSpdySessionTestClient, Http3ServerPush) {
return;
}
- EXPECT_EQ(0u, session_.GetNumOpenIncomingStreams());
+ EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(&session_));
// Push unidirectional stream is type 0x01.
std::string frame_type1 = quiche::QuicheTextUtils::HexDecode("01");
@@ -1950,7 +2012,7 @@ TEST_P(QuicSpdySessionTestClient, Http3ServerPush) {
session_.OnStreamFrame(QuicStreamFrame(stream_id1, /* fin = */ false,
/* offset = */ 0, frame_type1));
- EXPECT_EQ(1u, session_.GetNumOpenIncomingStreams());
+ EXPECT_EQ(1u, QuicSessionPeer::GetNumOpenDynamicStreams(&session_));
QuicStream* stream = session_.GetOrCreateStream(stream_id1);
EXPECT_EQ(1u, stream->flow_controller()->bytes_consumed());
EXPECT_EQ(1u, session_.flow_controller()->bytes_consumed());
@@ -1962,7 +2024,7 @@ TEST_P(QuicSpdySessionTestClient, Http3ServerPush) {
session_.OnStreamFrame(QuicStreamFrame(stream_id2, /* fin = */ false,
/* offset = */ 0, frame_type2));
- EXPECT_EQ(2u, session_.GetNumOpenIncomingStreams());
+ EXPECT_EQ(2u, QuicSessionPeer::GetNumOpenDynamicStreams(&session_));
stream = session_.GetOrCreateStream(stream_id2);
EXPECT_EQ(4u, stream->flow_controller()->bytes_consumed());
EXPECT_EQ(5u, session_.flow_controller()->bytes_consumed());
@@ -1973,7 +2035,7 @@ TEST_P(QuicSpdySessionTestClient, Http3ServerPushOutofOrderFrame) {
return;
}
- EXPECT_EQ(0u, session_.GetNumOpenIncomingStreams());
+ EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(&session_));
// Push unidirectional stream is type 0x01.
std::string frame_type = quiche::QuicheTextUtils::HexDecode("01");
@@ -1991,10 +2053,10 @@ TEST_P(QuicSpdySessionTestClient, Http3ServerPushOutofOrderFrame) {
// Receiving some stream data without stream type does not open the stream.
session_.OnStreamFrame(data2);
- EXPECT_EQ(0u, session_.GetNumOpenIncomingStreams());
+ EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(&session_));
session_.OnStreamFrame(data1);
- EXPECT_EQ(1u, session_.GetNumOpenIncomingStreams());
+ EXPECT_EQ(1u, QuicSessionPeer::GetNumOpenDynamicStreams(&session_));
QuicStream* stream = session_.GetOrCreateStream(stream_id);
EXPECT_EQ(3u, stream->flow_controller()->highest_received_byte_offset());
}
@@ -2273,7 +2335,7 @@ TEST_P(QuicSpdySessionTestServer, SimplePendingStreamType) {
QuicStopSendingFrame* stop_sending = frame.stop_sending_frame;
EXPECT_EQ(stream_id, stop_sending->stream_id);
- EXPECT_EQ(QuicHttp3ErrorCode::IETF_QUIC_HTTP3_STREAM_CREATION_ERROR,
+ EXPECT_EQ(QuicHttp3ErrorCode::STREAM_CREATION_ERROR,
static_cast<QuicHttp3ErrorCode>(
stop_sending->application_error_code));
@@ -2418,8 +2480,6 @@ TEST_P(QuicSpdySessionTestServer, ReceiveControlStream) {
EXPECT_NE(5u, session_.max_outbound_header_list_size());
EXPECT_NE(42u, QpackEncoderPeer::maximum_blocked_streams(qpack_encoder));
- EXPECT_CALL(*writer_, WritePacket(_, _, _, _, _))
- .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 0)));
EXPECT_CALL(debug_visitor, OnSettingsFrameReceived(settings));
session_.OnStreamFrame(frame);
@@ -2542,7 +2602,7 @@ TEST_P(QuicSpdySessionTestClient, ResetAfterInvalidIncomingStreamType) {
session_.OnStreamFrame(frame);
// There are no active streams.
- EXPECT_EQ(0u, session_.GetNumOpenIncomingStreams());
+ EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(&session_));
// The pending stream is still around, because it did not receive a FIN.
PendingStream* pending =
@@ -2869,9 +2929,6 @@ TEST_P(QuicSpdySessionTestServer, FineGrainedHpackErrorCodes) {
return;
}
- QuicFlagSaver flag_saver;
- SetQuicReloadableFlag(spdy_enable_granular_decompress_errors, true);
-
QuicStreamId request_stream_id = 5;
session_.CreateIncomingStream(request_stream_id);
@@ -3025,7 +3082,7 @@ TEST_P(QuicSpdySessionTestClient, SendInitialMaxPushIdIfSet) {
StrictMock<MockHttp3DebugVisitor> debug_visitor;
session_.set_debug_visitor(&debug_visitor);
- const QuicStreamId max_push_id = 5;
+ const PushId max_push_id = 5;
session_.SetMaxPushId(max_push_id);
InSequence s;
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 c376d010c8f..51f7c5c9525 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
@@ -192,7 +192,6 @@ QuicSpdyStream::QuicSpdyStream(QuicStreamId id,
headers_decompressed_(false),
header_list_size_limit_exceeded_(false),
headers_payload_length_(0),
- trailers_payload_length_(0),
trailers_decompressed_(false),
trailers_consumed_(false),
http_decoder_visitor_(std::make_unique<HttpDecoderVisitor>(this)),
@@ -229,7 +228,6 @@ QuicSpdyStream::QuicSpdyStream(PendingStream* pending,
headers_decompressed_(false),
header_list_size_limit_exceeded_(false),
headers_payload_length_(0),
- trailers_payload_length_(0),
trailers_decompressed_(false),
trailers_consumed_(false),
http_decoder_visitor_(std::make_unique<HttpDecoderVisitor>(this)),
@@ -285,7 +283,7 @@ size_t QuicSpdyStream::WriteHeaders(
// set and write side needs to be closed without actually sending a FIN on
// this stream.
// TODO(rch): Add test to ensure fin_sent_ is set whenever a fin is sent.
- set_fin_sent(true);
+ SetFinSent();
CloseWriteSide();
}
return bytes_written;
@@ -352,7 +350,7 @@ size_t QuicSpdyStream::WriteTrailers(
// If trailers are sent on the headers stream, then |fin_sent_| needs to be
// set without actually sending a FIN on this stream.
if (!VersionUsesHttp3(transport_version())) {
- set_fin_sent(kFin);
+ SetFinSent();
// Also, write side of this stream needs to be closed. However, only do
// this if there is no more buffered data, otherwise it will never be sent.
@@ -569,10 +567,7 @@ void QuicSpdyStream::OnHeadersDecoded(QuicHeaderList headers,
debug_visitor->OnHeadersDecoded(id(), headers);
}
- const QuicByteCount frame_length = headers_decompressed_
- ? trailers_payload_length_
- : headers_payload_length_;
- OnStreamHeaderList(/* fin = */ false, frame_length, headers);
+ OnStreamHeaderList(/* fin = */ false, headers_payload_length_, headers);
} else {
if (debug_visitor) {
debug_visitor->OnPushPromiseDecoded(id(), promised_stream_id, headers);
@@ -620,16 +615,7 @@ void QuicSpdyStream::MaybeSendPriorityUpdateFrame() {
}
void QuicSpdyStream::OnHeadersTooLarge() {
- if (VersionUsesHttp3(transport_version())) {
- // TODO(b/124216424): Reset stream with H3_REQUEST_CANCELLED (if client)
- // or with H3_REQUEST_REJECTED (if server).
- std::string error_message =
- quiche::QuicheStrCat("Too large headers received on stream ", id());
- OnUnrecoverableError(QUIC_HEADERS_STREAM_DATA_DECOMPRESS_FAILURE,
- error_message);
- } else {
- Reset(QUIC_HEADERS_TOO_LARGE);
- }
+ Reset(QUIC_HEADERS_TOO_LARGE);
}
void QuicSpdyStream::OnInitialHeadersComplete(
@@ -962,6 +948,8 @@ bool QuicSpdyStream::OnHeadersFrameStart(QuicByteCount header_length,
payload_length);
}
+ headers_payload_length_ = payload_length;
+
if (trailers_decompressed_) {
stream_delegate()->OnStreamError(
QUIC_HTTP_INVALID_FRAME_SEQUENCE_ON_SPDY_STREAM,
@@ -983,15 +971,6 @@ bool QuicSpdyStream::OnHeadersFramePayload(quiche::QuicheStringPiece payload) {
DCHECK(VersionUsesHttp3(transport_version()));
DCHECK(qpack_decoded_headers_accumulator_);
- // TODO(b/152518220): Save |payload_length| argument of OnHeadersFrameStart()
- // instead of accumulating payload length in |headers_payload_length_| or
- // |trailers_payload_length_|.
- if (headers_decompressed_) {
- trailers_payload_length_ += payload.length();
- } else {
- headers_payload_length_ += payload.length();
- }
-
qpack_decoded_headers_accumulator_->Decode(payload);
// |qpack_decoded_headers_accumulator_| is reset if an error is detected.
@@ -1040,7 +1019,7 @@ bool QuicSpdyStream::OnPushPromiseFramePushId(
id(), push_id, header_block_length);
}
- // TODO(renjietang): Check max push id and handle errors.
+ // TODO(b/151749109): Check max push id and handle errors.
spdy_session_->OnPushPromise(id(), push_id);
sequencer()->MarkConsumed(body_manager_.OnNonBody(push_id_length));
@@ -1139,7 +1118,7 @@ size_t QuicSpdyStream::WriteHeadersImpl(
encoded_headers.size() + encoder_stream_sent_byte_count,
header_block.TotalBytesUsed());
- return encoded_headers.size() + encoder_stream_sent_byte_count;
+ return encoded_headers.size();
}
#undef ENDPOINT // undef for jumbo builds
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 abf3ef4b78e..61bc1fb35c9 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
@@ -300,10 +300,8 @@ class QUIC_EXPORT_PRIVATE QuicSpdyStream
// Contains a copy of the decompressed header (name, value) pairs until they
// are consumed via Readv.
QuicHeaderList header_list_;
- // Length of HEADERS frame payload.
+ // Length of most recently received HEADERS frame payload.
QuicByteCount headers_payload_length_;
- // Length of TRAILERS frame payload.
- QuicByteCount trailers_payload_length_;
// True if the trailers have been completely decompressed.
bool trailers_decompressed_;
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 fab6d86a415..bafb0f282f0 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
@@ -39,6 +39,7 @@ using spdy::kV3LowestPriority;
using spdy::SpdyHeaderBlock;
using spdy::SpdyPriority;
using testing::_;
+using testing::AnyNumber;
using testing::AtLeast;
using testing::ElementsAre;
using testing::Invoke;
@@ -46,6 +47,7 @@ using testing::InvokeWithoutArgs;
using testing::MatchesRegex;
using testing::Pair;
using testing::Return;
+using testing::SaveArg;
using testing::StrictMock;
namespace quic {
@@ -82,7 +84,8 @@ class TestCryptoStream : public QuicCryptoStream, public QuicCryptoHandshaker {
EXPECT_TRUE(
session()->config()->FillTransportParameters(&transport_parameters));
error = session()->config()->ProcessTransportParameters(
- transport_parameters, CLIENT, &error_details);
+ transport_parameters, CLIENT, /* is_resumption = */ false,
+ &error_details);
} else {
CryptoHandshakeMessage msg;
session()->config()->ToHandshakeMessage(&msg, transport_version());
@@ -122,13 +125,16 @@ class TestCryptoStream : public QuicCryptoStream, public QuicCryptoHandshaker {
}
void OnPacketDecrypted(EncryptionLevel /*level*/) override {}
void OnOneRttPacketAcknowledged() override {}
+ void OnHandshakePacketSent() override {}
+ void OnConnectionClosed(QuicErrorCode /*error*/,
+ ConnectionCloseSource /*source*/) override {}
void OnHandshakeDoneReceived() override {}
- MOCK_METHOD0(OnCanWrite, void());
+ MOCK_METHOD(void, OnCanWrite, (), (override));
bool HasPendingCryptoRetransmission() const override { return false; }
- MOCK_CONST_METHOD0(HasPendingRetransmission, bool());
+ MOCK_METHOD(bool, HasPendingRetransmission, (), (const, override));
private:
using QuicCryptoStream::session;
@@ -144,7 +150,8 @@ class TestStream : public QuicSpdyStream {
QuicSpdySession* session,
bool should_process_data)
: QuicSpdyStream(id, session, BIDIRECTIONAL),
- should_process_data_(should_process_data) {}
+ should_process_data_(should_process_data),
+ headers_payload_length_(0) {}
~TestStream() override = default;
using QuicSpdyStream::set_ack_listener;
@@ -163,7 +170,7 @@ class TestStream : public QuicSpdyStream {
data_ += std::string(buffer, bytes_read);
}
- MOCK_METHOD1(WriteHeadersMock, void(bool fin));
+ MOCK_METHOD(void, WriteHeadersMock, (bool fin), ());
size_t WriteHeadersImpl(spdy::SpdyHeaderBlock header_block,
bool fin,
@@ -174,7 +181,8 @@ class TestStream : public QuicSpdyStream {
if (VersionUsesHttp3(transport_version())) {
// In this case, call QuicSpdyStream::WriteHeadersImpl() that does the
// actual work of closing the stream.
- QuicSpdyStream::WriteHeadersImpl(saved_headers_.Clone(), fin, nullptr);
+ return QuicSpdyStream::WriteHeadersImpl(saved_headers_.Clone(), fin,
+ nullptr);
}
return 0;
}
@@ -187,10 +195,20 @@ class TestStream : public QuicSpdyStream {
return QuicStream::sequencer();
}
+ void OnStreamHeaderList(bool fin,
+ size_t frame_len,
+ const QuicHeaderList& header_list) override {
+ headers_payload_length_ = frame_len;
+ QuicSpdyStream::OnStreamHeaderList(fin, frame_len, header_list);
+ }
+
+ size_t headers_payload_length() const { return headers_payload_length_; }
+
private:
bool should_process_data_;
spdy::SpdyHeaderBlock saved_headers_;
std::string data_;
+ size_t headers_payload_length_;
};
class TestSession : public MockQuicSpdySession {
@@ -306,6 +324,7 @@ class QuicSpdyStreamTest : public QuicTestWithParam<ParsedQuicVersion> {
&helper_, &alarm_factory_, perspective, SupportedVersions(GetParam()));
session_ = std::make_unique<StrictMock<TestSession>>(connection_);
session_->Initialize();
+ connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
ON_CALL(*session_, WritevData(_, _, _, _, _, _))
.WillByDefault(
Invoke(session_.get(), &MockQuicSpdySession::ConsumeData));
@@ -337,18 +356,9 @@ class QuicSpdyStreamTest : public QuicTestWithParam<ParsedQuicVersion> {
EXPECT_CALL(*session_,
WritevData(send_control_stream->id(), _, _, _, _, _))
.Times(num_control_stream_writes);
- auto qpack_decoder_stream =
- QuicSpdySessionPeer::GetQpackDecoderSendStream(session_.get());
- EXPECT_CALL(*session_,
- WritevData(qpack_decoder_stream->id(), 1, 0, _, _, _));
- auto qpack_encoder_stream =
- QuicSpdySessionPeer::GetQpackEncoderSendStream(session_.get());
- EXPECT_CALL(*session_,
- WritevData(qpack_encoder_stream->id(), 1, 0, _, _, _));
}
TestCryptoStream* crypto_stream = session_->GetMutableCryptoStream();
- EXPECT_CALL(*crypto_stream, HasPendingRetransmission())
- .Times(testing::AnyNumber());
+ EXPECT_CALL(*crypto_stream, HasPendingRetransmission()).Times(AnyNumber());
if (connection_->version().HasHandshakeDone() &&
session_->perspective() == Perspective::IS_SERVER) {
@@ -399,6 +409,21 @@ class QuicSpdyStreamTest : public QuicTestWithParam<ParsedQuicVersion> {
return quiche::QuicheStrCat(headers_frame_header, payload);
}
+ // Construct PUSH_PROMISE frame with given payload.
+ std::string SerializePushPromiseFrame(PushId push_id,
+ quiche::QuicheStringPiece payload) {
+ PushPromiseFrame frame;
+ frame.push_id = push_id;
+ frame.headers = payload;
+ std::unique_ptr<char[]> push_promise_buffer;
+ QuicByteCount push_promise_frame_header_length =
+ HttpEncoder::SerializePushPromiseFrameWithOnlyPushId(
+ frame, &push_promise_buffer);
+ quiche::QuicheStringPiece push_promise_frame_header(
+ push_promise_buffer.get(), push_promise_frame_header_length);
+ return quiche::QuicheStrCat(push_promise_frame_header, payload);
+ }
+
std::string DataFrame(quiche::QuicheStringPiece payload) {
std::unique_ptr<char[]> data_buffer;
QuicByteCount data_frame_header_length =
@@ -479,15 +504,18 @@ TEST_P(QuicSpdyStreamTest, ProcessTooLargeHeaderList) {
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+"),
- _));
+ EXPECT_CALL(*session_,
+ SendRstStream(stream_->id(), QUIC_HEADERS_TOO_LARGE, 0));
- stream_->OnStreamFrame(frame);
+ auto qpack_decoder_stream =
+ QuicSpdySessionPeer::GetQpackDecoderSendStream(session_.get());
+ // Stream type and stream cancellation.
+ EXPECT_CALL(*session_,
+ WritevData(qpack_decoder_stream->id(), _, _, NO_FIN, _, _))
+ .Times(2);
- EXPECT_TRUE(stream_->header_list().empty());
+ stream_->OnStreamFrame(frame);
+ EXPECT_THAT(stream_->stream_error(), IsStreamError(QUIC_HEADERS_TOO_LARGE));
}
TEST_P(QuicSpdyStreamTest, ProcessHeaderListWithFin) {
@@ -880,6 +908,7 @@ TEST_P(QuicSpdyStreamTest, StreamFlowControlBlocked) {
}
EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
.WillOnce(Return(QuicConsumedData(kWindow - kHeaderLength, true)));
+ EXPECT_CALL(*session_, SendBlocked(_));
EXPECT_CALL(*connection_, SendControlFrame(_));
stream_->WriteOrBufferBody(body, false);
@@ -899,7 +928,7 @@ TEST_P(QuicSpdyStreamTest, StreamFlowControlNoWindowUpdateIfNotConsumed) {
Initialize(!kShouldProcessData);
// Expect no WINDOW_UPDATE frames to be sent.
- EXPECT_CALL(*connection_, SendWindowUpdate(_, _)).Times(0);
+ EXPECT_CALL(*session_, SendWindowUpdate(_, _)).Times(0);
// Set a small flow control receive window.
const uint64_t kWindow = 36;
@@ -993,6 +1022,7 @@ TEST_P(QuicSpdyStreamTest, StreamFlowControlWindowUpdate) {
QuicStreamFrame frame2(GetNthClientInitiatedBidirectionalId(0), false,
kWindow / 3 + header_length,
quiche::QuicheStringPiece(data));
+ EXPECT_CALL(*session_, SendWindowUpdate(_, _));
EXPECT_CALL(*connection_, SendControlFrame(_));
stream_->OnStreamFrame(frame2);
EXPECT_EQ(kWindow, QuicFlowControllerPeer::ReceiveWindowSize(
@@ -1065,6 +1095,7 @@ TEST_P(QuicSpdyStreamTest, ConnectionFlowControlWindowUpdate) {
// Now receive a further single byte on one stream - again this does not
// trigger a stream WINDOW_UPDATE, but now the connection flow control window
// is over half full and thus a connection WINDOW_UPDATE is sent.
+ EXPECT_CALL(*session_, SendWindowUpdate(_, _));
EXPECT_CALL(*connection_, SendControlFrame(_));
QuicStreamFrame frame3(GetNthClientInitiatedBidirectionalId(0), false,
body.length() + header_length,
@@ -1151,8 +1182,7 @@ TEST_P(QuicSpdyStreamTest, StreamFlowControlFinNotBlocked) {
std::string body = "";
bool fin = true;
- EXPECT_CALL(*connection_,
- SendBlocked(GetNthClientInitiatedBidirectionalId(0)))
+ EXPECT_CALL(*session_, SendBlocked(GetNthClientInitiatedBidirectionalId(0)))
.Times(0);
EXPECT_CALL(*session_, WritevData(_, 0, _, FIN, _, _));
@@ -2148,8 +2178,14 @@ TEST_P(QuicSpdyStreamTest, ImmediateHeaderDecodingWithDynamicTableEntries) {
std::string headers = HeadersFrame(encoded_headers);
EXPECT_CALL(debug_visitor,
OnHeadersFrameReceived(stream_->id(), encoded_headers.length()));
- // Decoder stream type and header acknowledgement.
- EXPECT_CALL(*session_, WritevData(decoder_send_stream->id(), _, _, _, _, _));
+ // Decoder stream type.
+ EXPECT_CALL(*session_,
+ WritevData(decoder_send_stream->id(), /* write_length = */ 1,
+ /* offset = */ 0, _, _, _));
+ // Header acknowledgement.
+ EXPECT_CALL(*session_,
+ WritevData(decoder_send_stream->id(), /* write_length = */ 1,
+ /* offset = */ 1, _, _, _));
EXPECT_CALL(debug_visitor, OnHeadersDecoded(stream_->id(), _));
stream_->OnStreamFrame(QuicStreamFrame(stream_->id(), false, 0, headers));
@@ -2216,8 +2252,14 @@ TEST_P(QuicSpdyStreamTest, BlockedHeaderDecoding) {
auto decoder_send_stream =
QuicSpdySessionPeer::GetQpackDecoderSendStream(session_.get());
- // Decoder stream type and header acknowledgement.
- EXPECT_CALL(*session_, WritevData(decoder_send_stream->id(), _, _, _, _, _));
+ // Decoder stream type.
+ EXPECT_CALL(*session_,
+ WritevData(decoder_send_stream->id(), /* write_length = */ 1,
+ /* offset = */ 0, _, _, _));
+ // Header acknowledgement.
+ EXPECT_CALL(*session_,
+ WritevData(decoder_send_stream->id(), /* write_length = */ 1,
+ /* offset = */ 1, _, _, _));
EXPECT_CALL(debug_visitor, OnHeadersDecoded(stream_->id(), _));
// Deliver dynamic table entry to decoder.
session_->qpack_decoder()->OnInsertWithoutNameReference("foo", "bar");
@@ -2247,6 +2289,7 @@ TEST_P(QuicSpdyStreamTest, BlockedHeaderDecoding) {
// Decoding is blocked because dynamic table entry has not been received yet.
EXPECT_FALSE(stream_->trailers_decompressed());
+ // Header acknowledgement.
EXPECT_CALL(*session_, WritevData(decoder_send_stream->id(), _, _, _, _, _));
EXPECT_CALL(debug_visitor, OnHeadersDecoded(stream_->id(), _));
// Deliver second dynamic table entry to decoder.
@@ -2341,8 +2384,14 @@ TEST_P(QuicSpdyStreamTest, AsyncErrorDecodingTrailers) {
auto decoder_send_stream =
QuicSpdySessionPeer::GetQpackDecoderSendStream(session_.get());
- // The stream byte will be written in the first byte.
- EXPECT_CALL(*session_, WritevData(decoder_send_stream->id(), _, _, _, _, _));
+ // Decoder stream type.
+ EXPECT_CALL(*session_,
+ WritevData(decoder_send_stream->id(), /* write_length = */ 1,
+ /* offset = */ 0, _, _, _));
+ // Header acknowledgement.
+ EXPECT_CALL(*session_,
+ WritevData(decoder_send_stream->id(), /* write_length = */ 1,
+ /* offset = */ 1, _, _, _));
// Deliver dynamic table entry to decoder.
session_->qpack_decoder()->OnInsertWithoutNameReference("foo", "bar");
EXPECT_TRUE(stream_->headers_decompressed());
@@ -2607,13 +2656,7 @@ TEST_P(QuicSpdyStreamTest, PushPromiseOnDataStream) {
std::string headers = EncodeQpackHeaders(pushed_headers);
const QuicStreamId push_id = 1;
- PushPromiseFrame push_promise;
- push_promise.push_id = push_id;
- push_promise.headers = headers;
- std::unique_ptr<char[]> buffer;
- uint64_t length = HttpEncoder::SerializePushPromiseFrameWithOnlyPushId(
- push_promise, &buffer);
- std::string data = std::string(buffer.get(), length) + headers;
+ std::string data = SerializePushPromiseFrame(push_id, headers);
QuicStreamFrame frame(stream_->id(), false, 0, data);
EXPECT_CALL(debug_visitor, OnPushPromiseFrameReceived(stream_->id(), push_id,
@@ -2622,11 +2665,40 @@ TEST_P(QuicSpdyStreamTest, PushPromiseOnDataStream) {
OnPushPromiseDecoded(stream_->id(), push_id,
AsHeaderList(pushed_headers)));
EXPECT_CALL(*session_,
- OnPromiseHeaderList(stream_->id(), push_promise.push_id,
- headers.length(), _));
+ OnPromiseHeaderList(stream_->id(), push_id, headers.length(), _));
stream_->OnStreamFrame(frame);
}
+// Regression test for b/152518220.
+TEST_P(QuicSpdyStreamTest,
+ OnStreamHeaderBlockArgumentDoesNotIncludePushedHeaderBlock) {
+ Initialize(kShouldProcessData);
+ if (!UsesHttp3()) {
+ return;
+ }
+
+ std::string pushed_headers = EncodeQpackHeaders({{"foo", "bar"}});
+ const QuicStreamId push_id = 1;
+ std::string push_promise_frame =
+ SerializePushPromiseFrame(push_id, pushed_headers);
+ QuicStreamOffset offset = 0;
+ QuicStreamFrame frame1(stream_->id(), /* fin = */ false, offset,
+ push_promise_frame);
+ offset += push_promise_frame.length();
+
+ EXPECT_CALL(*session_, OnPromiseHeaderList(stream_->id(), push_id,
+ pushed_headers.length(), _));
+ stream_->OnStreamFrame(frame1);
+
+ std::string headers =
+ EncodeQpackHeaders({{":method", "GET"}, {":path", "/"}});
+ std::string headers_frame = HeadersFrame(headers);
+ QuicStreamFrame frame2(stream_->id(), /* fin = */ false, offset,
+ headers_frame);
+ stream_->OnStreamFrame(frame2);
+ EXPECT_EQ(headers.length(), stream_->headers_payload_length());
+}
+
// Close connection if a DATA frame is received before a HEADERS frame.
TEST_P(QuicSpdyStreamTest, DataBeforeHeaders) {
if (!UsesHttp3()) {
@@ -2794,7 +2866,14 @@ TEST_P(QuicSpdyStreamTest, StreamCancellationWhenStreamReset) {
auto qpack_decoder_stream =
QuicSpdySessionPeer::GetQpackDecoderSendStream(session_.get());
- EXPECT_CALL(*session_, WritevData(qpack_decoder_stream->id(), 1, 1, _, _, _));
+ // Stream type.
+ EXPECT_CALL(*session_,
+ WritevData(qpack_decoder_stream->id(), /* write_length = */ 1,
+ /* offset = */ 0, _, _, _));
+ // Stream cancellation.
+ EXPECT_CALL(*session_,
+ WritevData(qpack_decoder_stream->id(), /* write_length = */ 1,
+ /* offset = */ 1, _, _, _));
EXPECT_CALL(*session_,
SendRstStream(stream_->id(), QUIC_STREAM_CANCELLED, 0));
@@ -2812,12 +2891,57 @@ TEST_P(QuicSpdyStreamTest, StreamCancellationOnResetReceived) {
auto qpack_decoder_stream =
QuicSpdySessionPeer::GetQpackDecoderSendStream(session_.get());
- EXPECT_CALL(*session_, WritevData(qpack_decoder_stream->id(), 1, 1, _, _, _));
+ // Stream type.
+ EXPECT_CALL(*session_,
+ WritevData(qpack_decoder_stream->id(), /* write_length = */ 1,
+ /* offset = */ 0, _, _, _));
+ // Stream cancellation.
+ EXPECT_CALL(*session_,
+ WritevData(qpack_decoder_stream->id(), /* write_length = */ 1,
+ /* offset = */ 1, _, _, _));
stream_->OnStreamReset(QuicRstStreamFrame(
kInvalidControlFrameId, stream_->id(), QUIC_STREAM_CANCELLED, 0));
}
+TEST_P(QuicSpdyStreamTest, WriteHeadersReturnValue) {
+ if (!UsesHttp3()) {
+ return;
+ }
+
+ Initialize(kShouldProcessData);
+ testing::InSequence s;
+
+ // Enable QPACK dynamic table.
+ session_->OnSetting(SETTINGS_QPACK_MAX_TABLE_CAPACITY, 1024);
+ session_->OnSetting(SETTINGS_QPACK_BLOCKED_STREAMS, 1);
+
+ EXPECT_CALL(*stream_, WriteHeadersMock(true));
+
+ QpackSendStream* encoder_stream =
+ QuicSpdySessionPeer::GetQpackEncoderSendStream(session_.get());
+ EXPECT_CALL(*session_, WritevData(encoder_stream->id(), _, _, _, _, _))
+ .Times(AnyNumber());
+
+ // HEADERS frame header.
+ EXPECT_CALL(*session_,
+ WritevData(stream_->id(), _, /* offset = */ 0, _, _, _));
+ // HEADERS frame payload.
+ size_t headers_frame_payload_length = 0;
+ EXPECT_CALL(*session_, WritevData(stream_->id(), _, _, _, _, _))
+ .WillOnce(
+ DoAll(SaveArg<1>(&headers_frame_payload_length),
+ Invoke(session_.get(), &MockQuicSpdySession::ConsumeData)));
+
+ SpdyHeaderBlock request_headers;
+ request_headers["foo"] = "bar";
+ size_t write_headers_return_value =
+ stream_->WriteHeaders(std::move(request_headers), /*fin=*/true, nullptr);
+ EXPECT_TRUE(stream_->fin_sent());
+
+ EXPECT_EQ(headers_frame_payload_length, write_headers_return_value);
+}
+
} // namespace
} // namespace test
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager.cc b/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager.cc
index 6e8f13a10d6..6120f850bbc 100644
--- a/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager.cc
@@ -29,12 +29,27 @@ LegacyQuicStreamIdManager::LegacyQuicStreamIdManager(
? (QuicVersionUsesCryptoFrames(transport_version_)
? QuicUtils::GetInvalidStreamId(transport_version_)
: QuicUtils::GetCryptoStreamId(transport_version_))
- : QuicUtils::GetInvalidStreamId(transport_version_)) {}
+ : QuicUtils::GetInvalidStreamId(transport_version_)),
+ num_open_incoming_streams_(0),
+ num_open_outgoing_streams_(0),
+ handles_accounting_(
+ GetQuicReloadableFlag(quic_stream_id_manager_handles_accounting)) {
+ if (handles_accounting_) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_stream_id_manager_handles_accounting);
+ }
+}
LegacyQuicStreamIdManager::~LegacyQuicStreamIdManager() {}
bool LegacyQuicStreamIdManager::CanOpenNextOutgoingStream(
size_t current_num_open_outgoing_streams) const {
+ if (handles_accounting_) {
+ DCHECK_LE(num_open_outgoing_streams_, max_open_outgoing_streams_);
+ QUIC_DLOG_IF(INFO, num_open_outgoing_streams_ == max_open_outgoing_streams_)
+ << "Failed to create a new outgoing stream. "
+ << "Already " << num_open_outgoing_streams_ << " open.";
+ return num_open_outgoing_streams_ < max_open_outgoing_streams_;
+ }
if (current_num_open_outgoing_streams >= max_open_outgoing_streams_) {
QUIC_DLOG(INFO) << "Failed to create a new outgoing stream. "
<< "Already " << current_num_open_outgoing_streams
@@ -46,6 +61,9 @@ bool LegacyQuicStreamIdManager::CanOpenNextOutgoingStream(
bool LegacyQuicStreamIdManager::CanOpenIncomingStream(
size_t current_num_open_incoming_streams) const {
+ if (handles_accounting_) {
+ return num_open_incoming_streams_ < max_open_incoming_streams_;
+ }
// Check if the new number of open streams would cause the number of
// open streams to exceed the limit.
return current_num_open_incoming_streams < max_open_incoming_streams_;
@@ -102,6 +120,26 @@ QuicStreamId LegacyQuicStreamIdManager::GetNextOutgoingStreamId() {
return id;
}
+void LegacyQuicStreamIdManager::ActivateStream(bool is_incoming) {
+ DCHECK(handles_accounting_);
+ if (is_incoming) {
+ ++num_open_incoming_streams_;
+ return;
+ }
+ ++num_open_outgoing_streams_;
+}
+
+void LegacyQuicStreamIdManager::OnStreamClosed(bool is_incoming) {
+ DCHECK(handles_accounting_);
+ if (is_incoming) {
+ QUIC_BUG_IF(num_open_incoming_streams_ == 0);
+ --num_open_incoming_streams_;
+ return;
+ }
+ QUIC_BUG_IF(num_open_outgoing_streams_ == 0);
+ --num_open_outgoing_streams_;
+}
+
bool LegacyQuicStreamIdManager::IsAvailableStream(QuicStreamId id) const {
if (!IsIncomingStream(id)) {
// Stream IDs under next_ougoing_stream_id_ are either open or previously
diff --git a/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager.h b/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager.h
index 1a94905e41a..6c1309ebbc9 100644
--- a/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager.h
+++ b/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager.h
@@ -46,6 +46,12 @@ class QUIC_EXPORT_PRIVATE LegacyQuicStreamIdManager {
// underlying counter.
QuicStreamId GetNextOutgoingStreamId();
+ // Called when a new stream is open.
+ void ActivateStream(bool is_incoming);
+
+ // Called when a stream ID is closed.
+ void OnStreamClosed(bool is_incoming);
+
// Return true if |id| is peer initiated.
bool IsIncomingStream(QuicStreamId id) const;
@@ -82,6 +88,15 @@ class QUIC_EXPORT_PRIVATE LegacyQuicStreamIdManager {
size_t GetNumAvailableStreams() const;
+ size_t num_open_incoming_streams() const {
+ return num_open_incoming_streams_;
+ }
+ size_t num_open_outgoing_streams() const {
+ return num_open_outgoing_streams_;
+ }
+
+ bool handles_accounting() const { return handles_accounting_; }
+
private:
friend class test::QuicSessionPeer;
@@ -99,9 +114,20 @@ class QUIC_EXPORT_PRIVATE LegacyQuicStreamIdManager {
// Set of stream ids that are less than the largest stream id that has been
// received, but are nonetheless available to be created.
- QuicUnorderedSet<QuicStreamId> available_streams_;
+ QuicHashSet<QuicStreamId> available_streams_;
QuicStreamId largest_peer_created_stream_id_;
+
+ // A counter for peer initiated open streams. Used when handles_accounting_ is
+ // true.
+ size_t num_open_incoming_streams_;
+
+ // A counter for self initiated open streams. Used when handles_accounting_ is
+ // true.
+ size_t num_open_outgoing_streams_;
+
+ // Latched value of quic_stream_id_manager_handles_accounting.
+ const bool handles_accounting_;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager_test.cc
index bd37ffe338e..00654b48c45 100644
--- a/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager_test.cc
@@ -78,15 +78,31 @@ INSTANTIATE_TEST_SUITE_P(Tests,
::testing::PrintToStringParamName());
TEST_P(LegacyQuicStreamIdManagerTest, CanOpenNextOutgoingStream) {
+ if (GetQuicReloadableFlag(quic_stream_id_manager_handles_accounting)) {
+ for (size_t i = 0; i < manager_.max_open_outgoing_streams() - 1; ++i) {
+ manager_.ActivateStream(/*is_incoming=*/false);
+ }
+ }
EXPECT_TRUE(manager_.CanOpenNextOutgoingStream(
manager_.max_open_outgoing_streams() - 1));
+ if (GetQuicReloadableFlag(quic_stream_id_manager_handles_accounting)) {
+ manager_.ActivateStream(/*is_incoming=*/false);
+ }
EXPECT_FALSE(
manager_.CanOpenNextOutgoingStream(manager_.max_open_outgoing_streams()));
}
TEST_P(LegacyQuicStreamIdManagerTest, CanOpenIncomingStream) {
+ if (GetQuicReloadableFlag(quic_stream_id_manager_handles_accounting)) {
+ for (size_t i = 0; i < manager_.max_open_incoming_streams() - 1; ++i) {
+ manager_.ActivateStream(/*is_incoming=*/true);
+ }
+ }
EXPECT_TRUE(
manager_.CanOpenIncomingStream(manager_.max_open_incoming_streams() - 1));
+ if (GetQuicReloadableFlag(quic_stream_id_manager_handles_accounting)) {
+ manager_.ActivateStream(/*is_incoming=*/true);
+ }
EXPECT_FALSE(
manager_.CanOpenIncomingStream(manager_.max_open_incoming_streams()));
}
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 7aa0f1125d2..6469dd266b5 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
@@ -5,16 +5,11 @@
#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator.h"
#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h"
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_header_table.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
namespace quic {
-namespace {
-
-size_t kHeaderFieldSizeOverhead = 32;
-
-}
-
QpackDecodedHeadersAccumulator::QpackDecodedHeadersAccumulator(
QuicStreamId id,
QpackDecoder* qpack_decoder,
@@ -44,7 +39,7 @@ void QpackDecodedHeadersAccumulator::OnHeaderDecoded(
}
uncompressed_header_bytes_including_overhead_ +=
- name.size() + value.size() + kHeaderFieldSizeOverhead;
+ name.size() + value.size() + QpackEntry::kSizeOverhead;
if (uncompressed_header_bytes_including_overhead_ > max_header_list_size_) {
header_list_size_limit_exceeded_ = true;
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 c98f8543ffa..93e2561f367 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
@@ -42,11 +42,14 @@ const char* const kHeaderAcknowledgement = "\x81";
class MockVisitor : public QpackDecodedHeadersAccumulator::Visitor {
public:
~MockVisitor() override = default;
- MOCK_METHOD2(OnHeadersDecoded,
- void(QuicHeaderList headers,
- bool header_list_size_limit_exceeded));
- MOCK_METHOD1(OnHeaderDecodingError,
- void(quiche::QuicheStringPiece error_message));
+ MOCK_METHOD(void,
+ OnHeadersDecoded,
+ (QuicHeaderList headers, bool header_list_size_limit_exceeded),
+ (override));
+ MOCK_METHOD(void,
+ OnHeaderDecodingError,
+ (quiche::QuicheStringPiece error_message),
+ (override));
};
} // anonymous namespace
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_receiver_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_receiver_test.cc
index 44a2286a244..70d2450662a 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_receiver_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_receiver_test.cc
@@ -19,10 +19,16 @@ class MockDelegate : public QpackDecoderStreamReceiver::Delegate {
public:
~MockDelegate() override = default;
- MOCK_METHOD1(OnInsertCountIncrement, void(uint64_t increment));
- MOCK_METHOD1(OnHeaderAcknowledgement, void(QuicStreamId stream_id));
- MOCK_METHOD1(OnStreamCancellation, void(QuicStreamId stream_id));
- MOCK_METHOD1(OnErrorDetected, void(quiche::QuicheStringPiece error_message));
+ MOCK_METHOD(void, OnInsertCountIncrement, (uint64_t increment), (override));
+ MOCK_METHOD(void,
+ OnHeaderAcknowledgement,
+ (QuicStreamId stream_id),
+ (override));
+ MOCK_METHOD(void, OnStreamCancellation, (QuicStreamId stream_id), (override));
+ MOCK_METHOD(void,
+ OnErrorDetected,
+ (quiche::QuicheStringPiece error_message),
+ (override));
};
class QpackDecoderStreamReceiverTest : public QuicTest {
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 2b30e982ea7..db7ec794268 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
@@ -80,6 +80,11 @@ QpackEncoder::Instructions QpackEncoder::FirstPassEncode(
const spdy::SpdyHeaderBlock& header_list,
QpackBlockingManager::IndexSet* referred_indices,
QuicByteCount* encoder_stream_sent_byte_count) {
+ // If previous instructions are buffered in |encoder_stream_sender_|,
+ // do not count them towards the current header block.
+ const QuicByteCount initial_encoder_stream_buffered_byte_count =
+ encoder_stream_sender_.BufferedByteCount();
+
Instructions instructions;
instructions.reserve(header_list.size());
@@ -266,10 +271,16 @@ QpackEncoder::Instructions QpackEncoder::FirstPassEncode(
}
}
- const QuicByteCount sent_byte_count = encoder_stream_sender_.Flush();
+ const QuicByteCount encoder_stream_buffered_byte_count =
+ encoder_stream_sender_.BufferedByteCount();
+ DCHECK_GE(encoder_stream_buffered_byte_count,
+ initial_encoder_stream_buffered_byte_count);
if (encoder_stream_sent_byte_count) {
- *encoder_stream_sent_byte_count = sent_byte_count;
+ *encoder_stream_sent_byte_count =
+ encoder_stream_buffered_byte_count -
+ initial_encoder_stream_buffered_byte_count;
}
+ encoder_stream_sender_.Flush();
++header_list_count_;
@@ -374,7 +385,8 @@ void QpackEncoder::SetMaximumDynamicTableCapacity(
void QpackEncoder::SetDynamicTableCapacity(uint64_t dynamic_table_capacity) {
encoder_stream_sender_.SendSetDynamicTableCapacity(dynamic_table_capacity);
- encoder_stream_sender_.Flush();
+ // Do not flush encoder stream. This write can safely be delayed until more
+ // instructions are written.
bool success = header_table_.SetDynamicTableCapacity(dynamic_table_capacity);
DCHECK(success);
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_receiver_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_receiver_test.cc
index b5edd5f1472..71b6d3438e4 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_receiver_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_receiver_test.cc
@@ -19,16 +19,22 @@ class MockDelegate : public QpackEncoderStreamReceiver::Delegate {
public:
~MockDelegate() override = default;
- MOCK_METHOD3(OnInsertWithNameReference,
- void(bool is_static,
- uint64_t name_index,
- quiche::QuicheStringPiece value));
- MOCK_METHOD2(OnInsertWithoutNameReference,
- void(quiche::QuicheStringPiece name,
- quiche::QuicheStringPiece value));
- MOCK_METHOD1(OnDuplicate, void(uint64_t index));
- MOCK_METHOD1(OnSetDynamicTableCapacity, void(uint64_t capacity));
- MOCK_METHOD1(OnErrorDetected, void(quiche::QuicheStringPiece error_message));
+ MOCK_METHOD(void,
+ OnInsertWithNameReference,
+ (bool is_static,
+ uint64_t name_index,
+ quiche::QuicheStringPiece value),
+ (override));
+ MOCK_METHOD(void,
+ OnInsertWithoutNameReference,
+ (quiche::QuicheStringPiece name, quiche::QuicheStringPiece value),
+ (override));
+ MOCK_METHOD(void, OnDuplicate, (uint64_t index), (override));
+ MOCK_METHOD(void, OnSetDynamicTableCapacity, (uint64_t capacity), (override));
+ MOCK_METHOD(void,
+ OnErrorDetected,
+ (quiche::QuicheStringPiece error_message),
+ (override));
};
class QpackEncoderStreamReceiverTest : public QuicTest {
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 19311b6aeb9..0ae1aae7ff1 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
@@ -44,15 +44,13 @@ void QpackEncoderStreamSender::SendSetDynamicTableCapacity(uint64_t capacity) {
QpackInstructionWithValues::SetDynamicTableCapacity(capacity), &buffer_);
}
-QuicByteCount QpackEncoderStreamSender::Flush() {
+void QpackEncoderStreamSender::Flush() {
if (buffer_.empty()) {
- return 0;
+ return;
}
delegate_->WriteStreamData(buffer_);
- const QuicByteCount bytes_written = buffer_.size();
buffer_.clear();
- return bytes_written;
}
} // namespace quic
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 5701db54ffe..dee23c50d5b 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
@@ -38,9 +38,11 @@ class QUIC_EXPORT_PRIVATE QpackEncoderStreamSender {
// 5.2.4. Set Dynamic Table Capacity
void SendSetDynamicTableCapacity(uint64_t capacity);
+ // Returns number of buffered bytes.
+ QuicByteCount BufferedByteCount() const { return buffer_.size(); }
+
// Writes all buffered instructions on the encoder stream.
- // Returns the number of bytes written.
- QuicByteCount Flush();
+ void Flush();
// delegate must be set if dynamic table capacity is not zero.
void set_qpack_stream_sender_delegate(QpackStreamSenderDelegate* delegate) {
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 b3fd5f9de6a..ea45acc1abd 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
@@ -27,24 +27,29 @@ class QpackEncoderStreamSenderTest : public QuicTest {
};
TEST_F(QpackEncoderStreamSenderTest, InsertWithNameReference) {
+ EXPECT_EQ(0u, stream_.BufferedByteCount());
+
// Static, index fits in prefix, empty value.
std::string expected_encoded_data =
quiche::QuicheTextUtils::HexDecode("c500");
EXPECT_CALL(delegate_, WriteStreamData(Eq(expected_encoded_data)));
stream_.SendInsertWithNameReference(true, 5, "");
- EXPECT_EQ(expected_encoded_data.size(), stream_.Flush());
+ EXPECT_EQ(expected_encoded_data.size(), stream_.BufferedByteCount());
+ stream_.Flush();
// Static, index fits in prefix, Huffman encoded value.
expected_encoded_data = quiche::QuicheTextUtils::HexDecode("c28294e7");
EXPECT_CALL(delegate_, WriteStreamData(Eq(expected_encoded_data)));
stream_.SendInsertWithNameReference(true, 2, "foo");
- EXPECT_EQ(expected_encoded_data.size(), stream_.Flush());
+ EXPECT_EQ(expected_encoded_data.size(), stream_.BufferedByteCount());
+ stream_.Flush();
// Not static, index does not fit in prefix, not Huffman encoded value.
expected_encoded_data = quiche::QuicheTextUtils::HexDecode("bf4a03626172");
EXPECT_CALL(delegate_, WriteStreamData(Eq(expected_encoded_data)));
stream_.SendInsertWithNameReference(false, 137, "bar");
- EXPECT_EQ(expected_encoded_data.size(), stream_.Flush());
+ EXPECT_EQ(expected_encoded_data.size(), stream_.BufferedByteCount());
+ stream_.Flush();
// Value length does not fit in prefix.
// 'Z' would be Huffman encoded to 8 bits, so no Huffman encoding is used.
@@ -55,29 +60,35 @@ TEST_F(QpackEncoderStreamSenderTest, InsertWithNameReference) {
"5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a");
EXPECT_CALL(delegate_, WriteStreamData(Eq(expected_encoded_data)));
stream_.SendInsertWithNameReference(false, 42, std::string(127, 'Z'));
- EXPECT_EQ(expected_encoded_data.size(), stream_.Flush());
+ EXPECT_EQ(expected_encoded_data.size(), stream_.BufferedByteCount());
+ stream_.Flush();
}
TEST_F(QpackEncoderStreamSenderTest, InsertWithoutNameReference) {
+ EXPECT_EQ(0u, stream_.BufferedByteCount());
+
// Empty name and value.
std::string expected_encoded_data =
quiche::QuicheTextUtils::HexDecode("4000");
EXPECT_CALL(delegate_, WriteStreamData(Eq(expected_encoded_data)));
stream_.SendInsertWithoutNameReference("", "");
- EXPECT_EQ(expected_encoded_data.size(), stream_.Flush());
+ EXPECT_EQ(expected_encoded_data.size(), stream_.BufferedByteCount());
+ stream_.Flush();
// Huffman encoded short strings.
expected_encoded_data = quiche::QuicheTextUtils::HexDecode("6294e78294e7");
EXPECT_CALL(delegate_, WriteStreamData(Eq(expected_encoded_data)));
stream_.SendInsertWithoutNameReference("foo", "foo");
- EXPECT_EQ(expected_encoded_data.size(), stream_.Flush());
+ EXPECT_EQ(expected_encoded_data.size(), stream_.BufferedByteCount());
+ stream_.Flush();
// Not Huffman encoded short strings.
expected_encoded_data =
quiche::QuicheTextUtils::HexDecode("4362617203626172");
EXPECT_CALL(delegate_, WriteStreamData(Eq(expected_encoded_data)));
stream_.SendInsertWithoutNameReference("bar", "bar");
- EXPECT_EQ(expected_encoded_data.size(), stream_.Flush());
+ EXPECT_EQ(expected_encoded_data.size(), stream_.BufferedByteCount());
+ stream_.Flush();
// Not Huffman encoded long strings; length does not fit on prefix.
// 'Z' would be Huffman encoded to 8 bits, so no Huffman encoding is used.
@@ -90,35 +101,46 @@ TEST_F(QpackEncoderStreamSenderTest, InsertWithoutNameReference) {
EXPECT_CALL(delegate_, WriteStreamData(Eq(expected_encoded_data)));
stream_.SendInsertWithoutNameReference(std::string(31, 'Z'),
std::string(127, 'Z'));
- EXPECT_EQ(expected_encoded_data.size(), stream_.Flush());
+ EXPECT_EQ(expected_encoded_data.size(), stream_.BufferedByteCount());
+ stream_.Flush();
}
TEST_F(QpackEncoderStreamSenderTest, Duplicate) {
+ EXPECT_EQ(0u, stream_.BufferedByteCount());
+
// Small index fits in prefix.
std::string expected_encoded_data = quiche::QuicheTextUtils::HexDecode("11");
EXPECT_CALL(delegate_, WriteStreamData(Eq(expected_encoded_data)));
stream_.SendDuplicate(17);
- EXPECT_EQ(expected_encoded_data.size(), stream_.Flush());
+ EXPECT_EQ(expected_encoded_data.size(), stream_.BufferedByteCount());
+ stream_.Flush();
// Large index requires two extension bytes.
expected_encoded_data = quiche::QuicheTextUtils::HexDecode("1fd503");
EXPECT_CALL(delegate_, WriteStreamData(Eq(expected_encoded_data)));
stream_.SendDuplicate(500);
- EXPECT_EQ(expected_encoded_data.size(), stream_.Flush());
+ EXPECT_EQ(expected_encoded_data.size(), stream_.BufferedByteCount());
+ stream_.Flush();
}
TEST_F(QpackEncoderStreamSenderTest, SetDynamicTableCapacity) {
+ EXPECT_EQ(0u, stream_.BufferedByteCount());
+
// Small capacity fits in prefix.
std::string expected_encoded_data = quiche::QuicheTextUtils::HexDecode("31");
EXPECT_CALL(delegate_, WriteStreamData(Eq(expected_encoded_data)));
stream_.SendSetDynamicTableCapacity(17);
- EXPECT_EQ(expected_encoded_data.size(), stream_.Flush());
+ EXPECT_EQ(expected_encoded_data.size(), stream_.BufferedByteCount());
+ stream_.Flush();
+ EXPECT_EQ(0u, stream_.BufferedByteCount());
// Large capacity requires two extension bytes.
expected_encoded_data = quiche::QuicheTextUtils::HexDecode("3fd503");
EXPECT_CALL(delegate_, WriteStreamData(Eq(expected_encoded_data)));
stream_.SendSetDynamicTableCapacity(500);
- EXPECT_EQ(expected_encoded_data.size(), stream_.Flush());
+ EXPECT_EQ(expected_encoded_data.size(), stream_.BufferedByteCount());
+ stream_.Flush();
+ EXPECT_EQ(0u, stream_.BufferedByteCount());
}
// No writes should happen until Flush is called.
@@ -142,13 +164,17 @@ TEST_F(QpackEncoderStreamSenderTest, Coalesce) {
"11"); // Duplicate entry.
EXPECT_CALL(delegate_, WriteStreamData(Eq(expected_encoded_data)));
- EXPECT_EQ(expected_encoded_data.size(), stream_.Flush());
+ EXPECT_EQ(expected_encoded_data.size(), stream_.BufferedByteCount());
+ stream_.Flush();
+ EXPECT_EQ(0u, stream_.BufferedByteCount());
}
// No writes should happen if QpackEncoderStreamSender::Flush() is called
// when the buffer is empty.
TEST_F(QpackEncoderStreamSenderTest, FlushEmpty) {
- EXPECT_EQ(0u, stream_.Flush());
+ EXPECT_EQ(0u, stream_.BufferedByteCount());
+ stream_.Flush();
+ EXPECT_EQ(0u, stream_.BufferedByteCount());
}
} // namespace
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 212257cedb6..e0d21c53269 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
@@ -12,6 +12,7 @@
#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"
+#include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_text_utils.h"
@@ -213,11 +214,6 @@ TEST_F(QpackEncoderTest, InvalidHeaderAcknowledgement) {
TEST_F(QpackEncoderTest, DynamicTable) {
encoder_.SetMaximumBlockedStreams(1);
encoder_.SetMaximumDynamicTableCapacity(4096);
-
- // Set Dynamic Table Capacity instruction.
- EXPECT_CALL(
- encoder_stream_sender_delegate_,
- WriteStreamData(Eq(quiche::QuicheTextUtils::HexDecode("3fe11f"))));
encoder_.SetDynamicTableCapacity(4096);
spdy::SpdyHeaderBlock header_list;
@@ -226,6 +222,9 @@ TEST_F(QpackEncoderTest, DynamicTable) {
"baz"); // name matches dynamic entry
header_list["cookie"] = "baz"; // name matches static entry
+ // Set Dynamic Table Capacity instruction.
+ std::string set_dyanamic_table_capacity =
+ quiche::QuicheTextUtils::HexDecode("3fe11f");
// Insert three entries into the dynamic table.
std::string insert_entries = quiche::QuicheTextUtils::HexDecode(
"62" // insert without name reference
@@ -236,7 +235,8 @@ TEST_F(QpackEncoderTest, DynamicTable) {
"c5" // insert with name reference, static index 5
"0362617a"); // value "baz"
EXPECT_CALL(encoder_stream_sender_delegate_,
- WriteStreamData(Eq(insert_entries)));
+ WriteStreamData(Eq(quiche::QuicheStrCat(
+ set_dyanamic_table_capacity, insert_entries))));
EXPECT_EQ(quiche::QuicheTextUtils::HexDecode(
"0400" // prefix
@@ -250,10 +250,6 @@ TEST_F(QpackEncoderTest, DynamicTable) {
TEST_F(QpackEncoderTest, SmallDynamicTable) {
encoder_.SetMaximumBlockedStreams(1);
encoder_.SetMaximumDynamicTableCapacity(QpackEntry::Size("foo", "bar"));
-
- // Set Dynamic Table Capacity instruction.
- EXPECT_CALL(encoder_stream_sender_delegate_,
- WriteStreamData(Eq(quiche::QuicheTextUtils::HexDecode("3f07"))));
encoder_.SetDynamicTableCapacity(QpackEntry::Size("foo", "bar"));
spdy::SpdyHeaderBlock header_list;
@@ -263,13 +259,17 @@ TEST_F(QpackEncoderTest, SmallDynamicTable) {
header_list["cookie"] = "baz"; // name matches static entry
header_list["bar"] = "baz"; // no match
+ // Set Dynamic Table Capacity instruction.
+ std::string set_dyanamic_table_capacity =
+ quiche::QuicheTextUtils::HexDecode("3f07");
// Insert one entry into the dynamic table.
std::string insert_entry = quiche::QuicheTextUtils::HexDecode(
"62" // insert without name reference
"94e7" // Huffman-encoded name "foo"
"03626172"); // value "bar"
EXPECT_CALL(encoder_stream_sender_delegate_,
- WriteStreamData(Eq(insert_entry)));
+ WriteStreamData(Eq(quiche::QuicheStrCat(
+ set_dyanamic_table_capacity, insert_entry))));
EXPECT_EQ(quiche::QuicheTextUtils::HexDecode(
"0200" // prefix
@@ -288,23 +288,22 @@ TEST_F(QpackEncoderTest, SmallDynamicTable) {
TEST_F(QpackEncoderTest, BlockedStream) {
encoder_.SetMaximumBlockedStreams(1);
encoder_.SetMaximumDynamicTableCapacity(4096);
-
- // Set Dynamic Table Capacity instruction.
- EXPECT_CALL(
- encoder_stream_sender_delegate_,
- WriteStreamData(Eq(quiche::QuicheTextUtils::HexDecode("3fe11f"))));
encoder_.SetDynamicTableCapacity(4096);
spdy::SpdyHeaderBlock header_list1;
header_list1["foo"] = "bar";
+ // Set Dynamic Table Capacity instruction.
+ std::string set_dyanamic_table_capacity =
+ quiche::QuicheTextUtils::HexDecode("3fe11f");
// Insert one entry into the dynamic table.
std::string insert_entry1 = quiche::QuicheTextUtils::HexDecode(
"62" // insert without name reference
"94e7" // Huffman-encoded name "foo"
"03626172"); // value "bar"
EXPECT_CALL(encoder_stream_sender_delegate_,
- WriteStreamData(Eq(insert_entry1)));
+ WriteStreamData(Eq(quiche::QuicheStrCat(
+ set_dyanamic_table_capacity, insert_entry1))));
EXPECT_EQ(quiche::QuicheTextUtils::HexDecode("0200" // prefix
"80"), // dynamic entry 0
@@ -420,12 +419,10 @@ TEST_F(QpackEncoderTest, Draining) {
}
maximum_dynamic_table_capacity += QpackEntry::Size("one", "foo");
encoder_.SetMaximumDynamicTableCapacity(maximum_dynamic_table_capacity);
-
- // Set Dynamic Table Capacity instruction.
- EXPECT_CALL(encoder_stream_sender_delegate_, WriteStreamData(_));
encoder_.SetDynamicTableCapacity(maximum_dynamic_table_capacity);
- // Insert ten entries into the dynamic table.
+ // Set Dynamic Table Capacity instruction and insert ten entries into the
+ // dynamic table.
EXPECT_CALL(encoder_stream_sender_delegate_, WriteStreamData(_));
EXPECT_EQ(quiche::QuicheTextUtils::HexDecode(
@@ -466,10 +463,6 @@ TEST_F(QpackEncoderTest, Draining) {
TEST_F(QpackEncoderTest, DynamicTableCapacityLessThanMaximum) {
encoder_.SetMaximumDynamicTableCapacity(1024);
-
- // Set Dynamic Table Capacity instruction.
- EXPECT_CALL(encoder_stream_sender_delegate_,
- WriteStreamData(Eq(quiche::QuicheTextUtils::HexDecode("3e"))));
encoder_.SetDynamicTableCapacity(30);
QpackHeaderTable* header_table = QpackEncoderPeer::header_table(&encoder_);
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table_test.cc
index 5cf392023af..a96159be486 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table_test.cc
@@ -25,8 +25,8 @@ class MockObserver : public QpackHeaderTable::Observer {
public:
~MockObserver() override = default;
- MOCK_METHOD0(OnInsertCountReachedThreshold, void());
- MOCK_METHOD0(Cancel, void());
+ MOCK_METHOD(void, OnInsertCountReachedThreshold, (), (override));
+ MOCK_METHOD(void, Cancel, (), (override));
};
class QpackHeaderTableTest : public QuicTest {
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 99cda08dd28..a4bbc91aaf5 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
@@ -61,8 +61,14 @@ class MockDelegate : public QpackInstructionDecoder::Delegate {
MockDelegate& operator=(const MockDelegate&) = delete;
~MockDelegate() override = default;
- MOCK_METHOD1(OnInstructionDecoded, bool(const QpackInstruction* instruction));
- MOCK_METHOD1(OnError, void(quiche::QuicheStringPiece error_message));
+ MOCK_METHOD(bool,
+ OnInstructionDecoded,
+ (const QpackInstruction*),
+ (override));
+ MOCK_METHOD(void,
+ OnError,
+ (quiche::QuicheStringPiece error_message),
+ (override));
};
class QpackInstructionDecoderTest : public QuicTestWithParam<FragmentMode> {
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_alarm_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_alarm_test.cc
index b2f4690f9a5..87cbd699dff 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_alarm_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_alarm_test.cc
@@ -14,7 +14,7 @@ namespace {
class MockDelegate : public QuicAlarm::Delegate {
public:
- MOCK_METHOD0(OnAlarm, void());
+ MOCK_METHOD(void, OnAlarm, (), (override));
};
class DestructiveDelegate : public QuicAlarm::Delegate {
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_arena_scoped_ptr_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_arena_scoped_ptr_test.cc
index cd0780fe508..5b7548a5c53 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_arena_scoped_ptr_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_arena_scoped_ptr_test.cc
@@ -13,7 +13,7 @@ namespace {
enum class TestParam { kFromHeap, kFromArena };
struct TestObject {
- explicit TestObject(uintptr_t value) : value(value) { buffer.resize(1200); }
+ explicit TestObject(uintptr_t value) : value(value) { buffer.resize(1024); }
uintptr_t value;
// Ensure that we have a non-trivial destructor that will leak memory if it's
@@ -51,7 +51,7 @@ class QuicArenaScopedPtrParamTest : public QuicTestWithParam<TestParam> {
}
private:
- QuicOneBlockArena<1200> arena_;
+ QuicOneBlockArena<1024> arena_;
};
INSTANTIATE_TEST_SUITE_P(QuicArenaScopedPtrParamTest,
@@ -69,7 +69,7 @@ TEST_P(QuicArenaScopedPtrParamTest, NullObjects) {
}
TEST_P(QuicArenaScopedPtrParamTest, FromArena) {
- QuicOneBlockArena<1200> arena_;
+ QuicOneBlockArena<1024> arena_;
EXPECT_TRUE(arena_.New<TestObject>(0).is_from_arena());
EXPECT_FALSE(
QuicArenaScopedPtr<TestObject>(new TestObject(0)).is_from_arena());
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_buffered_packet_store.cc b/chromium/net/third_party/quiche/src/quic/core/quic_buffered_packet_store.cc
index e363461cf8c..cafe871f38b 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_buffered_packet_store.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_buffered_packet_store.cc
@@ -86,23 +86,25 @@ EnqueuePacketResult QuicBufferedPacketStore::EnqueuePacket(
QuicSocketAddress self_address,
QuicSocketAddress peer_address,
bool is_chlo,
- const std::string& alpn,
+ const std::vector<std::string>& alpns,
const ParsedQuicVersion& version) {
QUIC_BUG_IF(!GetQuicFlag(FLAGS_quic_allow_chlo_buffering))
<< "Shouldn't buffer packets if disabled via flag.";
QUIC_BUG_IF(is_chlo && QuicContainsKey(connections_with_chlo_, connection_id))
<< "Shouldn't buffer duplicated CHLO on connection " << connection_id;
- QUIC_BUG_IF(!is_chlo && !alpn.empty())
+ QUIC_BUG_IF(!is_chlo && !alpns.empty())
<< "Shouldn't have an ALPN defined for a non-CHLO packet.";
QUIC_BUG_IF(is_chlo && version.transport_version == QUIC_VERSION_UNSUPPORTED)
<< "Should have version for CHLO packet.";
- if (!QuicContainsKey(undecryptable_packets_, connection_id) &&
- ShouldBufferPacket(is_chlo)) {
- // Drop the packet if the upper limit of undecryptable packets has been
- // reached or the whole capacity of the store has been reached.
- return TOO_MANY_CONNECTIONS;
- } else if (!QuicContainsKey(undecryptable_packets_, connection_id)) {
+ const bool is_first_packet =
+ !QuicContainsKey(undecryptable_packets_, connection_id);
+ if (is_first_packet) {
+ if (ShouldBufferPacket(is_chlo)) {
+ // Drop the packet if the upper limit of undecryptable packets has been
+ // reached or the whole capacity of the store has been reached.
+ return TOO_MANY_CONNECTIONS;
+ }
undecryptable_packets_.emplace(
std::make_pair(connection_id, BufferedPacketList()));
undecryptable_packets_.back().second.ietf_quic = ietf_quic;
@@ -138,14 +140,25 @@ EnqueuePacketResult QuicBufferedPacketStore::EnqueuePacket(
// Add CHLO to the beginning of buffered packets so that it can be delivered
// first later.
queue.buffered_packets.push_front(std::move(new_entry));
- queue.alpn = alpn;
+ queue.alpns = alpns;
connections_with_chlo_[connection_id] = false; // Dummy value.
// Set the version of buffered packets of this connection on CHLO.
queue.version = version;
} else {
// Buffer non-CHLO packets in arrival order.
queue.buffered_packets.push_back(std::move(new_entry));
+
+ // Attempt to parse multi-packet TLS CHLOs.
+ if (is_first_packet) {
+ queue.tls_chlo_extractor.IngestPacket(version, packet);
+ // Since this is the first packet and it's not a CHLO, the
+ // TlsChloExtractor should not have the entire CHLO.
+ QUIC_BUG_IF(queue.tls_chlo_extractor.HasParsedFullChlo())
+ << "First packet in list should not contain full CHLO";
+ }
+ // TODO(b/154857081) Reorder CHLO packets ahead of other ones.
}
+
MaybeSetExpirationAlarm();
return SUCCESS;
}
@@ -240,4 +253,25 @@ bool QuicBufferedPacketStore::HasChloForConnection(
return QuicContainsKey(connections_with_chlo_, connection_id);
}
+bool QuicBufferedPacketStore::IngestPacketForTlsChloExtraction(
+ const QuicConnectionId& connection_id,
+ const ParsedQuicVersion& version,
+ const QuicReceivedPacket& packet,
+ std::vector<std::string>* out_alpns) {
+ DCHECK_NE(out_alpns, nullptr);
+ DCHECK_EQ(version.handshake_protocol, PROTOCOL_TLS1_3);
+ auto it = undecryptable_packets_.find(connection_id);
+ if (it == undecryptable_packets_.end()) {
+ QUIC_BUG << "Cannot ingest packet for unknown connection ID "
+ << connection_id;
+ return false;
+ }
+ it->second.tls_chlo_extractor.IngestPacket(version, packet);
+ if (!it->second.tls_chlo_extractor.HasParsedFullChlo()) {
+ return false;
+ }
+ *out_alpns = it->second.tls_chlo_extractor.alpns();
+ return true;
+}
+
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_buffered_packet_store.h b/chromium/net/third_party/quiche/src/quic/core/quic_buffered_packet_store.h
index 52d957e1a43..b862b42ee4f 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_buffered_packet_store.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_buffered_packet_store.h
@@ -13,6 +13,7 @@
#include "net/third_party/quiche/src/quic/core/quic_clock.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/tls_chlo_extractor.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
@@ -32,7 +33,7 @@ class QuicBufferedPacketStorePeer;
// of connections: connections with CHLO buffered and those without CHLO. The
// latter has its own upper limit along with the max number of connections this
// store can hold. The former pool can grow till this store is full.
-class QUIC_EXPORT_PRIVATE QuicBufferedPacketStore {
+class QUIC_NO_EXPORT QuicBufferedPacketStore {
public:
enum EnqueuePacketResult {
SUCCESS = 0,
@@ -40,7 +41,7 @@ class QUIC_EXPORT_PRIVATE QuicBufferedPacketStore {
TOO_MANY_CONNECTIONS // Too many connections stored up in the store.
};
- struct QUIC_EXPORT_PRIVATE BufferedPacket {
+ struct QUIC_NO_EXPORT BufferedPacket {
BufferedPacket(std::unique_ptr<QuicReceivedPacket> packet,
QuicSocketAddress self_address,
QuicSocketAddress peer_address);
@@ -56,7 +57,7 @@ class QUIC_EXPORT_PRIVATE QuicBufferedPacketStore {
};
// A queue of BufferedPackets for a connection.
- struct QUIC_EXPORT_PRIVATE BufferedPacketList {
+ struct QUIC_NO_EXPORT BufferedPacketList {
BufferedPacketList();
BufferedPacketList(BufferedPacketList&& other);
@@ -66,13 +67,14 @@ class QUIC_EXPORT_PRIVATE QuicBufferedPacketStore {
std::list<BufferedPacket> buffered_packets;
QuicTime creation_time;
- // The alpn from the CHLO, if one was found.
- std::string alpn;
+ // The ALPNs from the CHLO, if found.
+ std::vector<std::string> alpns;
// Indicating whether this is an IETF QUIC connection.
bool ietf_quic;
// If buffered_packets contains the CHLO, it is the version of the CHLO.
// Otherwise, it is the version of the first packet in |buffered_packets|.
ParsedQuicVersion version;
+ TlsChloExtractor tls_chlo_extractor;
};
typedef QuicLinkedHashMap<QuicConnectionId,
@@ -80,7 +82,7 @@ class QUIC_EXPORT_PRIVATE QuicBufferedPacketStore {
QuicConnectionIdHash>
BufferedPacketMap;
- class QUIC_EXPORT_PRIVATE VisitorInterface {
+ class QUIC_NO_EXPORT VisitorInterface {
public:
virtual ~VisitorInterface() {}
@@ -108,12 +110,22 @@ class QUIC_EXPORT_PRIVATE QuicBufferedPacketStore {
QuicSocketAddress self_address,
QuicSocketAddress peer_address,
bool is_chlo,
- const std::string& alpn,
+ const std::vector<std::string>& alpns,
const ParsedQuicVersion& version);
// Returns true if there are any packets buffered for |connection_id|.
bool HasBufferedPackets(QuicConnectionId connection_id) const;
+ // Ingests this packet into the corresponding TlsChloExtractor. This should
+ // only be called when HasBufferedPackets(connection_id) is true.
+ // Returns whether we've now parsed a full multi-packet TLS CHLO.
+ // When this returns true, |out_alpns| is populated with the list of ALPNs
+ // extracted from the CHLO.
+ bool IngestPacketForTlsChloExtraction(const QuicConnectionId& connection_id,
+ const ParsedQuicVersion& version,
+ const QuicReceivedPacket& packet,
+ std::vector<std::string>* out_alpns);
+
// Returns the list of buffered packets for |connection_id| and removes them
// from the store. Returns an empty list if no early arrived packets for this
// connection are present.
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_buffered_packet_store_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_buffered_packet_store_test.cc
index dbf6c16e627..d99f4e0586e 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_buffered_packet_store_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_buffered_packet_store_test.cc
@@ -74,13 +74,13 @@ class QuicBufferedPacketStoreTest : public QuicTest {
TEST_F(QuicBufferedPacketStoreTest, SimpleEnqueueAndDeliverPacket) {
QuicConnectionId connection_id = TestConnectionId(1);
store_.EnqueuePacket(connection_id, false, packet_, self_address_,
- peer_address_, false, "", invalid_version_);
+ peer_address_, false, {}, invalid_version_);
EXPECT_TRUE(store_.HasBufferedPackets(connection_id));
auto packets = store_.DeliverPackets(connection_id);
const std::list<BufferedPacket>& queue = packets.buffered_packets;
ASSERT_EQ(1u, queue.size());
// The alpn should be ignored for non-chlo packets.
- ASSERT_EQ("", packets.alpn);
+ ASSERT_TRUE(packets.alpns.empty());
// There is no valid version because CHLO has not arrived.
EXPECT_EQ(invalid_version_, packets.version);
// Check content of the only packet in the queue.
@@ -97,9 +97,9 @@ TEST_F(QuicBufferedPacketStoreTest, DifferentPacketAddressOnOneConnection) {
QuicSocketAddress addr_with_new_port(QuicIpAddress::Any4(), 256);
QuicConnectionId connection_id = TestConnectionId(1);
store_.EnqueuePacket(connection_id, false, packet_, self_address_,
- peer_address_, false, "", invalid_version_);
+ peer_address_, false, {}, invalid_version_);
store_.EnqueuePacket(connection_id, false, packet_, self_address_,
- addr_with_new_port, false, "", invalid_version_);
+ addr_with_new_port, false, {}, invalid_version_);
std::list<BufferedPacket> queue =
store_.DeliverPackets(connection_id).buffered_packets;
ASSERT_EQ(2u, queue.size());
@@ -114,9 +114,9 @@ TEST_F(QuicBufferedPacketStoreTest,
for (uint64_t conn_id = 1; conn_id <= num_connections; ++conn_id) {
QuicConnectionId connection_id = TestConnectionId(conn_id);
store_.EnqueuePacket(connection_id, false, packet_, self_address_,
- peer_address_, false, "", invalid_version_);
+ peer_address_, false, {}, invalid_version_);
store_.EnqueuePacket(connection_id, false, packet_, self_address_,
- peer_address_, false, "", invalid_version_);
+ peer_address_, false, {}, invalid_version_);
}
// Deliver packets in reversed order.
@@ -138,12 +138,12 @@ TEST_F(QuicBufferedPacketStoreTest,
// keep.
EXPECT_EQ(QuicBufferedPacketStore::SUCCESS,
store_.EnqueuePacket(connection_id, false, packet_, self_address_,
- peer_address_, true, "", valid_version_));
+ peer_address_, true, {}, valid_version_));
for (size_t i = 1; i <= num_packets; ++i) {
// Only first |kDefaultMaxUndecryptablePackets packets| will be buffered.
EnqueuePacketResult result =
store_.EnqueuePacket(connection_id, false, packet_, self_address_,
- peer_address_, false, "", invalid_version_);
+ peer_address_, false, {}, invalid_version_);
if (i <= kDefaultMaxUndecryptablePackets) {
EXPECT_EQ(EnqueuePacketResult::SUCCESS, result);
} else {
@@ -165,7 +165,7 @@ TEST_F(QuicBufferedPacketStoreTest, ReachNonChloConnectionUpperLimit) {
QuicConnectionId connection_id = TestConnectionId(conn_id);
EnqueuePacketResult result =
store_.EnqueuePacket(connection_id, false, packet_, self_address_,
- peer_address_, false, "", invalid_version_);
+ peer_address_, false, {}, invalid_version_);
if (conn_id <= kMaxConnectionsWithoutCHLO) {
EXPECT_EQ(EnqueuePacketResult::SUCCESS, result);
} else {
@@ -194,7 +194,7 @@ TEST_F(QuicBufferedPacketStoreTest,
for (uint64_t conn_id = 1; conn_id <= num_chlos; ++conn_id) {
EXPECT_EQ(EnqueuePacketResult::SUCCESS,
store_.EnqueuePacket(TestConnectionId(conn_id), false, packet_,
- self_address_, peer_address_, true, "",
+ self_address_, peer_address_, true, {},
valid_version_));
}
@@ -205,7 +205,7 @@ TEST_F(QuicBufferedPacketStoreTest,
QuicConnectionId connection_id = TestConnectionId(conn_id);
EnqueuePacketResult result =
store_.EnqueuePacket(connection_id, false, packet_, self_address_,
- peer_address_, true, "", valid_version_);
+ peer_address_, true, {}, valid_version_);
if (conn_id <= kDefaultMaxConnectionsInStore) {
EXPECT_EQ(EnqueuePacketResult::SUCCESS, result);
} else {
@@ -220,7 +220,7 @@ TEST_F(QuicBufferedPacketStoreTest, EnqueueChloOnTooManyDifferentConnections) {
QuicConnectionId connection_id = TestConnectionId(conn_id);
EXPECT_EQ(EnqueuePacketResult::SUCCESS,
store_.EnqueuePacket(connection_id, false, packet_, self_address_,
- peer_address_, false, "", invalid_version_));
+ peer_address_, false, {}, invalid_version_));
}
// Buffer CHLOs on other connections till store is full.
@@ -229,7 +229,7 @@ TEST_F(QuicBufferedPacketStoreTest, EnqueueChloOnTooManyDifferentConnections) {
QuicConnectionId connection_id = TestConnectionId(i);
EnqueuePacketResult rs =
store_.EnqueuePacket(connection_id, false, packet_, self_address_,
- peer_address_, true, "", valid_version_);
+ peer_address_, true, {}, valid_version_);
if (i <= kDefaultMaxConnectionsInStore) {
EXPECT_EQ(EnqueuePacketResult::SUCCESS, rs);
EXPECT_TRUE(store_.HasChloForConnection(connection_id));
@@ -246,7 +246,7 @@ TEST_F(QuicBufferedPacketStoreTest, EnqueueChloOnTooManyDifferentConnections) {
EXPECT_EQ(EnqueuePacketResult::SUCCESS,
store_.EnqueuePacket(
/*connection_id=*/TestConnectionId(1), false, packet_,
- self_address_, peer_address_, true, "", valid_version_));
+ self_address_, peer_address_, true, {}, valid_version_));
EXPECT_TRUE(store_.HasChloForConnection(
/*connection_id=*/TestConnectionId(1)));
@@ -274,14 +274,14 @@ TEST_F(QuicBufferedPacketStoreTest, EnqueueChloOnTooManyDifferentConnections) {
TEST_F(QuicBufferedPacketStoreTest, PacketQueueExpiredBeforeDelivery) {
QuicConnectionId connection_id = TestConnectionId(1);
store_.EnqueuePacket(connection_id, false, packet_, self_address_,
- peer_address_, false, "", invalid_version_);
+ peer_address_, false, {}, invalid_version_);
EXPECT_EQ(EnqueuePacketResult::SUCCESS,
store_.EnqueuePacket(connection_id, false, packet_, self_address_,
- peer_address_, true, "", valid_version_));
+ peer_address_, true, {}, valid_version_));
QuicConnectionId connection_id2 = TestConnectionId(2);
EXPECT_EQ(EnqueuePacketResult::SUCCESS,
store_.EnqueuePacket(connection_id2, false, packet_, self_address_,
- peer_address_, false, "", invalid_version_));
+ peer_address_, false, {}, invalid_version_));
// CHLO on connection 3 arrives 1ms later.
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
@@ -290,7 +290,7 @@ TEST_F(QuicBufferedPacketStoreTest, PacketQueueExpiredBeforeDelivery) {
// connections.
QuicSocketAddress another_client_address(QuicIpAddress::Any4(), 255);
store_.EnqueuePacket(connection_id3, false, packet_, self_address_,
- another_client_address, true, "", valid_version_);
+ another_client_address, true, {}, valid_version_);
// Advance clock to the time when connection 1 and 2 expires.
clock_.AdvanceTime(
@@ -322,9 +322,9 @@ TEST_F(QuicBufferedPacketStoreTest, PacketQueueExpiredBeforeDelivery) {
// for them to expire.
QuicConnectionId connection_id4 = TestConnectionId(4);
store_.EnqueuePacket(connection_id4, false, packet_, self_address_,
- peer_address_, false, "", invalid_version_);
+ peer_address_, false, {}, invalid_version_);
store_.EnqueuePacket(connection_id4, false, packet_, self_address_,
- peer_address_, false, "", invalid_version_);
+ peer_address_, false, {}, invalid_version_);
clock_.AdvanceTime(
QuicBufferedPacketStorePeer::expiration_alarm(&store_)->deadline() -
clock_.ApproximateNow());
@@ -339,9 +339,9 @@ TEST_F(QuicBufferedPacketStoreTest, SimpleDiscardPackets) {
// Enqueue some packets
store_.EnqueuePacket(connection_id, false, packet_, self_address_,
- peer_address_, false, "", invalid_version_);
+ peer_address_, false, {}, invalid_version_);
store_.EnqueuePacket(connection_id, false, packet_, self_address_,
- peer_address_, false, "", invalid_version_);
+ peer_address_, false, {}, invalid_version_);
EXPECT_TRUE(store_.HasBufferedPackets(connection_id));
EXPECT_FALSE(store_.HasChlosBuffered());
@@ -365,11 +365,11 @@ TEST_F(QuicBufferedPacketStoreTest, DiscardWithCHLOs) {
// Enqueue some packets, which include a CHLO
store_.EnqueuePacket(connection_id, false, packet_, self_address_,
- peer_address_, false, "", invalid_version_);
+ peer_address_, false, {}, invalid_version_);
store_.EnqueuePacket(connection_id, false, packet_, self_address_,
- peer_address_, true, "", valid_version_);
+ peer_address_, true, {}, valid_version_);
store_.EnqueuePacket(connection_id, false, packet_, self_address_,
- peer_address_, false, "", invalid_version_);
+ peer_address_, false, {}, invalid_version_);
EXPECT_TRUE(store_.HasBufferedPackets(connection_id));
EXPECT_TRUE(store_.HasChlosBuffered());
@@ -394,11 +394,11 @@ TEST_F(QuicBufferedPacketStoreTest, MultipleDiscardPackets) {
// Enqueue some packets for two connection IDs
store_.EnqueuePacket(connection_id_1, false, packet_, self_address_,
- peer_address_, false, "", invalid_version_);
+ peer_address_, false, {}, invalid_version_);
store_.EnqueuePacket(connection_id_1, false, packet_, self_address_,
- peer_address_, false, "", invalid_version_);
+ peer_address_, false, {}, invalid_version_);
store_.EnqueuePacket(connection_id_2, false, packet_, self_address_,
- peer_address_, true, "h3", valid_version_);
+ peer_address_, true, {"h3"}, valid_version_);
EXPECT_TRUE(store_.HasBufferedPackets(connection_id_1));
EXPECT_TRUE(store_.HasBufferedPackets(connection_id_2));
EXPECT_TRUE(store_.HasChlosBuffered());
@@ -415,7 +415,8 @@ TEST_F(QuicBufferedPacketStoreTest, MultipleDiscardPackets) {
EXPECT_TRUE(store_.HasBufferedPackets(connection_id_2));
auto packets = store_.DeliverPackets(connection_id_2);
EXPECT_EQ(1u, packets.buffered_packets.size());
- EXPECT_EQ("h3", packets.alpn);
+ ASSERT_EQ(1u, packets.alpns.size());
+ EXPECT_EQ("h3", packets.alpns[0]);
// Since connection_id_2's chlo arrives, verify version is set.
EXPECT_EQ(valid_version_, packets.version);
EXPECT_TRUE(store_.HasChlosBuffered());
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
index 997740bf300..1949d85f79e 100644
--- 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
@@ -7,6 +7,7 @@
#include <algorithm>
#include <cstddef>
+#include <cstring>
#include <iterator>
#include <memory>
#include <ostream>
@@ -62,6 +63,16 @@ class QUIC_NO_EXPORT QuicCircularDeque {
const basic_iterator<value_type>& it) // NOLINT(runtime/explicit)
: deque_(it.deque_), index_(it.index_) {}
+ // A copy assignment if Pointee is T.
+ // A assignment from iterator to const_iterator if Pointee is const T.
+ basic_iterator& operator=(const basic_iterator<value_type>& it) {
+ if (this != &it) {
+ deque_ = it.deque_;
+ index_ = it.index_;
+ }
+ return *this;
+ }
+
reference operator*() const { return *deque_->index_to_address(index_); }
pointer operator->() const { return deque_->index_to_address(index_); }
reference operator[](difference_type i) { return *(*this + i); }
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
index 6393f5d6c8a..c18369eac9b 100644
--- 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
@@ -90,9 +90,6 @@ void QuicCoalescedPacket::Clear() {
for (auto& packet : encrypted_buffers_) {
packet.clear();
}
- if (initial_packet_ != nullptr) {
- ClearSerializedPacket(initial_packet_.get());
- }
initial_packet_ = nullptr;
}
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
index 1974f77c56b..447ab95bf68 100644
--- 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
@@ -36,6 +36,9 @@ class QUIC_EXPORT_PRIVATE QuicCoalescedPacket {
std::string ToString(size_t serialized_length) const;
+ // Returns true if this coalesced packet contains packet of |level|.
+ bool ContainsPacketOfEncryptionLevel(EncryptionLevel level) const;
+
const SerializedPacket* initial_packet() const {
return initial_packet_.get();
}
@@ -49,9 +52,6 @@ class QUIC_EXPORT_PRIVATE QuicCoalescedPacket {
QuicPacketLength max_packet_length() const { return max_packet_length_; }
private:
- // Returns true if this coalesced packet contains packet of |level|.
- bool ContainsPacketOfEncryptionLevel(EncryptionLevel level) const;
-
// self/peer addresses are set when trying to coalesce the first packet.
// Packets with different self/peer addresses cannot be coalesced.
QuicSocketAddress self_address_;
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 d0087c46f09..7c781f4def0 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
@@ -6,11 +6,13 @@
#include <algorithm>
#include <cstring>
+#include <limits>
#include <string>
#include <utility>
#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_id.h"
#include "net/third_party/quiche/src/quic/core/quic_constants.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"
@@ -58,74 +60,6 @@ QuicConfigValue::QuicConfigValue(QuicTag tag, QuicConfigPresence presence)
: tag_(tag), presence_(presence) {}
QuicConfigValue::~QuicConfigValue() {}
-QuicNegotiableValue::QuicNegotiableValue(QuicTag tag,
- QuicConfigPresence presence)
- : QuicConfigValue(tag, presence), negotiated_(false) {}
-QuicNegotiableValue::~QuicNegotiableValue() {}
-
-QuicNegotiableUint32::QuicNegotiableUint32(QuicTag tag,
- QuicConfigPresence presence)
- : QuicNegotiableValue(tag, presence),
- max_value_(0),
- default_value_(0),
- negotiated_value_(0) {}
-QuicNegotiableUint32::~QuicNegotiableUint32() {}
-
-void QuicNegotiableUint32::set(uint32_t max, uint32_t default_value) {
- DCHECK_LE(default_value, max);
- max_value_ = max;
- default_value_ = default_value;
-}
-
-uint32_t QuicNegotiableUint32::GetUint32() const {
- if (negotiated()) {
- return negotiated_value_;
- }
- return default_value_;
-}
-
-// Returns the maximum value negotiable.
-uint32_t QuicNegotiableUint32::GetMax() const {
- return max_value_;
-}
-
-void QuicNegotiableUint32::ToHandshakeMessage(
- CryptoHandshakeMessage* out) const {
- if (negotiated()) {
- out->SetValue(tag_, negotiated_value_);
- } else {
- out->SetValue(tag_, max_value_);
- }
-}
-
-QuicErrorCode QuicNegotiableUint32::ProcessPeerHello(
- const CryptoHandshakeMessage& peer_hello,
- HelloType hello_type,
- std::string* error_details) {
- DCHECK(!negotiated());
- DCHECK(error_details != nullptr);
- uint32_t value;
- QuicErrorCode error = ReadUint32(peer_hello, tag_, presence_, default_value_,
- &value, error_details);
- if (error != QUIC_NO_ERROR) {
- return error;
- }
- return ReceiveValue(value, hello_type, error_details);
-}
-
-QuicErrorCode QuicNegotiableUint32::ReceiveValue(uint32_t value,
- HelloType hello_type,
- std::string* error_details) {
- if (hello_type == SERVER && value > max_value_) {
- *error_details = "Invalid value received for " + QuicTagToString(tag_);
- return QUIC_INVALID_NEGOTIATED_VALUE;
- }
-
- set_negotiated(true);
- negotiated_value_ = std::min(value, max_value_);
- return QUIC_NO_ERROR;
-}
-
QuicFixedUint32::QuicFixedUint32(QuicTag tag, QuicConfigPresence presence)
: QuicConfigValue(tag, presence),
has_send_value_(false),
@@ -163,6 +97,11 @@ void QuicFixedUint32::SetReceivedValue(uint32_t value) {
}
void QuicFixedUint32::ToHandshakeMessage(CryptoHandshakeMessage* out) const {
+ if (tag_ == 0) {
+ QUIC_BUG
+ << "This parameter does not support writing to CryptoHandshakeMessage";
+ return;
+ }
if (has_send_value_) {
out->SetValue(tag_, send_value_);
}
@@ -173,6 +112,12 @@ QuicErrorCode QuicFixedUint32::ProcessPeerHello(
HelloType /*hello_type*/,
std::string* error_details) {
DCHECK(error_details != nullptr);
+ if (tag_ == 0) {
+ *error_details =
+ "This parameter does not support reading from CryptoHandshakeMessage";
+ QUIC_BUG << *error_details;
+ return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
+ }
QuicErrorCode error = peer_hello.GetUint32(tag_, &receive_value_);
switch (error) {
case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND:
@@ -191,6 +136,92 @@ QuicErrorCode QuicFixedUint32::ProcessPeerHello(
return error;
}
+QuicFixedUint62::QuicFixedUint62(QuicTag name, QuicConfigPresence presence)
+ : QuicConfigValue(name, presence),
+ has_send_value_(false),
+ has_receive_value_(false) {}
+
+QuicFixedUint62::~QuicFixedUint62() {}
+
+bool QuicFixedUint62::HasSendValue() const {
+ return has_send_value_;
+}
+
+uint64_t QuicFixedUint62::GetSendValue() const {
+ if (!has_send_value_) {
+ QUIC_BUG << "No send value to get for tag:" << QuicTagToString(tag_);
+ return 0;
+ }
+ return send_value_;
+}
+
+void QuicFixedUint62::SetSendValue(uint64_t value) {
+ if (value > kVarInt62MaxValue) {
+ QUIC_BUG << "QuicFixedUint62 invalid value " << value;
+ value = kVarInt62MaxValue;
+ }
+ has_send_value_ = true;
+ send_value_ = value;
+}
+
+bool QuicFixedUint62::HasReceivedValue() const {
+ return has_receive_value_;
+}
+
+uint64_t QuicFixedUint62::GetReceivedValue() const {
+ if (!has_receive_value_) {
+ QUIC_BUG << "No receive value to get for tag:" << QuicTagToString(tag_);
+ return 0;
+ }
+ return receive_value_;
+}
+
+void QuicFixedUint62::SetReceivedValue(uint64_t value) {
+ has_receive_value_ = true;
+ receive_value_ = value;
+}
+
+void QuicFixedUint62::ToHandshakeMessage(CryptoHandshakeMessage* out) const {
+ if (!has_send_value_) {
+ return;
+ }
+ uint32_t send_value32;
+ if (send_value_ > std::numeric_limits<uint32_t>::max()) {
+ QUIC_BUG << "Attempting to send " << send_value_
+ << " for tag:" << QuicTagToString(tag_);
+ send_value32 = std::numeric_limits<uint32_t>::max();
+ } else {
+ send_value32 = static_cast<uint32_t>(send_value_);
+ }
+ out->SetValue(tag_, send_value32);
+}
+
+QuicErrorCode QuicFixedUint62::ProcessPeerHello(
+ const CryptoHandshakeMessage& peer_hello,
+ HelloType /*hello_type*/,
+ std::string* error_details) {
+ DCHECK(error_details != nullptr);
+ uint32_t receive_value32;
+ QuicErrorCode error = peer_hello.GetUint32(tag_, &receive_value32);
+ // GetUint32 is guaranteed to always initialize receive_value32.
+ receive_value_ = receive_value32;
+ switch (error) {
+ case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND:
+ if (presence_ == PRESENCE_OPTIONAL) {
+ return QUIC_NO_ERROR;
+ }
+ *error_details = "Missing " + QuicTagToString(tag_);
+ break;
+ case QUIC_NO_ERROR:
+ has_receive_value_ = true;
+ break;
+ default:
+ *error_details = "Bad " + QuicTagToString(tag_);
+ break;
+ }
+ return error;
+}
+
QuicFixedUint128::QuicFixedUint128(QuicTag tag, QuicConfigPresence presence)
: QuicConfigValue(tag, presence),
has_send_value_(false),
@@ -271,7 +302,7 @@ bool QuicFixedTagVector::HasSendValues() const {
return has_send_values_;
}
-QuicTagVector QuicFixedTagVector::GetSendValues() const {
+const QuicTagVector& QuicFixedTagVector::GetSendValues() const {
QUIC_BUG_IF(!has_send_values_)
<< "No send values to get for tag:" << QuicTagToString(tag_);
return send_values_;
@@ -286,7 +317,7 @@ bool QuicFixedTagVector::HasReceivedValues() const {
return has_receive_values_;
}
-QuicTagVector QuicFixedTagVector::GetReceivedValues() const {
+const QuicTagVector& QuicFixedTagVector::GetReceivedValues() const {
QUIC_BUG_IF(!has_receive_values_)
<< "No receive value to get for tag:" << QuicTagToString(tag_);
return receive_values_;
@@ -397,13 +428,13 @@ QuicErrorCode QuicFixedSocketAddress::ProcessPeerHello(
}
QuicConfig::QuicConfig()
- : max_time_before_crypto_handshake_(QuicTime::Delta::Zero()),
+ : negotiated_(false),
+ max_time_before_crypto_handshake_(QuicTime::Delta::Zero()),
max_idle_time_before_crypto_handshake_(QuicTime::Delta::Zero()),
max_undecryptable_packets_(0),
connection_options_(kCOPT, PRESENCE_OPTIONAL),
client_connection_options_(kCLOP, PRESENCE_OPTIONAL),
- idle_network_timeout_seconds_(kICSL, PRESENCE_REQUIRED),
- silent_close_(kSCLS, PRESENCE_OPTIONAL),
+ idle_timeout_to_send_(QuicTime::Delta::Infinite()),
max_bidirectional_streams_(kMIBS, PRESENCE_REQUIRED),
max_unidirectional_streams_(kMIUS, PRESENCE_OPTIONAL),
bytes_for_connection_id_(kTCID, PRESENCE_OPTIONAL),
@@ -416,13 +447,14 @@ QuicConfig::QuicConfig()
initial_stream_flow_control_window_bytes_(kSFCW, PRESENCE_OPTIONAL),
initial_session_flow_control_window_bytes_(kCFCW, PRESENCE_OPTIONAL),
connection_migration_disabled_(kNCMR, PRESENCE_OPTIONAL),
- alternate_server_address_(kASAD, PRESENCE_OPTIONAL),
- support_max_header_list_size_(kSMHL, PRESENCE_OPTIONAL),
+ alternate_server_address_ipv6_(kASAD, PRESENCE_OPTIONAL),
+ alternate_server_address_ipv4_(kASAD, PRESENCE_OPTIONAL),
stateless_reset_token_(kSRST, PRESENCE_OPTIONAL),
max_ack_delay_ms_(kMAD, PRESENCE_OPTIONAL),
ack_delay_exponent_(kADE, PRESENCE_OPTIONAL),
max_packet_size_(0, PRESENCE_OPTIONAL),
- max_datagram_frame_size_(0, PRESENCE_OPTIONAL) {
+ max_datagram_frame_size_(0, PRESENCE_OPTIONAL),
+ active_connection_id_limit_(0, PRESENCE_OPTIONAL) {
SetDefaults();
}
@@ -450,7 +482,7 @@ bool QuicConfig::HasReceivedConnectionOptions() const {
return connection_options_.HasReceivedValues();
}
-QuicTagVector QuicConfig::ReceivedConnectionOptions() const {
+const QuicTagVector& QuicConfig::ReceivedConnectionOptions() const {
return connection_options_.GetReceivedValues();
}
@@ -458,7 +490,7 @@ bool QuicConfig::HasSendConnectionOptions() const {
return connection_options_.HasSendValues();
}
-QuicTagVector QuicConfig::SendConnectionOptions() const {
+const QuicTagVector& QuicConfig::SendConnectionOptions() const {
return connection_options_.GetSendValues();
}
@@ -493,26 +525,35 @@ bool QuicConfig::HasClientRequestedIndependentOption(
ContainsQuicTag(client_connection_options_.GetSendValues(), tag));
}
-void QuicConfig::SetIdleNetworkTimeout(
- QuicTime::Delta max_idle_network_timeout,
- QuicTime::Delta default_idle_network_timeout) {
- idle_network_timeout_seconds_.set(
- static_cast<uint32_t>(max_idle_network_timeout.ToSeconds()),
- static_cast<uint32_t>(default_idle_network_timeout.ToSeconds()));
-}
+const QuicTagVector& QuicConfig::ClientRequestedIndependentOptions(
+ Perspective perspective) const {
+ static const QuicTagVector* no_options = new QuicTagVector;
+ if (perspective == Perspective::IS_SERVER) {
+ return HasReceivedConnectionOptions() ? ReceivedConnectionOptions()
+ : *no_options;
+ }
-QuicTime::Delta QuicConfig::IdleNetworkTimeout() const {
- return QuicTime::Delta::FromSeconds(
- idle_network_timeout_seconds_.GetUint32());
+ return client_connection_options_.HasSendValues()
+ ? client_connection_options_.GetSendValues()
+ : *no_options;
}
-// TODO(ianswett) Use this for silent close on mobile, or delete.
-QUIC_UNUSED void QuicConfig::SetSilentClose(bool silent_close) {
- silent_close_.set(silent_close ? 1 : 0, silent_close ? 1 : 0);
+void QuicConfig::SetIdleNetworkTimeout(QuicTime::Delta idle_network_timeout) {
+ if (idle_network_timeout.ToMicroseconds() <= 0) {
+ QUIC_BUG << "Invalid idle network timeout " << idle_network_timeout;
+ return;
+ }
+ idle_timeout_to_send_ = idle_network_timeout;
}
-bool QuicConfig::SilentClose() const {
- return silent_close_.GetUint32() > 0;
+QuicTime::Delta QuicConfig::IdleNetworkTimeout() const {
+ // TODO(b/152032210) add a QUIC_BUG to ensure that is not called before we've
+ // received the peer's values. This is true in production code but not in all
+ // of our tests that use a fake QuicConfig.
+ if (!received_idle_timeout_.has_value()) {
+ return idle_timeout_to_send_;
+ }
+ return received_idle_timeout_.value();
}
void QuicConfig::SetMaxBidirectionalStreamsToSend(uint32_t max_streams) {
@@ -579,11 +620,11 @@ uint32_t QuicConfig::ReceivedAckDelayExponent() const {
return ack_delay_exponent_.GetReceivedValue();
}
-void QuicConfig::SetMaxPacketSizeToSend(uint32_t max_packet_size) {
+void QuicConfig::SetMaxPacketSizeToSend(uint64_t max_packet_size) {
max_packet_size_.SetSendValue(max_packet_size);
}
-uint32_t QuicConfig::GetMaxPacketSizeToSend() const {
+uint64_t QuicConfig::GetMaxPacketSizeToSend() const {
return max_packet_size_.GetSendValue();
}
@@ -591,16 +632,16 @@ bool QuicConfig::HasReceivedMaxPacketSize() const {
return max_packet_size_.HasReceivedValue();
}
-uint32_t QuicConfig::ReceivedMaxPacketSize() const {
+uint64_t QuicConfig::ReceivedMaxPacketSize() const {
return max_packet_size_.GetReceivedValue();
}
void QuicConfig::SetMaxDatagramFrameSizeToSend(
- uint32_t max_datagram_frame_size) {
+ uint64_t max_datagram_frame_size) {
max_datagram_frame_size_.SetSendValue(max_datagram_frame_size);
}
-uint32_t QuicConfig::GetMaxDatagramFrameSizeToSend() const {
+uint64_t QuicConfig::GetMaxDatagramFrameSizeToSend() const {
return max_datagram_frame_size_.GetSendValue();
}
@@ -608,10 +649,27 @@ bool QuicConfig::HasReceivedMaxDatagramFrameSize() const {
return max_datagram_frame_size_.HasReceivedValue();
}
-uint32_t QuicConfig::ReceivedMaxDatagramFrameSize() const {
+uint64_t QuicConfig::ReceivedMaxDatagramFrameSize() const {
return max_datagram_frame_size_.GetReceivedValue();
}
+void QuicConfig::SetActiveConnectionIdLimitToSend(
+ uint64_t active_connection_id_limit) {
+ active_connection_id_limit_.SetSendValue(active_connection_id_limit);
+}
+
+uint64_t QuicConfig::GetActiveConnectionIdLimitToSend() const {
+ return active_connection_id_limit_.GetSendValue();
+}
+
+bool QuicConfig::HasReceivedActiveConnectionIdLimit() const {
+ return active_connection_id_limit_.HasReceivedValue();
+}
+
+uint64_t QuicConfig::ReceivedActiveConnectionIdLimit() const {
+ return active_connection_id_limit_.GetReceivedValue();
+}
+
bool QuicConfig::HasSetBytesForConnectionIdToSend() const {
return bytes_for_connection_id_.HasSendValue();
}
@@ -628,7 +686,7 @@ uint32_t QuicConfig::ReceivedBytesForConnectionId() const {
return bytes_for_connection_id_.GetReceivedValue();
}
-void QuicConfig::SetInitialRoundTripTimeUsToSend(uint32_t rtt) {
+void QuicConfig::SetInitialRoundTripTimeUsToSend(uint64_t rtt) {
initial_round_trip_time_us_.SetSendValue(rtt);
}
@@ -636,7 +694,7 @@ bool QuicConfig::HasReceivedInitialRoundTripTimeUs() const {
return initial_round_trip_time_us_.HasReceivedValue();
}
-uint32_t QuicConfig::ReceivedInitialRoundTripTimeUs() const {
+uint64_t QuicConfig::ReceivedInitialRoundTripTimeUs() const {
return initial_round_trip_time_us_.GetReceivedValue();
}
@@ -644,12 +702,12 @@ bool QuicConfig::HasInitialRoundTripTimeUsToSend() const {
return initial_round_trip_time_us_.HasSendValue();
}
-uint32_t QuicConfig::GetInitialRoundTripTimeUsToSend() const {
+uint64_t QuicConfig::GetInitialRoundTripTimeUsToSend() const {
return initial_round_trip_time_us_.GetSendValue();
}
void QuicConfig::SetInitialStreamFlowControlWindowToSend(
- uint32_t window_bytes) {
+ uint64_t window_bytes) {
if (window_bytes < kMinimumFlowControlSendWindow) {
QUIC_BUG << "Initial stream flow control receive window (" << window_bytes
<< ") cannot be set lower than minimum ("
@@ -659,7 +717,7 @@ void QuicConfig::SetInitialStreamFlowControlWindowToSend(
initial_stream_flow_control_window_bytes_.SetSendValue(window_bytes);
}
-uint32_t QuicConfig::GetInitialStreamFlowControlWindowToSend() const {
+uint64_t QuicConfig::GetInitialStreamFlowControlWindowToSend() const {
return initial_stream_flow_control_window_bytes_.GetSendValue();
}
@@ -667,17 +725,17 @@ bool QuicConfig::HasReceivedInitialStreamFlowControlWindowBytes() const {
return initial_stream_flow_control_window_bytes_.HasReceivedValue();
}
-uint32_t QuicConfig::ReceivedInitialStreamFlowControlWindowBytes() const {
+uint64_t QuicConfig::ReceivedInitialStreamFlowControlWindowBytes() const {
return initial_stream_flow_control_window_bytes_.GetReceivedValue();
}
void QuicConfig::SetInitialMaxStreamDataBytesIncomingBidirectionalToSend(
- uint32_t window_bytes) {
+ uint64_t window_bytes) {
initial_max_stream_data_bytes_incoming_bidirectional_.SetSendValue(
window_bytes);
}
-uint32_t QuicConfig::GetInitialMaxStreamDataBytesIncomingBidirectionalToSend()
+uint64_t QuicConfig::GetInitialMaxStreamDataBytesIncomingBidirectionalToSend()
const {
if (initial_max_stream_data_bytes_incoming_bidirectional_.HasSendValue()) {
return initial_max_stream_data_bytes_incoming_bidirectional_.GetSendValue();
@@ -691,19 +749,19 @@ bool QuicConfig::HasReceivedInitialMaxStreamDataBytesIncomingBidirectional()
.HasReceivedValue();
}
-uint32_t QuicConfig::ReceivedInitialMaxStreamDataBytesIncomingBidirectional()
+uint64_t QuicConfig::ReceivedInitialMaxStreamDataBytesIncomingBidirectional()
const {
return initial_max_stream_data_bytes_incoming_bidirectional_
.GetReceivedValue();
}
void QuicConfig::SetInitialMaxStreamDataBytesOutgoingBidirectionalToSend(
- uint32_t window_bytes) {
+ uint64_t window_bytes) {
initial_max_stream_data_bytes_outgoing_bidirectional_.SetSendValue(
window_bytes);
}
-uint32_t QuicConfig::GetInitialMaxStreamDataBytesOutgoingBidirectionalToSend()
+uint64_t QuicConfig::GetInitialMaxStreamDataBytesOutgoingBidirectionalToSend()
const {
if (initial_max_stream_data_bytes_outgoing_bidirectional_.HasSendValue()) {
return initial_max_stream_data_bytes_outgoing_bidirectional_.GetSendValue();
@@ -717,18 +775,18 @@ bool QuicConfig::HasReceivedInitialMaxStreamDataBytesOutgoingBidirectional()
.HasReceivedValue();
}
-uint32_t QuicConfig::ReceivedInitialMaxStreamDataBytesOutgoingBidirectional()
+uint64_t QuicConfig::ReceivedInitialMaxStreamDataBytesOutgoingBidirectional()
const {
return initial_max_stream_data_bytes_outgoing_bidirectional_
.GetReceivedValue();
}
void QuicConfig::SetInitialMaxStreamDataBytesUnidirectionalToSend(
- uint32_t window_bytes) {
+ uint64_t window_bytes) {
initial_max_stream_data_bytes_unidirectional_.SetSendValue(window_bytes);
}
-uint32_t QuicConfig::GetInitialMaxStreamDataBytesUnidirectionalToSend() const {
+uint64_t QuicConfig::GetInitialMaxStreamDataBytesUnidirectionalToSend() const {
if (initial_max_stream_data_bytes_unidirectional_.HasSendValue()) {
return initial_max_stream_data_bytes_unidirectional_.GetSendValue();
}
@@ -739,12 +797,12 @@ bool QuicConfig::HasReceivedInitialMaxStreamDataBytesUnidirectional() const {
return initial_max_stream_data_bytes_unidirectional_.HasReceivedValue();
}
-uint32_t QuicConfig::ReceivedInitialMaxStreamDataBytesUnidirectional() const {
+uint64_t QuicConfig::ReceivedInitialMaxStreamDataBytesUnidirectional() const {
return initial_max_stream_data_bytes_unidirectional_.GetReceivedValue();
}
void QuicConfig::SetInitialSessionFlowControlWindowToSend(
- uint32_t window_bytes) {
+ uint64_t window_bytes) {
if (window_bytes < kMinimumFlowControlSendWindow) {
QUIC_BUG << "Initial session flow control receive window (" << window_bytes
<< ") cannot be set lower than default ("
@@ -754,7 +812,7 @@ void QuicConfig::SetInitialSessionFlowControlWindowToSend(
initial_session_flow_control_window_bytes_.SetSendValue(window_bytes);
}
-uint32_t QuicConfig::GetInitialSessionFlowControlWindowToSend() const {
+uint64_t QuicConfig::GetInitialSessionFlowControlWindowToSend() const {
return initial_session_flow_control_window_bytes_.GetSendValue();
}
@@ -762,7 +820,7 @@ bool QuicConfig::HasReceivedInitialSessionFlowControlWindowBytes() const {
return initial_session_flow_control_window_bytes_.HasReceivedValue();
}
-uint32_t QuicConfig::ReceivedInitialSessionFlowControlWindowBytes() const {
+uint64_t QuicConfig::ReceivedInitialSessionFlowControlWindowBytes() const {
return initial_session_flow_control_window_bytes_.GetReceivedValue();
}
@@ -774,25 +832,59 @@ bool QuicConfig::DisableConnectionMigration() const {
return connection_migration_disabled_.HasReceivedValue();
}
-void QuicConfig::SetAlternateServerAddressToSend(
- const QuicSocketAddress& alternate_server_address) {
- alternate_server_address_.SetSendValue(alternate_server_address);
+void QuicConfig::SetIPv6AlternateServerAddressToSend(
+ const QuicSocketAddress& alternate_server_address_ipv6) {
+ if (!alternate_server_address_ipv6.host().IsIPv6()) {
+ QUIC_BUG << "Cannot use SetIPv6AlternateServerAddressToSend with "
+ << alternate_server_address_ipv6;
+ return;
+ }
+ alternate_server_address_ipv6_.SetSendValue(alternate_server_address_ipv6);
+}
+
+bool QuicConfig::HasReceivedIPv6AlternateServerAddress() const {
+ return alternate_server_address_ipv6_.HasReceivedValue();
+}
+
+const QuicSocketAddress& QuicConfig::ReceivedIPv6AlternateServerAddress()
+ const {
+ return alternate_server_address_ipv6_.GetReceivedValue();
+}
+
+void QuicConfig::SetIPv4AlternateServerAddressToSend(
+ const QuicSocketAddress& alternate_server_address_ipv4) {
+ if (!alternate_server_address_ipv4.host().IsIPv4()) {
+ QUIC_BUG << "Cannot use SetIPv4AlternateServerAddressToSend with "
+ << alternate_server_address_ipv4;
+ return;
+ }
+ alternate_server_address_ipv4_.SetSendValue(alternate_server_address_ipv4);
}
-bool QuicConfig::HasReceivedAlternateServerAddress() const {
- return alternate_server_address_.HasReceivedValue();
+bool QuicConfig::HasReceivedIPv4AlternateServerAddress() const {
+ return alternate_server_address_ipv4_.HasReceivedValue();
}
-const QuicSocketAddress& QuicConfig::ReceivedAlternateServerAddress() const {
- return alternate_server_address_.GetReceivedValue();
+const QuicSocketAddress& QuicConfig::ReceivedIPv4AlternateServerAddress()
+ const {
+ return alternate_server_address_ipv4_.GetReceivedValue();
}
-void QuicConfig::SetSupportMaxHeaderListSize() {
- support_max_header_list_size_.SetSendValue(1);
+void QuicConfig::SetOriginalConnectionIdToSend(
+ const QuicConnectionId& original_connection_id) {
+ original_connection_id_to_send_ = original_connection_id;
}
-bool QuicConfig::SupportMaxHeaderListSize() const {
- return support_max_header_list_size_.HasReceivedValue();
+bool QuicConfig::HasReceivedOriginalConnectionId() const {
+ return received_original_connection_id_.has_value();
+}
+
+QuicConnectionId QuicConfig::ReceivedOriginalConnectionId() const {
+ if (!HasReceivedOriginalConnectionId()) {
+ QUIC_BUG << "No received original connection ID";
+ return EmptyQuicConnectionId();
+ }
+ return received_original_connection_id_.value();
}
void QuicConfig::SetStatelessResetTokenToSend(
@@ -809,9 +901,7 @@ QuicUint128 QuicConfig::ReceivedStatelessResetToken() const {
}
bool QuicConfig::negotiated() const {
- // TODO(ianswett): Add the negotiated parameters once and iterate over all
- // of them in negotiated, ToHandshakeMessage, and ProcessPeerHello.
- return idle_network_timeout_seconds_.negotiated();
+ return negotiated_;
}
void QuicConfig::SetCreateSessionTagIndicators(QuicTagVector tags) {
@@ -823,9 +913,7 @@ const QuicTagVector& QuicConfig::create_session_tag_indicators() const {
}
void QuicConfig::SetDefaults() {
- idle_network_timeout_seconds_.set(kMaximumIdleTimeoutSecs,
- kDefaultIdleTimeoutSecs);
- silent_close_.set(1, 0);
+ SetIdleNetworkTimeout(QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs));
SetMaxBidirectionalStreamsToSend(kDefaultMaxStreamsPerConnection);
SetMaxUnidirectionalStreamsToSend(kDefaultMaxStreamsPerConnection);
max_time_before_crypto_handshake_ =
@@ -837,7 +925,6 @@ void QuicConfig::SetDefaults() {
SetInitialStreamFlowControlWindowToSend(kMinimumFlowControlSendWindow);
SetInitialSessionFlowControlWindowToSend(kMinimumFlowControlSendWindow);
SetMaxAckDelayToSendMs(kDefaultDelayedAckTimeMs);
- SetSupportMaxHeaderListSize();
SetAckDelayExponentToSend(kDefaultAckDelayExponent);
SetMaxPacketSizeToSend(kMaxIncomingPacketSize);
SetMaxDatagramFrameSizeToSend(kMaxAcceptedDatagramFrameSize);
@@ -846,8 +933,20 @@ void QuicConfig::SetDefaults() {
void QuicConfig::ToHandshakeMessage(
CryptoHandshakeMessage* out,
QuicTransportVersion transport_version) const {
- idle_network_timeout_seconds_.ToHandshakeMessage(out);
- silent_close_.ToHandshakeMessage(out);
+ // Idle timeout has custom rules that are different from other values.
+ // We configure ourselves with the minumum value between the one sent and
+ // the one received. Additionally, when QUIC_CRYPTO is used, the server
+ // MUST send an idle timeout no greater than the idle timeout it received
+ // from the client. We therefore send the received value if it is lower.
+ QuicFixedUint32 idle_timeout_seconds(kICSL, PRESENCE_REQUIRED);
+ uint32_t idle_timeout_to_send_seconds = idle_timeout_to_send_.ToSeconds();
+ if (received_idle_timeout_.has_value() &&
+ received_idle_timeout_->ToSeconds() < idle_timeout_to_send_seconds) {
+ idle_timeout_to_send_seconds = received_idle_timeout_->ToSeconds();
+ }
+ idle_timeout_seconds.SetSendValue(idle_timeout_to_send_seconds);
+ idle_timeout_seconds.ToHandshakeMessage(out);
+
// Do not need a version check here, max...bi... will encode
// as "MIDS" -- the max initial dynamic streams tag -- if
// doing some version other than IETF QUIC.
@@ -866,8 +965,11 @@ void QuicConfig::ToHandshakeMessage(
initial_session_flow_control_window_bytes_.ToHandshakeMessage(out);
connection_migration_disabled_.ToHandshakeMessage(out);
connection_options_.ToHandshakeMessage(out);
- alternate_server_address_.ToHandshakeMessage(out);
- support_max_header_list_size_.ToHandshakeMessage(out);
+ if (alternate_server_address_ipv6_.HasSendValue()) {
+ alternate_server_address_ipv6_.ToHandshakeMessage(out);
+ } else {
+ alternate_server_address_ipv4_.ToHandshakeMessage(out);
+ }
stateless_reset_token_.ToHandshakeMessage(out);
}
@@ -879,12 +981,29 @@ QuicErrorCode QuicConfig::ProcessPeerHello(
QuicErrorCode error = QUIC_NO_ERROR;
if (error == QUIC_NO_ERROR) {
- error = idle_network_timeout_seconds_.ProcessPeerHello(
- peer_hello, hello_type, error_details);
- }
- if (error == QUIC_NO_ERROR) {
- error =
- silent_close_.ProcessPeerHello(peer_hello, hello_type, error_details);
+ // Idle timeout has custom rules that are different from other values.
+ // We configure ourselves with the minumum value between the one sent and
+ // the one received. Additionally, when QUIC_CRYPTO is used, the server
+ // MUST send an idle timeout no greater than the idle timeout it received
+ // from the client.
+ QuicFixedUint32 idle_timeout_seconds(kICSL, PRESENCE_REQUIRED);
+ error = idle_timeout_seconds.ProcessPeerHello(peer_hello, hello_type,
+ error_details);
+ if (error == QUIC_NO_ERROR) {
+ if (idle_timeout_seconds.GetReceivedValue() >
+ idle_timeout_to_send_.ToSeconds()) {
+ // The received value is higher than ours, ignore it if from the client
+ // and raise an error if from the server.
+ if (hello_type == SERVER) {
+ error = QUIC_INVALID_NEGOTIATED_VALUE;
+ *error_details =
+ "Invalid value received for " + QuicTagToString(kICSL);
+ }
+ } else {
+ received_idle_timeout_ = QuicTime::Delta::FromSeconds(
+ idle_timeout_seconds.GetReceivedValue());
+ }
+ }
}
if (error == QUIC_NO_ERROR) {
error = max_bidirectional_streams_.ProcessPeerHello(peer_hello, hello_type,
@@ -919,12 +1038,18 @@ QuicErrorCode QuicConfig::ProcessPeerHello(
error_details);
}
if (error == QUIC_NO_ERROR) {
- error = alternate_server_address_.ProcessPeerHello(peer_hello, hello_type,
- error_details);
- }
- if (error == QUIC_NO_ERROR) {
- error = support_max_header_list_size_.ProcessPeerHello(
- peer_hello, hello_type, error_details);
+ QuicFixedSocketAddress alternate_server_address(kASAD, PRESENCE_OPTIONAL);
+ error = alternate_server_address.ProcessPeerHello(peer_hello, hello_type,
+ error_details);
+ if (error == QUIC_NO_ERROR && alternate_server_address.HasReceivedValue()) {
+ const QuicSocketAddress& received_address =
+ alternate_server_address.GetReceivedValue();
+ if (received_address.host().IsIPv6()) {
+ alternate_server_address_ipv6_.SetReceivedValue(received_address);
+ } else if (received_address.host().IsIPv4()) {
+ alternate_server_address_ipv4_.SetReceivedValue(received_address);
+ }
+ }
}
if (error == QUIC_NO_ERROR) {
error = stateless_reset_token_.ProcessPeerHello(peer_hello, hello_type,
@@ -941,12 +1066,19 @@ QuicErrorCode QuicConfig::ProcessPeerHello(
error = ack_delay_exponent_.ProcessPeerHello(peer_hello, hello_type,
error_details);
}
+ if (error == QUIC_NO_ERROR) {
+ negotiated_ = true;
+ }
return error;
}
bool QuicConfig::FillTransportParameters(TransportParameters* params) const {
+ if (original_connection_id_to_send_.has_value()) {
+ params->original_connection_id = original_connection_id_to_send_.value();
+ }
+
params->idle_timeout_milliseconds.set_value(
- idle_network_timeout_seconds_.GetMax() * kNumMillisPerSecond);
+ idle_timeout_to_send_.ToMilliseconds());
if (stateless_reset_token_.HasSendValue()) {
QuicUint128 stateless_reset_token = stateless_reset_token_.GetSendValue();
@@ -985,26 +1117,50 @@ bool QuicConfig::FillTransportParameters(TransportParameters* params) const {
connection_migration_disabled_.HasSendValue() &&
connection_migration_disabled_.GetSendValue() != 0;
- if (alternate_server_address_.HasSendValue()) {
+ if (alternate_server_address_ipv6_.HasSendValue() ||
+ alternate_server_address_ipv4_.HasSendValue()) {
TransportParameters::PreferredAddress preferred_address;
- QuicSocketAddress socket_address = alternate_server_address_.GetSendValue();
- if (socket_address.host().IsIPv6()) {
- preferred_address.ipv6_socket_address = socket_address;
- } else {
- preferred_address.ipv4_socket_address = socket_address;
+ if (alternate_server_address_ipv6_.HasSendValue()) {
+ preferred_address.ipv6_socket_address =
+ alternate_server_address_ipv6_.GetSendValue();
+ }
+ if (alternate_server_address_ipv4_.HasSendValue()) {
+ preferred_address.ipv4_socket_address =
+ alternate_server_address_ipv4_.GetSendValue();
}
params->preferred_address =
std::make_unique<TransportParameters::PreferredAddress>(
preferred_address);
}
- if (!params->google_quic_params) {
- params->google_quic_params = std::make_unique<CryptoHandshakeMessage>();
+ if (active_connection_id_limit_.HasSendValue()) {
+ params->active_connection_id_limit.set_value(
+ active_connection_id_limit_.GetSendValue());
}
- silent_close_.ToHandshakeMessage(params->google_quic_params.get());
- initial_round_trip_time_us_.ToHandshakeMessage(
- params->google_quic_params.get());
- connection_options_.ToHandshakeMessage(params->google_quic_params.get());
+
+ if (GetQuicRestartFlag(quic_google_transport_param_send_new)) {
+ QUIC_RESTART_FLAG_COUNT_N(quic_google_transport_param_send_new, 1, 3);
+ if (initial_round_trip_time_us_.HasSendValue()) {
+ params->initial_round_trip_time_us.set_value(
+ initial_round_trip_time_us_.GetSendValue());
+ }
+ if (connection_options_.HasSendValues() &&
+ !connection_options_.GetSendValues().empty()) {
+ params->google_connection_options = connection_options_.GetSendValues();
+ }
+ }
+
+ if (!GetQuicRestartFlag(quic_google_transport_param_omit_old)) {
+ if (!params->google_quic_params) {
+ params->google_quic_params = std::make_unique<CryptoHandshakeMessage>();
+ }
+ initial_round_trip_time_us_.ToHandshakeMessage(
+ params->google_quic_params.get());
+ connection_options_.ToHandshakeMessage(params->google_quic_params.get());
+ } else {
+ QUIC_RESTART_FLAG_COUNT_N(quic_google_transport_param_omit_old, 1, 3);
+ }
+
params->custom_parameters = custom_transport_parameters_to_send_;
return true;
@@ -1013,25 +1169,23 @@ bool QuicConfig::FillTransportParameters(TransportParameters* params) const {
QuicErrorCode QuicConfig::ProcessTransportParameters(
const TransportParameters& params,
HelloType hello_type,
+ bool is_resumption,
std::string* error_details) {
- // Intentionally round down to probe too often rather than not often enough.
- uint64_t idle_timeout_seconds =
- params.idle_timeout_milliseconds.value() / kNumMillisPerSecond;
- // An idle timeout of zero indicates it is disabled (in other words, it is
- // set to infinity). When the idle timeout is very high, we set it to our
- // preferred maximum and still probe that often.
- if (idle_timeout_seconds > idle_network_timeout_seconds_.GetMax() ||
- idle_timeout_seconds == 0) {
- idle_timeout_seconds = idle_network_timeout_seconds_.GetMax();
- }
- QuicErrorCode error = idle_network_timeout_seconds_.ReceiveValue(
- idle_timeout_seconds, hello_type, error_details);
- if (error != QUIC_NO_ERROR) {
- DCHECK(!error_details->empty());
- return error;
- }
-
- if (!params.stateless_reset_token.empty()) {
+ if (!is_resumption && params.original_connection_id.has_value()) {
+ received_original_connection_id_ = params.original_connection_id.value();
+ }
+
+ if (params.idle_timeout_milliseconds.value() > 0 &&
+ params.idle_timeout_milliseconds.value() <
+ static_cast<uint64_t>(idle_timeout_to_send_.ToMilliseconds())) {
+ // An idle timeout of zero indicates it is disabled.
+ // We also ignore values higher than ours which will cause us to use the
+ // smallest value between ours and our peer's.
+ received_idle_timeout_ = QuicTime::Delta::FromMilliseconds(
+ params.idle_timeout_milliseconds.value());
+ }
+
+ if (!is_resumption && !params.stateless_reset_token.empty()) {
QuicUint128 stateless_reset_token;
if (params.stateless_reset_token.size() != sizeof(stateless_reset_token)) {
QUIC_BUG << "Bad stateless reset token length "
@@ -1051,12 +1205,13 @@ QuicErrorCode QuicConfig::ProcessTransportParameters(
if (params.max_datagram_frame_size.IsValid()) {
max_datagram_frame_size_.SetReceivedValue(
params.max_datagram_frame_size.value());
- // TODO(dschinazi) act on this.
}
initial_session_flow_control_window_bytes_.SetReceivedValue(
- std::min<uint64_t>(params.initial_max_data.value(),
- std::numeric_limits<uint32_t>::max()));
+ params.initial_max_data.value());
+
+ // IETF QUIC specifies stream IDs and stream counts as 62-bit integers but
+ // our implementation uses uint32_t to represent them to save memory.
max_bidirectional_streams_.SetReceivedValue(
std::min<uint64_t>(params.initial_max_streams_bidi.value(),
std::numeric_limits<uint32_t>::max()));
@@ -1071,61 +1226,79 @@ QuicErrorCode QuicConfig::ProcessTransportParameters(
// received transport parameters, so a local stream is one initiated by our
// peer, which means an incoming stream.
initial_max_stream_data_bytes_incoming_bidirectional_.SetReceivedValue(
- std::min<uint64_t>(params.initial_max_stream_data_bidi_local.value(),
- std::numeric_limits<uint32_t>::max()));
+ params.initial_max_stream_data_bidi_local.value());
initial_max_stream_data_bytes_outgoing_bidirectional_.SetReceivedValue(
- std::min<uint64_t>(params.initial_max_stream_data_bidi_remote.value(),
- std::numeric_limits<uint32_t>::max()));
+ params.initial_max_stream_data_bidi_remote.value());
initial_max_stream_data_bytes_unidirectional_.SetReceivedValue(
- std::min<uint64_t>(params.initial_max_stream_data_uni.value(),
- std::numeric_limits<uint32_t>::max()));
+ params.initial_max_stream_data_uni.value());
- if (GetQuicReloadableFlag(quic_negotiate_ack_delay_time)) {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_negotiate_ack_delay_time, 4, 4);
- max_ack_delay_ms_.SetReceivedValue(std::min<uint32_t>(
- params.max_ack_delay.value(), std::numeric_limits<uint32_t>::max()));
- }
- if (params.ack_delay_exponent.IsValid()) {
- ack_delay_exponent_.SetReceivedValue(params.ack_delay_exponent.value());
+ if (!is_resumption) {
+ if (GetQuicReloadableFlag(quic_negotiate_ack_delay_time)) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_negotiate_ack_delay_time, 4, 4);
+ max_ack_delay_ms_.SetReceivedValue(params.max_ack_delay.value());
+ }
+ if (params.ack_delay_exponent.IsValid()) {
+ ack_delay_exponent_.SetReceivedValue(params.ack_delay_exponent.value());
+ }
+ if (params.preferred_address != nullptr) {
+ if (params.preferred_address->ipv6_socket_address.port() != 0) {
+ alternate_server_address_ipv6_.SetReceivedValue(
+ params.preferred_address->ipv6_socket_address);
+ }
+ if (params.preferred_address->ipv4_socket_address.port() != 0) {
+ alternate_server_address_ipv4_.SetReceivedValue(
+ params.preferred_address->ipv4_socket_address);
+ }
+ }
}
+
if (params.disable_migration) {
connection_migration_disabled_.SetReceivedValue(1u);
}
- if (params.preferred_address != nullptr) {
- if (params.preferred_address->ipv6_socket_address.port() != 0) {
- alternate_server_address_.SetReceivedValue(
- params.preferred_address->ipv6_socket_address);
- } else if (params.preferred_address->ipv4_socket_address.port() != 0) {
- alternate_server_address_.SetReceivedValue(
- params.preferred_address->ipv4_socket_address);
- }
- }
+ active_connection_id_limit_.SetReceivedValue(
+ params.active_connection_id_limit.value());
- const CryptoHandshakeMessage* peer_params = params.google_quic_params.get();
- if (peer_params != nullptr) {
- error =
- silent_close_.ProcessPeerHello(*peer_params, hello_type, error_details);
- if (error != QUIC_NO_ERROR) {
- DCHECK(!error_details->empty());
- return error;
+ bool google_params_already_parsed = false;
+ if (GetQuicRestartFlag(quic_google_transport_param_send_new)) {
+ QUIC_RESTART_FLAG_COUNT_N(quic_google_transport_param_send_new, 2, 3);
+ if (params.initial_round_trip_time_us.value() > 0) {
+ google_params_already_parsed = true;
+ initial_round_trip_time_us_.SetReceivedValue(
+ params.initial_round_trip_time_us.value());
}
- error = initial_round_trip_time_us_.ProcessPeerHello(
- *peer_params, hello_type, error_details);
- if (error != QUIC_NO_ERROR) {
- DCHECK(!error_details->empty());
- return error;
+ if (params.google_connection_options.has_value()) {
+ google_params_already_parsed = true;
+ connection_options_.SetReceivedValues(
+ params.google_connection_options.value());
}
- error = connection_options_.ProcessPeerHello(*peer_params, hello_type,
- error_details);
- if (error != QUIC_NO_ERROR) {
- DCHECK(!error_details->empty());
- return error;
+ }
+
+ if (!GetQuicRestartFlag(quic_google_transport_param_omit_old)) {
+ const CryptoHandshakeMessage* peer_params = params.google_quic_params.get();
+ if (peer_params != nullptr && !google_params_already_parsed) {
+ QuicErrorCode error = initial_round_trip_time_us_.ProcessPeerHello(
+ *peer_params, hello_type, error_details);
+ if (error != QUIC_NO_ERROR) {
+ DCHECK(!error_details->empty());
+ return error;
+ }
+ error = connection_options_.ProcessPeerHello(*peer_params, hello_type,
+ error_details);
+ if (error != QUIC_NO_ERROR) {
+ DCHECK(!error_details->empty());
+ return error;
+ }
}
+ } else {
+ QUIC_RESTART_FLAG_COUNT_N(quic_google_transport_param_omit_old, 2, 3);
}
received_custom_transport_parameters_ = params.custom_parameters;
+ if (!is_resumption) {
+ negotiated_ = true;
+ }
*error_details = "";
return QUIC_NO_ERROR;
}
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 95a26cb0d8f..4d2bacce383 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
@@ -10,10 +10,12 @@
#include <string>
#include "net/third_party/quiche/src/quic/core/crypto/transport_parameters.h"
+#include "net/third_party/quiche/src/quic/core/quic_connection_id.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/platform/api/quic_export.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_uint128.h"
+#include "net/third_party/quiche/src/common/platform/api/quiche_optional.h"
namespace quic {
@@ -62,86 +64,62 @@ class QUIC_EXPORT_PRIVATE QuicConfigValue {
const QuicConfigPresence presence_;
};
-class QUIC_EXPORT_PRIVATE QuicNegotiableValue : public QuicConfigValue {
+// Stores uint32_t from CHLO or SHLO messages that are not negotiated.
+class QUIC_EXPORT_PRIVATE QuicFixedUint32 : public QuicConfigValue {
public:
- QuicNegotiableValue(QuicTag tag, QuicConfigPresence presence);
- ~QuicNegotiableValue() override;
-
- bool negotiated() const { return negotiated_; }
+ QuicFixedUint32(QuicTag name, QuicConfigPresence presence);
+ ~QuicFixedUint32() override;
- protected:
- void set_negotiated(bool negotiated) { negotiated_ = negotiated; }
+ bool HasSendValue() const;
- private:
- bool negotiated_;
-};
+ uint32_t GetSendValue() const;
-class QUIC_EXPORT_PRIVATE QuicNegotiableUint32 : public QuicNegotiableValue {
- // TODO(fayang): some negotiated values use uint32 as bool (e.g., silent
- // close). Consider adding a QuicNegotiableBool type.
- public:
- // Default and max values default to 0.
- QuicNegotiableUint32(QuicTag name, QuicConfigPresence presence);
- ~QuicNegotiableUint32() override;
+ void SetSendValue(uint32_t value);
- // Sets the maximum possible value that can be achieved after negotiation and
- // also the default values to be assumed if PRESENCE_OPTIONAL and the *HLO msg
- // doesn't contain a value corresponding to |name_|. |max| is serialised via
- // ToHandshakeMessage call if |negotiated_| is false.
- void set(uint32_t max, uint32_t default_value);
+ bool HasReceivedValue() const;
- // Returns the value negotiated if |negotiated_| is true, otherwise returns
- // default_value_ (used to set default values before negotiation finishes).
- uint32_t GetUint32() const;
+ uint32_t GetReceivedValue() const;
- // Returns the maximum value negotiable.
- uint32_t GetMax() const;
+ void SetReceivedValue(uint32_t value);
- // Serialises |name_| and value to |out|. If |negotiated_| is true then
- // |negotiated_value_| is serialised, otherwise |max_value_| is serialised.
+ // If has_send_value is true, serialises |tag_| and |send_value_| to |out|.
void ToHandshakeMessage(CryptoHandshakeMessage* out) const override;
- // Processes the corresponding value from |peer_hello| and if present calls
- // ReceiveValue with it. If the corresponding value is missing and
- // PRESENCE_OPTIONAL then |negotiated_value_| is set to |default_value_|.
+ // Sets |value_| to the corresponding value from |peer_hello_| if it exists.
QuicErrorCode ProcessPeerHello(const CryptoHandshakeMessage& peer_hello,
HelloType hello_type,
std::string* error_details) override;
- // Takes a value |value| parsed from a handshake message (whether a TLS
- // ClientHello/ServerHello or a CryptoHandshakeMessage) whose sender was
- // |hello_type|, and sets |negotiated_value_| to the minimum of |value| and
- // |max_value_|. On success this function returns QUIC_NO_ERROR; if there is
- // an error, details are put in |*error_details|.
- QuicErrorCode ReceiveValue(uint32_t value,
- HelloType hello_type,
- std::string* error_details);
-
private:
- uint32_t max_value_;
- uint32_t default_value_;
- uint32_t negotiated_value_;
+ uint32_t send_value_;
+ bool has_send_value_;
+ uint32_t receive_value_;
+ bool has_receive_value_;
};
-// Stores uint32_t from CHLO or SHLO messages that are not negotiated.
-class QUIC_EXPORT_PRIVATE QuicFixedUint32 : public QuicConfigValue {
+// Stores 62bit numbers from handshake messages that unilaterally shared by each
+// endpoint. IMPORTANT: these are serialized as 32-bit unsigned integers when
+// using QUIC_CRYPTO versions and CryptoHandshakeMessage.
+class QUIC_EXPORT_PRIVATE QuicFixedUint62 : public QuicConfigValue {
public:
- QuicFixedUint32(QuicTag name, QuicConfigPresence presence);
- ~QuicFixedUint32() override;
+ QuicFixedUint62(QuicTag name, QuicConfigPresence presence);
+ ~QuicFixedUint62() override;
bool HasSendValue() const;
- uint32_t GetSendValue() const;
+ uint64_t GetSendValue() const;
- void SetSendValue(uint32_t value);
+ void SetSendValue(uint64_t value);
bool HasReceivedValue() const;
- uint32_t GetReceivedValue() const;
+ uint64_t GetReceivedValue() const;
- void SetReceivedValue(uint32_t value);
+ void SetReceivedValue(uint64_t value);
// If has_send_value is true, serialises |tag_| and |send_value_| to |out|.
+ // IMPORTANT: this method serializes |send_value_| as an unsigned 32bit
+ // integer.
void ToHandshakeMessage(CryptoHandshakeMessage* out) const override;
// Sets |value_| to the corresponding value from |peer_hello_| if it exists.
@@ -150,9 +128,9 @@ class QUIC_EXPORT_PRIVATE QuicFixedUint32 : public QuicConfigValue {
std::string* error_details) override;
private:
- uint32_t send_value_;
+ uint64_t send_value_;
bool has_send_value_;
- uint32_t receive_value_;
+ uint64_t receive_value_;
bool has_receive_value_;
};
@@ -198,13 +176,13 @@ class QUIC_EXPORT_PRIVATE QuicFixedTagVector : public QuicConfigValue {
bool HasSendValues() const;
- QuicTagVector GetSendValues() const;
+ const QuicTagVector& GetSendValues() const;
void SetSendValues(const QuicTagVector& values);
bool HasReceivedValues() const;
- QuicTagVector GetReceivedValues() const;
+ const QuicTagVector& GetReceivedValues() const;
void SetReceivedValues(const QuicTagVector& values);
@@ -275,11 +253,11 @@ class QUIC_EXPORT_PRIVATE QuicConfig {
// function does nothing and returns false.
bool SetInitialReceivedConnectionOptions(const QuicTagVector& tags);
- QuicTagVector ReceivedConnectionOptions() const;
+ const QuicTagVector& ReceivedConnectionOptions() const;
bool HasSendConnectionOptions() const;
- QuicTagVector SendConnectionOptions() const;
+ const QuicTagVector& SendConnectionOptions() const;
// Returns true if the client is sending or the server has received a
// connection option.
@@ -296,14 +274,12 @@ class QUIC_EXPORT_PRIVATE QuicConfig {
bool HasClientRequestedIndependentOption(QuicTag tag,
Perspective perspective) const;
- void SetIdleNetworkTimeout(QuicTime::Delta max_idle_network_timeout,
- QuicTime::Delta default_idle_network_timeout);
-
- QuicTime::Delta IdleNetworkTimeout() const;
+ const QuicTagVector& ClientRequestedIndependentOptions(
+ Perspective perspective) const;
- void SetSilentClose(bool silent_close);
+ void SetIdleNetworkTimeout(QuicTime::Delta idle_network_timeout);
- bool SilentClose() const;
+ QuicTime::Delta IdleNetworkTimeout() const;
// Sets the max bidirectional stream count that this endpoint supports.
void SetMaxBidirectionalStreamsToSend(uint32_t max_streams);
@@ -340,10 +316,6 @@ class QUIC_EXPORT_PRIVATE QuicConfig {
return max_idle_time_before_crypto_handshake_;
}
- QuicNegotiableUint32 idle_network_timeout_seconds() const {
- return idle_network_timeout_seconds_;
- }
-
void set_max_undecryptable_packets(size_t max_undecryptable_packets) {
max_undecryptable_packets_ = max_undecryptable_packets;
}
@@ -352,89 +324,85 @@ class QUIC_EXPORT_PRIVATE QuicConfig {
return max_undecryptable_packets_;
}
+ // Peer's connection id length, in bytes. Only used in Q043 and Q046.
bool HasSetBytesForConnectionIdToSend() const;
-
- // Sets the peer's connection id length, in bytes.
void SetBytesForConnectionIdToSend(uint32_t bytes);
-
bool HasReceivedBytesForConnectionId() const;
-
uint32_t ReceivedBytesForConnectionId() const;
- // Sets an estimated initial round trip time in us.
- void SetInitialRoundTripTimeUsToSend(uint32_t rtt_us);
-
+ // Estimated initial round trip time in us.
+ void SetInitialRoundTripTimeUsToSend(uint64_t rtt_us);
bool HasReceivedInitialRoundTripTimeUs() const;
-
- uint32_t ReceivedInitialRoundTripTimeUs() const;
-
+ uint64_t ReceivedInitialRoundTripTimeUs() const;
bool HasInitialRoundTripTimeUsToSend() const;
-
- uint32_t GetInitialRoundTripTimeUsToSend() const;
+ uint64_t GetInitialRoundTripTimeUsToSend() const;
// Sets an initial stream flow control window size to transmit to the peer.
- void SetInitialStreamFlowControlWindowToSend(uint32_t window_bytes);
- uint32_t GetInitialStreamFlowControlWindowToSend() const;
+ void SetInitialStreamFlowControlWindowToSend(uint64_t window_bytes);
+ uint64_t GetInitialStreamFlowControlWindowToSend() const;
bool HasReceivedInitialStreamFlowControlWindowBytes() const;
- uint32_t ReceivedInitialStreamFlowControlWindowBytes() const;
+ uint64_t ReceivedInitialStreamFlowControlWindowBytes() const;
// Specifies the initial flow control window (max stream data) for
// incoming bidirectional streams. Incoming means streams initiated by our
// peer. If not set, GetInitialMaxStreamDataBytesIncomingBidirectionalToSend
// returns the value passed to SetInitialStreamFlowControlWindowToSend.
void SetInitialMaxStreamDataBytesIncomingBidirectionalToSend(
- uint32_t window_bytes);
- uint32_t GetInitialMaxStreamDataBytesIncomingBidirectionalToSend() const;
+ uint64_t window_bytes);
+ uint64_t GetInitialMaxStreamDataBytesIncomingBidirectionalToSend() const;
bool HasReceivedInitialMaxStreamDataBytesIncomingBidirectional() const;
- uint32_t ReceivedInitialMaxStreamDataBytesIncomingBidirectional() const;
+ uint64_t ReceivedInitialMaxStreamDataBytesIncomingBidirectional() const;
// Specifies the initial flow control window (max stream data) for
// outgoing bidirectional streams. Outgoing means streams initiated by us.
// If not set, GetInitialMaxStreamDataBytesOutgoingBidirectionalToSend
// returns the value passed to SetInitialStreamFlowControlWindowToSend.
void SetInitialMaxStreamDataBytesOutgoingBidirectionalToSend(
- uint32_t window_bytes);
- uint32_t GetInitialMaxStreamDataBytesOutgoingBidirectionalToSend() const;
+ uint64_t window_bytes);
+ uint64_t GetInitialMaxStreamDataBytesOutgoingBidirectionalToSend() const;
bool HasReceivedInitialMaxStreamDataBytesOutgoingBidirectional() const;
- uint32_t ReceivedInitialMaxStreamDataBytesOutgoingBidirectional() const;
+ uint64_t ReceivedInitialMaxStreamDataBytesOutgoingBidirectional() const;
// Specifies the initial flow control window (max stream data) for
// unidirectional streams. If not set,
// GetInitialMaxStreamDataBytesUnidirectionalToSend returns the value passed
// to SetInitialStreamFlowControlWindowToSend.
- void SetInitialMaxStreamDataBytesUnidirectionalToSend(uint32_t window_bytes);
- uint32_t GetInitialMaxStreamDataBytesUnidirectionalToSend() const;
+ void SetInitialMaxStreamDataBytesUnidirectionalToSend(uint64_t window_bytes);
+ uint64_t GetInitialMaxStreamDataBytesUnidirectionalToSend() const;
bool HasReceivedInitialMaxStreamDataBytesUnidirectional() const;
- uint32_t ReceivedInitialMaxStreamDataBytesUnidirectional() const;
+ uint64_t ReceivedInitialMaxStreamDataBytesUnidirectional() const;
// Sets an initial session flow control window size to transmit to the peer.
- void SetInitialSessionFlowControlWindowToSend(uint32_t window_bytes);
-
- uint32_t GetInitialSessionFlowControlWindowToSend() const;
-
+ void SetInitialSessionFlowControlWindowToSend(uint64_t window_bytes);
+ uint64_t GetInitialSessionFlowControlWindowToSend() const;
bool HasReceivedInitialSessionFlowControlWindowBytes() const;
+ uint64_t ReceivedInitialSessionFlowControlWindowBytes() const;
- uint32_t ReceivedInitialSessionFlowControlWindowBytes() const;
-
+ // Disable connection migration.
void SetDisableConnectionMigration();
-
bool DisableConnectionMigration() const;
- void SetAlternateServerAddressToSend(
- const QuicSocketAddress& alternate_server_address);
-
- bool HasReceivedAlternateServerAddress() const;
-
- const QuicSocketAddress& ReceivedAlternateServerAddress() const;
-
- void SetSupportMaxHeaderListSize();
-
- bool SupportMaxHeaderListSize() const;
-
+ // IPv6 alternate server address.
+ void SetIPv6AlternateServerAddressToSend(
+ const QuicSocketAddress& alternate_server_address_ipv6);
+ bool HasReceivedIPv6AlternateServerAddress() const;
+ const QuicSocketAddress& ReceivedIPv6AlternateServerAddress() const;
+
+ // IPv4 alternate server address.
+ void SetIPv4AlternateServerAddressToSend(
+ const QuicSocketAddress& alternate_server_address_ipv4);
+ bool HasReceivedIPv4AlternateServerAddress() const;
+ const QuicSocketAddress& ReceivedIPv4AlternateServerAddress() const;
+
+ // Original connection ID.
+ void SetOriginalConnectionIdToSend(
+ const QuicConnectionId& original_connection_id);
+ bool HasReceivedOriginalConnectionId() const;
+ QuicConnectionId ReceivedOriginalConnectionId() const;
+
+ // Stateless reset token.
void SetStatelessResetTokenToSend(QuicUint128 stateless_reset_token);
-
bool HasReceivedStatelessResetToken() const;
-
QuicUint128 ReceivedStatelessResetToken() const;
// Manage the IETF QUIC Max ACK Delay transport parameter.
@@ -453,16 +421,22 @@ class QUIC_EXPORT_PRIVATE QuicConfig {
uint32_t ReceivedAckDelayExponent() const;
// IETF QUIC max_packet_size transport parameter.
- void SetMaxPacketSizeToSend(uint32_t max_packet_size);
- uint32_t GetMaxPacketSizeToSend() const;
+ void SetMaxPacketSizeToSend(uint64_t max_packet_size);
+ uint64_t GetMaxPacketSizeToSend() const;
bool HasReceivedMaxPacketSize() const;
- uint32_t ReceivedMaxPacketSize() const;
+ uint64_t ReceivedMaxPacketSize() const;
// IETF QUIC max_datagram_frame_size transport parameter.
- void SetMaxDatagramFrameSizeToSend(uint32_t max_datagram_frame_size);
- uint32_t GetMaxDatagramFrameSizeToSend() const;
+ void SetMaxDatagramFrameSizeToSend(uint64_t max_datagram_frame_size);
+ uint64_t GetMaxDatagramFrameSizeToSend() const;
bool HasReceivedMaxDatagramFrameSize() const;
- uint32_t ReceivedMaxDatagramFrameSize() const;
+ uint64_t ReceivedMaxDatagramFrameSize() const;
+
+ // IETF QUIC active_connection_id_limit transport parameter.
+ void SetActiveConnectionIdLimitToSend(uint64_t active_connection_id_limit);
+ uint64_t GetActiveConnectionIdLimitToSend() const;
+ bool HasReceivedActiveConnectionIdLimit() const;
+ uint64_t ReceivedActiveConnectionIdLimit() const;
bool negotiated() const;
@@ -488,10 +462,13 @@ class QUIC_EXPORT_PRIVATE QuicConfig {
// ProcessTransportParameters reads from |params| which was received from a
// peer operating as a |hello_type|. It processes values for ICSL, MIDS, CFCW,
- // and SFCW and sets the corresponding members of this QuicConfig. On failure,
- // it returns a QuicErrorCode and puts a detailed error in |*error_details|.
+ // and SFCW and sets the corresponding members of this QuicConfig.
+ // If |is_resumption|, some configs will not be processed.
+ // On failure, it returns a QuicErrorCode and puts a detailed error in
+ // |*error_details|.
QuicErrorCode ProcessTransportParameters(const TransportParameters& params,
HelloType hello_type,
+ bool is_resumption,
std::string* error_details);
TransportParameters::ParameterMap& custom_transport_parameters_to_send() {
@@ -508,6 +485,9 @@ class QUIC_EXPORT_PRIVATE QuicConfig {
// SetDefaults sets the members to sensible, default values.
void SetDefaults();
+ // Whether we've received the peer's config.
+ bool negotiated_;
+
// Configurations options that are not negotiated.
// Maximum time the session can be alive before crypto handshake is finished.
QuicTime::Delta max_time_before_crypto_handshake_;
@@ -521,10 +501,12 @@ class QUIC_EXPORT_PRIVATE QuicConfig {
QuicFixedTagVector connection_options_;
// Connection options which only affect the client side.
QuicFixedTagVector client_connection_options_;
- // Idle network timeout in seconds.
- QuicNegotiableUint32 idle_network_timeout_seconds_;
- // Whether to use silent close. Defaults to 0 (false) and is otherwise true.
- QuicNegotiableUint32 silent_close_;
+ // Idle network timeout.
+ // Uses the max_idle_timeout transport parameter in IETF QUIC.
+ // Note that received_idle_timeout_ is only populated if we receive the
+ // peer's value, which isn't guaranteed in IETF QUIC as sending is optional.
+ QuicTime::Delta idle_timeout_to_send_;
+ quiche::QuicheOptional<QuicTime::Delta> received_idle_timeout_;
// Maximum number of dynamic streams that a Google QUIC connection
// can support or the maximum number of bidirectional streams that
// an IETF QUIC connection can support.
@@ -532,6 +514,7 @@ class QUIC_EXPORT_PRIVATE QuicConfig {
// advertising.
// The ReceivedValue is the limit on locally-created streams that
// the peer advertised.
+ // Uses the initial_max_streams_bidi transport parameter in IETF QUIC.
QuicFixedUint32 max_bidirectional_streams_;
// Maximum number of unidirectional streams that the connection can
// support.
@@ -539,36 +522,46 @@ class QUIC_EXPORT_PRIVATE QuicConfig {
// advertising.
// The ReceivedValue is the limit on locally-created streams that the peer
// advertised.
+ // Uses the initial_max_streams_uni transport parameter in IETF QUIC.
QuicFixedUint32 max_unidirectional_streams_;
- // The number of bytes required for the connection ID.
+ // The number of bytes required for the connection ID. This is only used in
+ // the legacy header format used only by Q043 at this point.
QuicFixedUint32 bytes_for_connection_id_;
// Initial round trip time estimate in microseconds.
- QuicFixedUint32 initial_round_trip_time_us_;
+ QuicFixedUint62 initial_round_trip_time_us_;
// Initial IETF QUIC stream flow control receive windows in bytes.
// Incoming bidirectional streams.
- QuicFixedUint32 initial_max_stream_data_bytes_incoming_bidirectional_;
+ // Uses the initial_max_stream_data_bidi_{local,remote} transport parameter
+ // in IETF QUIC, depending on whether we're sending or receiving.
+ QuicFixedUint62 initial_max_stream_data_bytes_incoming_bidirectional_;
// Outgoing bidirectional streams.
- QuicFixedUint32 initial_max_stream_data_bytes_outgoing_bidirectional_;
+ // Uses the initial_max_stream_data_bidi_{local,remote} transport parameter
+ // in IETF QUIC, depending on whether we're sending or receiving.
+ QuicFixedUint62 initial_max_stream_data_bytes_outgoing_bidirectional_;
// Unidirectional streams.
- QuicFixedUint32 initial_max_stream_data_bytes_unidirectional_;
+ // Uses the initial_max_stream_data_uni transport parameter in IETF QUIC.
+ QuicFixedUint62 initial_max_stream_data_bytes_unidirectional_;
// Initial Google QUIC stream flow control receive window in bytes.
- QuicFixedUint32 initial_stream_flow_control_window_bytes_;
+ QuicFixedUint62 initial_stream_flow_control_window_bytes_;
// Initial session flow control receive window in bytes.
- QuicFixedUint32 initial_session_flow_control_window_bytes_;
+ // Uses the initial_max_data transport parameter in IETF QUIC.
+ QuicFixedUint62 initial_session_flow_control_window_bytes_;
- // Whether tell peer not to attempt connection migration.
+ // Whether active connection migration is allowed.
+ // Uses the disable_active_migration transport parameter in IETF QUIC.
QuicFixedUint32 connection_migration_disabled_;
- // An alternate server address the client could connect to.
- QuicFixedSocketAddress alternate_server_address_;
-
- // Whether support HTTP/2 SETTINGS_MAX_HEADER_LIST_SIZE SETTINGS frame.
- QuicFixedUint32 support_max_header_list_size_;
+ // Alternate server addresses the client could connect to.
+ // Uses the preferred_address transport parameter in IETF QUIC.
+ // Note that when QUIC_CRYPTO is in use, only one of the addresses is sent.
+ QuicFixedSocketAddress alternate_server_address_ipv6_;
+ QuicFixedSocketAddress alternate_server_address_ipv4_;
// Stateless reset token used in IETF public reset packet.
+ // Uses the stateless_reset_token transport parameter in IETF QUIC.
QuicFixedUint128 stateless_reset_token_;
// List of QuicTags whose presence immediately causes the session to
@@ -579,20 +572,32 @@ class QUIC_EXPORT_PRIVATE QuicConfig {
// Maximum ack delay. The sent value is the value used on this node.
// The received value is the value received from the peer and used by
// the peer.
+ // Uses the max_ack_delay transport parameter in IETF QUIC.
QuicFixedUint32 max_ack_delay_ms_;
- // ack_delay_exponent parameter negotiated in IETF QUIC transport
- // parameter negotiation. The sent exponent is the exponent that this
- // node uses when serializing an ACK frame (and the peer should use when
- // deserializing the frame); the received exponent is the value the peer uses
- // to serialize frames and this node uses to deserialize them.
+ // The sent exponent is the exponent that this node uses when serializing an
+ // ACK frame (and the peer should use when deserializing the frame);
+ // the received exponent is the value the peer uses to serialize frames and
+ // this node uses to deserialize them.
+ // Uses the ack_delay_exponent transport parameter in IETF QUIC.
QuicFixedUint32 ack_delay_exponent_;
- // max_packet_size IETF QUIC transport parameter.
- QuicFixedUint32 max_packet_size_;
+ // Maximum packet size in bytes.
+ // Uses the max_packet_size transport parameter in IETF QUIC.
+ QuicFixedUint62 max_packet_size_;
+
+ // Maximum DATAGRAM/MESSAGE frame size in bytes.
+ // Uses the max_datagram_frame_size transport parameter in IETF QUIC.
+ QuicFixedUint62 max_datagram_frame_size_;
+
+ // Maximum number of connection IDs from the peer.
+ // Uses the active_connection_id_limit transport parameter in IETF QUIC.
+ QuicFixedUint62 active_connection_id_limit_;
- // max_datagram_frame_size IETF QUIC transport parameter.
- QuicFixedUint32 max_datagram_frame_size_;
+ // Sent by the server when it has previously sent a RETRY packet.
+ // Uses the original_connection_id transport parameter in IETF QUIC.
+ quiche::QuicheOptional<QuicConnectionId> original_connection_id_to_send_;
+ quiche::QuicheOptional<QuicConnectionId> received_original_connection_id_;
// Custom transport parameters that can be sent and received in the TLS
// handshake.
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 69ce78de0fd..4aa10ef40b0 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
@@ -12,6 +12,7 @@
#include "net/third_party/quiche/src/quic/core/quic_time.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_flags.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_uint128.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_config_peer.h"
@@ -21,18 +22,36 @@ namespace quic {
namespace test {
namespace {
-const uint32_t kMaxPacketSizeForTest = 1234;
-const uint32_t kMaxDatagramFrameSizeForTest = 1333;
+constexpr uint32_t kMaxPacketSizeForTest = 1234;
+constexpr uint32_t kMaxDatagramFrameSizeForTest = 1333;
+constexpr uint8_t kFakeStatelessResetTokenData[16] = {
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F};
+constexpr uint64_t kFakeAckDelayExponent = 10;
+constexpr uint64_t kFakeMaxAckDelay = 51;
+constexpr uint64_t kFakeActiveConnectionIdLimit = 52;
+
+// TODO(b/153726130): Consider merging this with methods in
+// transport_parameters_test.cc.
+std::vector<uint8_t> CreateFakeStatelessResetToken() {
+ return std::vector<uint8_t>(
+ kFakeStatelessResetTokenData,
+ kFakeStatelessResetTokenData + sizeof(kFakeStatelessResetTokenData));
+}
+
+class QuicConfigTest : public QuicTestWithParam<ParsedQuicVersion> {
+ public:
+ QuicConfigTest() : version_(GetParam()) {}
-class QuicConfigTest : public QuicTestWithParam<QuicTransportVersion> {
protected:
+ ParsedQuicVersion version_;
QuicConfig config_;
};
// Run all tests with all versions of QUIC.
INSTANTIATE_TEST_SUITE_P(QuicConfigTests,
QuicConfigTest,
- ::testing::ValuesIn(AllSupportedTransportVersions()),
+ ::testing::ValuesIn(AllSupportedVersions()),
::testing::PrintToStringParamName());
TEST_P(QuicConfigTest, SetDefaults) {
@@ -85,14 +104,17 @@ TEST_P(QuicConfigTest, AutoSetIetfFlowControl) {
}
TEST_P(QuicConfigTest, ToHandshakeMessage) {
+ if (version_.UsesTls()) {
+ // CryptoHandshakeMessage is only used for QUIC_CRYPTO.
+ return;
+ }
config_.SetInitialStreamFlowControlWindowToSend(
kInitialStreamFlowControlWindowForTest);
config_.SetInitialSessionFlowControlWindowToSend(
kInitialSessionFlowControlWindowForTest);
- config_.SetIdleNetworkTimeout(QuicTime::Delta::FromSeconds(5),
- QuicTime::Delta::FromSeconds(2));
+ config_.SetIdleNetworkTimeout(QuicTime::Delta::FromSeconds(5));
CryptoHandshakeMessage msg;
- config_.ToHandshakeMessage(&msg, GetParam());
+ config_.ToHandshakeMessage(&msg, version_.transport_version);
uint32_t value;
QuicErrorCode error = msg.GetUint32(kICSL, &value);
@@ -109,14 +131,17 @@ TEST_P(QuicConfigTest, ToHandshakeMessage) {
}
TEST_P(QuicConfigTest, ProcessClientHello) {
+ if (version_.UsesTls()) {
+ // CryptoHandshakeMessage is only used for QUIC_CRYPTO.
+ return;
+ }
const uint32_t kTestMaxAckDelayMs =
static_cast<uint32_t>(kDefaultDelayedAckTimeMs + 1);
QuicConfig client_config;
QuicTagVector cgst;
cgst.push_back(kQBIC);
client_config.SetIdleNetworkTimeout(
- QuicTime::Delta::FromSeconds(2 * kMaximumIdleTimeoutSecs),
- QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs));
+ QuicTime::Delta::FromSeconds(2 * kMaximumIdleTimeoutSecs));
client_config.SetInitialRoundTripTimeUsToSend(10 * kNumMicrosPerMilli);
client_config.SetInitialStreamFlowControlWindowToSend(
2 * kInitialStreamFlowControlWindowForTest);
@@ -127,7 +152,7 @@ TEST_P(QuicConfigTest, ProcessClientHello) {
client_config.SetConnectionOptionsToSend(copt);
client_config.SetMaxAckDelayToSendMs(kTestMaxAckDelayMs);
CryptoHandshakeMessage msg;
- client_config.ToHandshakeMessage(&msg, GetParam());
+ client_config.ToHandshakeMessage(&msg, version_.transport_version);
std::string error_details;
QuicTagVector initial_received_options;
@@ -171,6 +196,10 @@ TEST_P(QuicConfigTest, ProcessClientHello) {
}
TEST_P(QuicConfigTest, ProcessServerHello) {
+ if (version_.UsesTls()) {
+ // CryptoHandshakeMessage is only used for QUIC_CRYPTO.
+ return;
+ }
QuicIpAddress host;
host.FromString("127.0.3.1");
const QuicSocketAddress kTestServerAddress = QuicSocketAddress(host, 1234);
@@ -181,18 +210,17 @@ TEST_P(QuicConfigTest, ProcessServerHello) {
QuicTagVector cgst;
cgst.push_back(kQBIC);
server_config.SetIdleNetworkTimeout(
- QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs / 2),
QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs / 2));
server_config.SetInitialRoundTripTimeUsToSend(10 * kNumMicrosPerMilli);
server_config.SetInitialStreamFlowControlWindowToSend(
2 * kInitialStreamFlowControlWindowForTest);
server_config.SetInitialSessionFlowControlWindowToSend(
2 * kInitialSessionFlowControlWindowForTest);
- server_config.SetAlternateServerAddressToSend(kTestServerAddress);
+ server_config.SetIPv4AlternateServerAddressToSend(kTestServerAddress);
server_config.SetStatelessResetTokenToSend(kTestResetToken);
server_config.SetMaxAckDelayToSendMs(kTestMaxAckDelayMs);
CryptoHandshakeMessage msg;
- server_config.ToHandshakeMessage(&msg, GetParam());
+ server_config.ToHandshakeMessage(&msg, version_.transport_version);
std::string error_details;
const QuicErrorCode error =
config_.ProcessPeerHello(msg, SERVER, &error_details);
@@ -205,8 +233,9 @@ TEST_P(QuicConfigTest, ProcessServerHello) {
2 * kInitialStreamFlowControlWindowForTest);
EXPECT_EQ(config_.ReceivedInitialSessionFlowControlWindowBytes(),
2 * kInitialSessionFlowControlWindowForTest);
- EXPECT_TRUE(config_.HasReceivedAlternateServerAddress());
- EXPECT_EQ(kTestServerAddress, config_.ReceivedAlternateServerAddress());
+ EXPECT_TRUE(config_.HasReceivedIPv4AlternateServerAddress());
+ EXPECT_EQ(kTestServerAddress, config_.ReceivedIPv4AlternateServerAddress());
+ EXPECT_FALSE(config_.HasReceivedIPv6AlternateServerAddress());
EXPECT_TRUE(config_.HasReceivedStatelessResetToken());
EXPECT_EQ(kTestResetToken, config_.ReceivedStatelessResetToken());
if (GetQuicReloadableFlag(quic_negotiate_ack_delay_time)) {
@@ -225,6 +254,10 @@ TEST_P(QuicConfigTest, ProcessServerHello) {
}
TEST_P(QuicConfigTest, MissingOptionalValuesInCHLO) {
+ if (version_.UsesTls()) {
+ // CryptoHandshakeMessage is only used for QUIC_CRYPTO.
+ return;
+ }
CryptoHandshakeMessage msg;
msg.SetValue(kICSL, 1);
@@ -241,6 +274,10 @@ TEST_P(QuicConfigTest, MissingOptionalValuesInCHLO) {
}
TEST_P(QuicConfigTest, MissingOptionalValuesInSHLO) {
+ if (version_.UsesTls()) {
+ // CryptoHandshakeMessage is only used for QUIC_CRYPTO.
+ return;
+ }
CryptoHandshakeMessage msg;
// Set all REQUIRED tags.
@@ -256,6 +293,10 @@ TEST_P(QuicConfigTest, MissingOptionalValuesInSHLO) {
}
TEST_P(QuicConfigTest, MissingValueInCHLO) {
+ if (version_.UsesTls()) {
+ // CryptoHandshakeMessage is only used for QUIC_CRYPTO.
+ return;
+ }
// Server receives CHLO with missing kICSL.
CryptoHandshakeMessage msg;
std::string error_details;
@@ -265,6 +306,10 @@ TEST_P(QuicConfigTest, MissingValueInCHLO) {
}
TEST_P(QuicConfigTest, MissingValueInSHLO) {
+ if (version_.UsesTls()) {
+ // CryptoHandshakeMessage is only used for QUIC_CRYPTO.
+ return;
+ }
// Client receives SHLO with missing kICSL.
CryptoHandshakeMessage msg;
std::string error_details;
@@ -274,13 +319,16 @@ TEST_P(QuicConfigTest, MissingValueInSHLO) {
}
TEST_P(QuicConfigTest, OutOfBoundSHLO) {
+ if (version_.UsesTls()) {
+ // CryptoHandshakeMessage is only used for QUIC_CRYPTO.
+ return;
+ }
QuicConfig server_config;
server_config.SetIdleNetworkTimeout(
- QuicTime::Delta::FromSeconds(2 * kMaximumIdleTimeoutSecs),
QuicTime::Delta::FromSeconds(2 * kMaximumIdleTimeoutSecs));
CryptoHandshakeMessage msg;
- server_config.ToHandshakeMessage(&msg, GetParam());
+ server_config.ToHandshakeMessage(&msg, version_.transport_version);
std::string error_details;
const QuicErrorCode error =
config_.ProcessPeerHello(msg, SERVER, &error_details);
@@ -301,6 +349,10 @@ TEST_P(QuicConfigTest, InvalidFlowControlWindow) {
}
TEST_P(QuicConfigTest, HasClientSentConnectionOption) {
+ if (version_.UsesTls()) {
+ // CryptoHandshakeMessage is only used for QUIC_CRYPTO.
+ return;
+ }
QuicConfig client_config;
QuicTagVector copt;
copt.push_back(kTBBR);
@@ -309,7 +361,7 @@ TEST_P(QuicConfigTest, HasClientSentConnectionOption) {
kTBBR, Perspective::IS_CLIENT));
CryptoHandshakeMessage msg;
- client_config.ToHandshakeMessage(&msg, GetParam());
+ client_config.ToHandshakeMessage(&msg, version_.transport_version);
std::string error_details;
const QuicErrorCode error =
@@ -324,13 +376,17 @@ TEST_P(QuicConfigTest, HasClientSentConnectionOption) {
}
TEST_P(QuicConfigTest, DontSendClientConnectionOptions) {
+ if (version_.UsesTls()) {
+ // CryptoHandshakeMessage is only used for QUIC_CRYPTO.
+ return;
+ }
QuicConfig client_config;
QuicTagVector copt;
copt.push_back(kTBBR);
client_config.SetClientConnectionOptions(copt);
CryptoHandshakeMessage msg;
- client_config.ToHandshakeMessage(&msg, GetParam());
+ client_config.ToHandshakeMessage(&msg, version_.transport_version);
std::string error_details;
const QuicErrorCode error =
@@ -342,6 +398,10 @@ TEST_P(QuicConfigTest, DontSendClientConnectionOptions) {
}
TEST_P(QuicConfigTest, HasClientRequestedIndependentOption) {
+ if (version_.UsesTls()) {
+ // CryptoHandshakeMessage is only used for QUIC_CRYPTO.
+ return;
+ }
QuicConfig client_config;
QuicTagVector client_opt;
client_opt.push_back(kRENO);
@@ -357,7 +417,7 @@ TEST_P(QuicConfigTest, HasClientRequestedIndependentOption) {
kTBBR, Perspective::IS_CLIENT));
CryptoHandshakeMessage msg;
- client_config.ToHandshakeMessage(&msg, GetParam());
+ client_config.ToHandshakeMessage(&msg, version_.transport_version);
std::string error_details;
const QuicErrorCode error =
@@ -374,23 +434,30 @@ TEST_P(QuicConfigTest, HasClientRequestedIndependentOption) {
}
TEST_P(QuicConfigTest, IncomingLargeIdleTimeoutTransportParameter) {
- // Configure our default to 30s and max to 60s, then receive 120s from peer.
- // Since the received value is above the max, we should then use the max.
- config_.SetIdleNetworkTimeout(quic::QuicTime::Delta::FromSeconds(60),
- quic::QuicTime::Delta::FromSeconds(30));
+ if (!version_.UsesTls()) {
+ // TransportParameters are only used for QUIC+TLS.
+ return;
+ }
+ // Configure our idle timeout to 60s, then receive 120s from peer.
+ // Since the received value is above ours, we should then use ours.
+ config_.SetIdleNetworkTimeout(quic::QuicTime::Delta::FromSeconds(60));
TransportParameters params;
params.idle_timeout_milliseconds.set_value(120000);
std::string error_details = "foobar";
- EXPECT_THAT(
- config_.ProcessTransportParameters(params, SERVER, &error_details),
- IsQuicNoError());
+ EXPECT_THAT(config_.ProcessTransportParameters(
+ params, SERVER, /* is_resumption = */ false, &error_details),
+ IsQuicNoError());
EXPECT_EQ("", error_details);
EXPECT_EQ(quic::QuicTime::Delta::FromSeconds(60),
config_.IdleNetworkTimeout());
}
TEST_P(QuicConfigTest, FillTransportParams) {
+ if (!version_.UsesTls()) {
+ // TransportParameters are only used for QUIC+TLS.
+ return;
+ }
config_.SetInitialMaxStreamDataBytesIncomingBidirectionalToSend(
2 * kMinimumFlowControlSendWindow);
config_.SetInitialMaxStreamDataBytesOutgoingBidirectionalToSend(
@@ -399,6 +466,7 @@ TEST_P(QuicConfigTest, FillTransportParams) {
4 * kMinimumFlowControlSendWindow);
config_.SetMaxPacketSizeToSend(kMaxPacketSizeForTest);
config_.SetMaxDatagramFrameSizeToSend(kMaxDatagramFrameSizeForTest);
+ config_.SetActiveConnectionIdLimitToSend(kFakeActiveConnectionIdLimit);
TransportParameters params;
config_.FillTransportParameters(&params);
@@ -416,9 +484,16 @@ TEST_P(QuicConfigTest, FillTransportParams) {
EXPECT_EQ(kMaxPacketSizeForTest, params.max_packet_size.value());
EXPECT_EQ(kMaxDatagramFrameSizeForTest,
params.max_datagram_frame_size.value());
+ EXPECT_EQ(kFakeActiveConnectionIdLimit,
+ params.active_connection_id_limit.value());
}
TEST_P(QuicConfigTest, ProcessTransportParametersServer) {
+ if (!version_.UsesTls()) {
+ // TransportParameters are only used for QUIC+TLS.
+ return;
+ }
+ SetQuicReloadableFlag(quic_negotiate_ack_delay_time, true);
TransportParameters params;
params.initial_max_stream_data_bidi_local.set_value(
@@ -429,11 +504,19 @@ TEST_P(QuicConfigTest, ProcessTransportParametersServer) {
kMinimumFlowControlSendWindow);
params.max_packet_size.set_value(kMaxPacketSizeForTest);
params.max_datagram_frame_size.set_value(kMaxDatagramFrameSizeForTest);
+ params.initial_max_streams_bidi.set_value(kDefaultMaxStreamsPerConnection);
+ params.stateless_reset_token = CreateFakeStatelessResetToken();
+ params.max_ack_delay.set_value(kFakeMaxAckDelay);
+ params.ack_delay_exponent.set_value(kFakeAckDelayExponent);
+ params.active_connection_id_limit.set_value(kFakeActiveConnectionIdLimit);
std::string error_details;
- EXPECT_THAT(
- config_.ProcessTransportParameters(params, SERVER, &error_details),
- IsQuicNoError());
+ EXPECT_THAT(config_.ProcessTransportParameters(
+ params, SERVER, /* is_resumption = */ true, &error_details),
+ IsQuicNoError())
+ << error_details;
+
+ EXPECT_FALSE(config_.negotiated());
ASSERT_TRUE(
config_.HasReceivedInitialMaxStreamDataBytesIncomingBidirectional());
@@ -456,16 +539,89 @@ TEST_P(QuicConfigTest, ProcessTransportParametersServer) {
EXPECT_EQ(kMaxDatagramFrameSizeForTest,
config_.ReceivedMaxDatagramFrameSize());
+ ASSERT_TRUE(config_.HasReceivedMaxBidirectionalStreams());
+ EXPECT_EQ(kDefaultMaxStreamsPerConnection,
+ config_.ReceivedMaxBidirectionalStreams());
+
EXPECT_FALSE(config_.DisableConnectionMigration());
+
+ // The following config shouldn't be processed because of resumption.
+ EXPECT_FALSE(config_.HasReceivedStatelessResetToken());
+ EXPECT_FALSE(config_.HasReceivedMaxAckDelayMs());
+ EXPECT_FALSE(config_.HasReceivedAckDelayExponent());
+
+ // Let the config process another slightly tweaked transport paramters.
+ // Note that the values for flow control and stream limit cannot be smaller
+ // than before. This rule is enforced in QuicSession::OnConfigNegotiated().
+ params.initial_max_stream_data_bidi_local.set_value(
+ 2 * kMinimumFlowControlSendWindow + 1);
+ params.initial_max_stream_data_bidi_remote.set_value(
+ 4 * kMinimumFlowControlSendWindow);
+ params.initial_max_stream_data_uni.set_value(5 *
+ kMinimumFlowControlSendWindow);
+ params.max_packet_size.set_value(2 * kMaxPacketSizeForTest);
+ params.max_datagram_frame_size.set_value(2 * kMaxDatagramFrameSizeForTest);
+ params.initial_max_streams_bidi.set_value(2 *
+ kDefaultMaxStreamsPerConnection);
+ params.disable_migration = true;
+
+ EXPECT_THAT(config_.ProcessTransportParameters(
+ params, SERVER, /* is_resumption = */ false, &error_details),
+ IsQuicNoError())
+ << error_details;
+
+ EXPECT_TRUE(config_.negotiated());
+
+ ASSERT_TRUE(
+ config_.HasReceivedInitialMaxStreamDataBytesIncomingBidirectional());
+ EXPECT_EQ(2 * kMinimumFlowControlSendWindow + 1,
+ config_.ReceivedInitialMaxStreamDataBytesIncomingBidirectional());
+
+ ASSERT_TRUE(
+ config_.HasReceivedInitialMaxStreamDataBytesOutgoingBidirectional());
+ EXPECT_EQ(4 * kMinimumFlowControlSendWindow,
+ config_.ReceivedInitialMaxStreamDataBytesOutgoingBidirectional());
+
+ ASSERT_TRUE(config_.HasReceivedInitialMaxStreamDataBytesUnidirectional());
+ EXPECT_EQ(5 * kMinimumFlowControlSendWindow,
+ config_.ReceivedInitialMaxStreamDataBytesUnidirectional());
+
+ ASSERT_TRUE(config_.HasReceivedMaxPacketSize());
+ EXPECT_EQ(2 * kMaxPacketSizeForTest, config_.ReceivedMaxPacketSize());
+
+ ASSERT_TRUE(config_.HasReceivedMaxDatagramFrameSize());
+ EXPECT_EQ(2 * kMaxDatagramFrameSizeForTest,
+ config_.ReceivedMaxDatagramFrameSize());
+
+ ASSERT_TRUE(config_.HasReceivedMaxBidirectionalStreams());
+ EXPECT_EQ(2 * kDefaultMaxStreamsPerConnection,
+ config_.ReceivedMaxBidirectionalStreams());
+
+ EXPECT_TRUE(config_.DisableConnectionMigration());
+
+ ASSERT_TRUE(config_.HasReceivedStatelessResetToken());
+ ASSERT_TRUE(config_.HasReceivedMaxAckDelayMs());
+ EXPECT_EQ(config_.ReceivedMaxAckDelayMs(), kFakeMaxAckDelay);
+
+ ASSERT_TRUE(config_.HasReceivedAckDelayExponent());
+ EXPECT_EQ(config_.ReceivedAckDelayExponent(), kFakeAckDelayExponent);
+
+ ASSERT_TRUE(config_.HasReceivedActiveConnectionIdLimit());
+ EXPECT_EQ(config_.ReceivedActiveConnectionIdLimit(),
+ kFakeActiveConnectionIdLimit);
}
TEST_P(QuicConfigTest, DisableMigrationTransportParameter) {
+ if (!version_.UsesTls()) {
+ // TransportParameters are only used for QUIC+TLS.
+ return;
+ }
TransportParameters params;
params.disable_migration = true;
std::string error_details;
- EXPECT_THAT(
- config_.ProcessTransportParameters(params, SERVER, &error_details),
- IsQuicNoError());
+ EXPECT_THAT(config_.ProcessTransportParameters(
+ params, SERVER, /* is_resumption = */ false, &error_details),
+ IsQuicNoError());
EXPECT_TRUE(config_.DisableConnectionMigration());
}
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 f83dbdd8950..4f089a44fe9 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
@@ -286,9 +286,6 @@ QuicConnection::QuicConnection(
mtu_discovery_alarm_(alarm_factory_->CreateAlarm(
arena_.New<MtuDiscoveryAlarmDelegate>(this),
&arena_)),
- path_degrading_alarm_(alarm_factory_->CreateAlarm(
- arena_.New<PathDegradingAlarmDelegate>(this),
- &arena_)),
process_undecryptable_packets_alarm_(alarm_factory_->CreateAlarm(
arena_.New<ProcessUndecryptablePacketsAlarmDelegate>(this),
&arena_)),
@@ -299,6 +296,7 @@ QuicConnection::QuicConnection(
handshake_timeout_(QuicTime::Delta::Infinite()),
time_of_first_packet_sent_after_receiving_(QuicTime::Zero()),
time_of_last_received_packet_(clock_->ApproximateNow()),
+ time_of_last_decryptable_packet_(time_of_last_received_packet_),
sent_packet_manager_(perspective,
clock_,
random_generator_,
@@ -347,7 +345,9 @@ QuicConnection::QuicConnection(
<< "QuicConnection: attempted to use server connection ID "
<< server_connection_id << " which is invalid with version "
<< QuicVersionToString(transport_version());
-
+ if (advance_ack_timeout_update_) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_advance_ack_timeout_update);
+ }
framer_.set_visitor(this);
stats_.connection_creation_time = clock_->ApproximateNow();
// TODO(ianswett): Supply the NetworkChangeVisitor as a constructor argument
@@ -407,9 +407,40 @@ void QuicConnection::SetFromConfig(const QuicConfig& config) {
// Handshake complete, set handshake timeout to Infinite.
SetNetworkTimeouts(QuicTime::Delta::Infinite(),
config.IdleNetworkTimeout());
- if (config.SilentClose()) {
- idle_timeout_connection_close_behavior_ =
- ConnectionCloseBehavior::SILENT_CLOSE;
+ idle_timeout_connection_close_behavior_ =
+ ConnectionCloseBehavior::SILENT_CLOSE;
+ if (original_connection_id_.has_value()) {
+ DCHECK_EQ(perspective_, Perspective::IS_CLIENT);
+ // We received a RETRY packet, validate that the |original_connection_id|
+ // from the config matches the one from the RETRY.
+ if (!config.HasReceivedOriginalConnectionId() ||
+ config.ReceivedOriginalConnectionId() !=
+ original_connection_id_.value()) {
+ std::string received_value;
+ if (config.HasReceivedOriginalConnectionId()) {
+ received_value = config.ReceivedOriginalConnectionId().ToString();
+ } else {
+ received_value = "none";
+ }
+ std::string error_details = quiche::QuicheStrCat(
+ "Bad original_connection_id: expected ",
+ original_connection_id_.value().ToString(), ", received ",
+ received_value, ", RETRY used ", server_connection_id_.ToString());
+ CloseConnection(IETF_QUIC_PROTOCOL_VIOLATION, error_details,
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return;
+ }
+ } else {
+ // We did not receive a RETRY packet, make sure we did not receive the
+ // original_connection_id transport parameter.
+ if (config.HasReceivedOriginalConnectionId()) {
+ std::string error_details = quiche::QuicheStrCat(
+ "Bad original_connection_id: did not receive RETRY but received ",
+ config.ReceivedOriginalConnectionId().ToString());
+ CloseConnection(IETF_QUIC_PROTOCOL_VIOLATION, error_details,
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return;
+ }
}
} else {
SetNetworkTimeouts(config.max_time_before_crypto_handshake(),
@@ -466,8 +497,7 @@ void QuicConnection::SetFromConfig(const QuicConfig& config) {
framer_.set_process_timestamps(true);
uber_received_packet_manager_.set_save_timestamps(true);
}
- if (GetQuicReloadableFlag(quic_bundle_retransmittable_with_pto_ack) &&
- config.HasClientSentConnectionOption(kEACK, perspective_)) {
+ if (config.HasClientSentConnectionOption(kEACK, perspective_)) {
bundle_retransmittable_with_pto_ack_ = true;
}
if (config.HasReceivedMaxPacketSize()) {
@@ -475,6 +505,10 @@ void QuicConnection::SetFromConfig(const QuicConfig& config) {
packet_creator_.SetMaxPacketLength(
GetLimitedMaxPacketSize(packet_creator_.max_packet_length()));
}
+ if (config.HasReceivedMaxDatagramFrameSize()) {
+ packet_creator_.SetMaxDatagramFrameSize(
+ config.ReceivedMaxDatagramFrameSize());
+ }
supports_release_time_ =
writer_ != nullptr && writer_->SupportsReleaseTime() &&
@@ -485,6 +519,11 @@ void QuicConnection::SetFromConfig(const QuicConfig& config) {
}
}
+void QuicConnection::ApplyConnectionOptions(
+ const QuicTagVector& connection_options) {
+ sent_packet_manager_.ApplyConnectionOptions(connection_options);
+}
+
void QuicConnection::OnSendConnectionState(
const CachedNetworkParameters& cached_network_params) {
if (debug_visitor_ != nullptr) {
@@ -679,6 +718,8 @@ void QuicConnection::OnRetryPacket(
<< server_connection_id_ << " with " << new_connection_id
<< ", received token "
<< quiche::QuicheTextUtils::HexEncode(retry_token);
+ DCHECK(!original_connection_id_.has_value());
+ original_connection_id_ = server_connection_id_;
server_connection_id_ = new_connection_id;
packet_creator_.SetServerConnectionId(server_connection_id_);
packet_creator_.SetRetryToken(retry_token);
@@ -808,6 +849,14 @@ void QuicConnection::OnDecryptedPacket(EncryptionLevel level) {
// Address is validated by successfully processing a HANDSHAKE packet.
address_validated_ = true;
}
+ if (extend_idle_time_on_decryptable_packets_) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_extend_idle_time_on_decryptable_packets);
+ if (use_idle_network_detector_) {
+ idle_network_detector_.OnPacketReceived(time_of_last_received_packet_);
+ } else {
+ time_of_last_decryptable_packet_ = time_of_last_received_packet_;
+ }
+ }
visitor_->OnPacketDecrypted(level);
}
@@ -913,9 +962,14 @@ bool QuicConnection::OnStreamFrame(const QuicStreamFrame& frame) {
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
return false;
}
+ if (advance_ack_timeout_update_) {
+ MaybeUpdateAckTimeout();
+ }
visitor_->OnStreamFrame(frame);
stats_.stream_bytes_received += frame.data_length;
- should_last_packet_instigate_acks_ = true;
+ if (!advance_ack_timeout_update_) {
+ should_last_packet_instigate_acks_ = true;
+ }
consecutive_retransmittable_on_wire_ping_count_ = 0;
return connected_;
}
@@ -930,8 +984,13 @@ bool QuicConnection::OnCryptoFrame(const QuicCryptoFrame& frame) {
if (debug_visitor_ != nullptr) {
debug_visitor_->OnCryptoFrame(frame);
}
+ if (advance_ack_timeout_update_) {
+ MaybeUpdateAckTimeout();
+ }
visitor_->OnCryptoFrame(frame);
- should_last_packet_instigate_acks_ = true;
+ if (!advance_ack_timeout_update_) {
+ should_last_packet_instigate_acks_ = true;
+ }
return connected_;
}
@@ -1118,7 +1177,11 @@ bool QuicConnection::OnPingFrame(const QuicPingFrame& frame) {
if (debug_visitor_ != nullptr) {
debug_visitor_->OnPingFrame(frame);
}
- should_last_packet_instigate_acks_ = true;
+ if (advance_ack_timeout_update_) {
+ MaybeUpdateAckTimeout();
+ } else {
+ should_last_packet_instigate_acks_ = true;
+ }
return true;
}
@@ -1160,8 +1223,13 @@ bool QuicConnection::OnRstStreamFrame(const QuicRstStreamFrame& frame) {
<< "RST_STREAM_FRAME received for stream: " << frame.stream_id
<< " with error: "
<< QuicRstStreamErrorCodeToString(frame.error_code);
+ if (advance_ack_timeout_update_) {
+ MaybeUpdateAckTimeout();
+ }
visitor_->OnRstStream(frame);
- should_last_packet_instigate_acks_ = true;
+ if (!advance_ack_timeout_update_) {
+ should_last_packet_instigate_acks_ = true;
+ }
return connected_;
}
@@ -1192,7 +1260,11 @@ bool QuicConnection::OnPathChallengeFrame(const QuicPathChallengeFrame& frame) {
// response.
received_path_challenge_payloads_.push_back(frame.data_buffer);
- should_last_packet_instigate_acks_ = true;
+ if (advance_ack_timeout_update_) {
+ MaybeUpdateAckTimeout();
+ } else {
+ should_last_packet_instigate_acks_ = true;
+ }
return true;
}
@@ -1200,7 +1272,11 @@ bool QuicConnection::OnPathResponseFrame(const QuicPathResponseFrame& frame) {
if (debug_visitor_ != nullptr) {
debug_visitor_->OnPathResponseFrame(frame);
}
- should_last_packet_instigate_acks_ = true;
+ if (advance_ack_timeout_update_) {
+ MaybeUpdateAckTimeout();
+ } else {
+ should_last_packet_instigate_acks_ = true;
+ }
if (!transmitted_connectivity_probe_payload_ ||
*transmitted_connectivity_probe_payload_ != frame.data_buffer) {
// Is not for the probe we sent, ignore it.
@@ -1226,31 +1302,30 @@ bool QuicConnection::OnConnectionCloseFrame(
case GOOGLE_QUIC_CONNECTION_CLOSE:
QUIC_DLOG(INFO) << ENDPOINT << "Received ConnectionClose for connection: "
<< connection_id() << ", with error: "
- << QuicErrorCodeToString(frame.extracted_error_code)
- << " (" << frame.error_details << ")";
+ << QuicErrorCodeToString(frame.quic_error_code) << " ("
+ << frame.error_details << ")";
break;
case IETF_QUIC_TRANSPORT_CONNECTION_CLOSE:
QUIC_DLOG(INFO) << ENDPOINT
<< "Received Transport ConnectionClose for connection: "
<< connection_id() << ", with error: "
- << QuicErrorCodeToString(frame.extracted_error_code)
- << " (" << frame.error_details << ")"
- << ", transport error code: "
- << frame.transport_error_code << ", error frame type: "
+ << QuicErrorCodeToString(frame.quic_error_code) << " ("
+ << frame.error_details << ")"
+ << ", transport error code: " << frame.wire_error_code
+ << ", error frame type: "
<< frame.transport_close_frame_type;
break;
case IETF_QUIC_APPLICATION_CONNECTION_CLOSE:
QUIC_DLOG(INFO) << ENDPOINT
<< "Received Application ConnectionClose for connection: "
<< connection_id() << ", with error: "
- << QuicErrorCodeToString(frame.extracted_error_code)
- << " (" << frame.error_details << ")"
- << ", application error code: "
- << frame.application_error_code;
+ << QuicErrorCodeToString(frame.quic_error_code) << " ("
+ << frame.error_details << ")"
+ << ", application error code: " << frame.wire_error_code;
break;
}
- if (frame.extracted_error_code == QUIC_BAD_MULTIPATH_FLAG) {
+ if (frame.quic_error_code == QUIC_BAD_MULTIPATH_FLAG) {
QUIC_LOG_FIRST_N(ERROR, 10) << "Unexpected QUIC_BAD_MULTIPATH_FLAG error."
<< " last_received_header: " << last_header_
<< " encryption_level: " << encryption_level_;
@@ -1288,9 +1363,13 @@ bool QuicConnection::OnGoAwayFrame(const QuicGoAwayFrame& frame) {
<< frame.last_good_stream_id
<< " and error: " << QuicErrorCodeToString(frame.error_code)
<< " and reason: " << frame.reason_phrase;
-
+ if (advance_ack_timeout_update_) {
+ MaybeUpdateAckTimeout();
+ }
visitor_->OnGoAway(frame);
- should_last_packet_instigate_acks_ = true;
+ if (!advance_ack_timeout_update_) {
+ should_last_packet_instigate_acks_ = true;
+ }
return connected_;
}
@@ -1305,8 +1384,13 @@ bool QuicConnection::OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) {
debug_visitor_->OnWindowUpdateFrame(frame, GetTimeOfLastReceivedPacket());
}
QUIC_DVLOG(1) << ENDPOINT << "WINDOW_UPDATE_FRAME received " << frame;
+ if (advance_ack_timeout_update_) {
+ MaybeUpdateAckTimeout();
+ }
visitor_->OnWindowUpdateFrame(frame);
- should_last_packet_instigate_acks_ = true;
+ if (!advance_ack_timeout_update_) {
+ should_last_packet_instigate_acks_ = true;
+ }
return connected_;
}
@@ -1343,9 +1427,14 @@ bool QuicConnection::OnMessageFrame(const QuicMessageFrame& frame) {
if (debug_visitor_ != nullptr) {
debug_visitor_->OnMessageFrame(frame);
}
+ if (advance_ack_timeout_update_) {
+ MaybeUpdateAckTimeout();
+ }
visitor_->OnMessageReceived(
quiche::QuicheStringPiece(frame.data, frame.message_length));
- should_last_packet_instigate_acks_ = true;
+ if (!advance_ack_timeout_update_) {
+ should_last_packet_instigate_acks_ = true;
+ }
return connected_;
}
@@ -1366,8 +1455,13 @@ bool QuicConnection::OnHandshakeDoneFrame(const QuicHandshakeDoneFrame& frame) {
if (debug_visitor_ != nullptr) {
debug_visitor_->OnHandshakeDoneFrame(frame);
}
+ if (advance_ack_timeout_update_) {
+ MaybeUpdateAckTimeout();
+ }
visitor_->OnHandshakeDoneReceived();
- should_last_packet_instigate_acks_ = true;
+ if (!advance_ack_timeout_update_) {
+ should_last_packet_instigate_acks_ = true;
+ }
return connected_;
}
@@ -1383,9 +1477,14 @@ bool QuicConnection::OnBlockedFrame(const QuicBlockedFrame& frame) {
}
QUIC_DLOG(INFO) << ENDPOINT
<< "BLOCKED_FRAME received for stream: " << frame.stream_id;
+ if (advance_ack_timeout_update_) {
+ MaybeUpdateAckTimeout();
+ }
visitor_->OnBlockedFrame(frame);
stats_.blocked_frames_received++;
- should_last_packet_instigate_acks_ = true;
+ if (!advance_ack_timeout_update_) {
+ should_last_packet_instigate_acks_ = true;
+ }
return connected_;
}
@@ -1457,10 +1556,12 @@ void QuicConnection::OnPacketComplete() {
// For IETF QUIC, it is guaranteed that TLS will give connection the
// corresponding write key before read key. In other words, connection should
// never process a packet while an ACK for it cannot be encrypted.
- uber_received_packet_manager_.MaybeUpdateAckTimeout(
- should_last_packet_instigate_acks_, last_decrypted_packet_level_,
- last_header_.packet_number, GetTimeOfLastReceivedPacket(),
- clock_->ApproximateNow(), sent_packet_manager_.GetRttStats());
+ if (!advance_ack_timeout_update_ || !should_last_packet_instigate_acks_) {
+ uber_received_packet_manager_.MaybeUpdateAckTimeout(
+ should_last_packet_instigate_acks_, last_decrypted_packet_level_,
+ last_header_.packet_number, GetTimeOfLastReceivedPacket(),
+ clock_->ApproximateNow(), sent_packet_manager_.GetRttStats());
+ }
ClearLastFrames();
CloseIfTooManyOutstandingSentPackets();
@@ -1735,9 +1836,12 @@ void QuicConnection::OnUndecryptablePacket(const QuicEncryptedPacket& packet,
}
if (should_enqueue) {
- QueueUndecryptablePacket(packet);
- } else if (debug_visitor_ != nullptr) {
- debug_visitor_->OnUndecryptablePacket();
+ QueueUndecryptablePacket(packet, decryption_level);
+ }
+
+ if (debug_visitor_ != nullptr) {
+ debug_visitor_->OnUndecryptablePacket(decryption_level,
+ /*dropped=*/!should_enqueue);
}
}
@@ -1795,7 +1899,7 @@ void QuicConnection::ProcessUdpPacket(const QuicSocketAddress& self_address,
<< " too far from current time:"
<< clock_->ApproximateNow().ToDebuggingValue();
}
- if (use_idle_network_detector_) {
+ if (!extend_idle_time_on_decryptable_packets_ && use_idle_network_detector_) {
QUIC_RELOADABLE_FLAG_COUNT_N(quic_use_idle_network_detector, 1, 6);
idle_network_detector_.OnPacketReceived(packet.receipt_time());
} else {
@@ -2018,6 +2122,12 @@ void QuicConnection::WriteQueuedPackets() {
// TODO(wub): Reduce max packet size to a safe default, or the actual MTU.
mtu_discoverer_.Disable();
mtu_discovery_alarm_->Cancel();
+ if (GetQuicReloadableFlag(
+ quic_ignore_msg_too_big_from_buffered_packets)) {
+ QUIC_RELOADABLE_FLAG_COUNT(
+ quic_ignore_msg_too_big_from_buffered_packets);
+ buffered_packets_.pop_front();
+ }
continue;
}
if (IsWriteError(result.status)) {
@@ -2157,6 +2267,23 @@ bool QuicConnection::CanWrite(HasRetransmittableData retransmittable) {
return true;
}
+QuicTime QuicConnection::CalculatePacketSentTime() {
+ const QuicTime now = clock_->Now();
+ if (!supports_release_time_ || per_packet_options_ == nullptr) {
+ // Don't change the release delay.
+ return now;
+ }
+
+ auto next_release_time_result = sent_packet_manager_.GetNextReleaseTime();
+
+ // Release before |now| is impossible.
+ QuicTime next_release_time =
+ std::max(now, next_release_time_result.release_time);
+ per_packet_options_->release_time_delay = next_release_time - now;
+ per_packet_options_->allow_burst = next_release_time_result.allow_burst;
+ return next_release_time;
+}
+
bool QuicConnection::WritePacket(SerializedPacket* packet) {
if (ShouldDiscardPacket(*packet)) {
++stats_.packets_discarded;
@@ -2166,8 +2293,6 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) {
packet->packet_number < sent_packet_manager_.GetLargestSentPacket()) {
QUIC_BUG << "Attempt to write packet:" << packet->packet_number
<< " after:" << sent_packet_manager_.GetLargestSentPacket();
- QUIC_CLIENT_HISTOGRAM_COUNTS("QuicSession.NumQueuedPacketsAtOutOfOrder",
- buffered_packets_.size(), 1, 1000, 50, "");
CloseConnection(QUIC_INTERNAL_ERROR, "Packet written out of order.",
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
return true;
@@ -2180,7 +2305,7 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) {
// Termination packets are encrypted and saved, so don't exit early.
const bool is_termination_packet = IsTerminationPacket(*packet);
QuicPacketNumber packet_number = packet->packet_number;
- QuicPacketLength encrypted_length = packet->encrypted_length;
+ const QuicPacketLength encrypted_length = packet->encrypted_length;
// Termination packets are eventually owned by TimeWaitListManager.
// Others are deleted at the end of this call.
if (is_termination_packet) {
@@ -2213,18 +2338,7 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) {
// Measure the RTT from before the write begins to avoid underestimating the
// min_rtt_, especially in cases where the thread blocks or gets swapped out
// during the WritePacket below.
- QuicTime packet_send_time = clock_->Now();
- if (supports_release_time_ && per_packet_options_ != nullptr) {
- QuicTime next_release_time = sent_packet_manager_.GetNextReleaseTime();
- QuicTime::Delta release_time_delay = QuicTime::Delta::Zero();
- QuicTime now = packet_send_time;
- if (next_release_time > now) {
- release_time_delay = next_release_time - now;
- // Set packet_send_time to the future to make the RTT estimation accurate.
- packet_send_time = next_release_time;
- }
- per_packet_options_->release_time_delay = release_time_delay;
- }
+ QuicTime packet_send_time = CalculatePacketSentTime();
WriteResult result(WRITE_STATUS_OK, encrypted_length);
switch (fate) {
case COALESCE:
@@ -2314,8 +2428,8 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) {
// 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
+ QUIC_DVLOG(1) << ENDPOINT
+ << " MTU probe packet too big, size:" << encrypted_length
<< ", long_term_mtu_:" << long_term_mtu_;
mtu_discoverer_.Disable();
mtu_discovery_alarm_->Cancel();
@@ -2349,29 +2463,22 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) {
!is_termination_packet) {
// Start blackhole/path degrading detections if the sent packet is not
// termination packet and contains retransmittable data.
- if (use_blackhole_detector_) {
- // Do not restart detection if detection is in progress indicating no
- // forward progress has been made since last event (i.e., packet was sent
- // or new packets were acknowledged).
- if (!blackhole_detector_.IsDetectionInProgress()) {
- // Try to start detections if no detection in progress. This could
- // because either both detections are inactive when sending last packet
- // or this connection just gets out of quiescence.
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_use_blackhole_detector, 1, 4);
- blackhole_detector_.RestartDetection(GetPathDegradingDeadline(),
- GetNetworkBlackholeDeadline());
- }
- } else if (!is_path_degrading_ && !path_degrading_alarm_->IsSet()) {
- // This is the first retransmittable packet on the working path.
- // Start the path degrading alarm to detect new path degrading.
- SetPathDegradingAlarm();
+ // Do not restart detection if detection is in progress indicating no
+ // forward progress has been made since last event (i.e., packet was sent
+ // or new packets were acknowledged).
+ if (!blackhole_detector_.IsDetectionInProgress()) {
+ // Try to start detections if no detection in progress. This could
+ // because either both detections are inactive when sending last packet
+ // or this connection just gets out of quiescence.
+ blackhole_detector_.RestartDetection(GetPathDegradingDeadline(),
+ GetNetworkBlackholeDeadline());
}
if (use_idle_network_detector_) {
idle_network_detector_.OnPacketSent(packet_send_time);
QUIC_RELOADABLE_FLAG_COUNT_N(quic_use_idle_network_detector, 2, 6);
} else if (time_of_first_packet_sent_after_receiving_ <
- time_of_last_received_packet_) {
+ GetTimeOfLastReceivedPacket()) {
// Update |time_of_first_packet_sent_after_receiving_| if this is the
// first packet sent after the last packet was received. If it were
// updated on every sent packet, then sending into a black hole might
@@ -2386,7 +2493,7 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) {
if (EnforceAntiAmplificationLimit()) {
// Include bytes sent even if they are not in flight.
- bytes_sent_before_address_validation_ += packet->encrypted_length;
+ bytes_sent_before_address_validation_ += encrypted_length;
}
const bool in_flight = sent_packet_manager_.OnPacketSent(
@@ -2474,12 +2581,10 @@ bool QuicConnection::ShouldDiscardPacket(const SerializedPacket& packet) {
}
bool QuicConnection::ShouldIgnoreWriteError() {
- if (!GetQuicReloadableFlag(quic_ignore_one_write_error_after_mtu_probe) ||
- previous_validated_mtu_ == 0) {
+ if (previous_validated_mtu_ == 0) {
return false;
}
- QUIC_CODE_COUNT(quic_ignore_one_write_error_after_mtu_probe);
SetMaxPacketLength(previous_validated_mtu_);
mtu_discoverer_.Disable();
mtu_discovery_alarm_->Cancel();
@@ -2524,8 +2629,8 @@ char* QuicConnection::GetPacketBuffer() {
return writer_->GetNextWriteLocation(self_address().host(), peer_address());
}
-void QuicConnection::OnSerializedPacket(SerializedPacket* serialized_packet) {
- if (serialized_packet->encrypted_buffer == nullptr) {
+void QuicConnection::OnSerializedPacket(SerializedPacket serialized_packet) {
+ if (serialized_packet.encrypted_buffer == nullptr) {
// We failed to serialize the packet, so close the connection.
// Specify that the close is silent, that no packet be sent, so no infinite
// loop here.
@@ -2544,14 +2649,14 @@ void QuicConnection::OnSerializedPacket(SerializedPacket* serialized_packet) {
return;
}
- if (serialized_packet->retransmittable_frames.empty()) {
+ 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_;
} else {
consecutive_num_packets_with_no_retransmittable_frames_ = 0;
}
- SendOrQueuePacket(serialized_packet);
+ SendOrQueuePacket(std::move(serialized_packet));
}
void QuicConnection::OnUnrecoverableError(QuicErrorCode error,
@@ -2610,14 +2715,9 @@ void QuicConnection::OnHandshakeComplete() {
kAlarmGranularity);
}
-void QuicConnection::SendOrQueuePacket(SerializedPacket* packet) {
+void QuicConnection::SendOrQueuePacket(SerializedPacket packet) {
// The caller of this function is responsible for checking CanWrite().
- if (packet->encrypted_buffer == nullptr) {
- QUIC_BUG << "packet.encrypted_buffer == nullptr in to SendOrQueuePacket";
- return;
- }
- WritePacket(packet);
- ClearSerializedPacket(packet);
+ WritePacket(&packet);
}
void QuicConnection::OnPingTimeout() {
@@ -2668,28 +2768,6 @@ void QuicConnection::OnRetransmissionTimeout() {
QuicPacketNumber previous_created_packet_number =
packet_creator_.packet_number();
- if (!use_blackhole_detector_) {
- if (close_connection_after_five_rtos_ &&
- sent_packet_manager_.GetConsecutiveRtoCount() >= 4) {
- // Close on the 5th consecutive RTO, so after 4 previous RTOs have
- // occurred.
- CloseConnection(QUIC_TOO_MANY_RTOS,
- "5 consecutive retransmission timeouts",
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- return;
- }
- if (sent_packet_manager_.pto_enabled() && max_consecutive_ptos_ > 0 &&
- sent_packet_manager_.GetConsecutivePtoCount() >=
- max_consecutive_ptos_) {
- CloseConnection(
- QUIC_TOO_MANY_RTOS,
- quiche::QuicheStrCat(max_consecutive_ptos_ + 1,
- "consecutive retransmission timeouts"),
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- return;
- }
- }
-
const auto retransmission_mode =
sent_packet_manager_.OnRetransmissionTimeout();
if (sent_packet_manager_.skip_packet_number_for_pto() &&
@@ -2701,10 +2779,7 @@ void QuicConnection::OnRetransmissionTimeout() {
packet_creator_.SkipNPacketNumbers(
num_packet_numbers_to_skip, sent_packet_manager_.GetLeastUnacked(),
sent_packet_manager_.EstimateMaxPacketsInFlight(max_packet_length()));
- if (GetQuicReloadableFlag(quic_send_ping_when_pto_skips_packet_number)) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_send_ping_when_pto_skips_packet_number);
- previous_created_packet_number += num_packet_numbers_to_skip;
- }
+ previous_created_packet_number += num_packet_numbers_to_skip;
if (debug_visitor_ != nullptr) {
debug_visitor_->OnNPacketNumbersSkipped(num_packet_numbers_to_skip);
}
@@ -2840,16 +2915,17 @@ const QuicDecrypter* QuicConnection::alternative_decrypter() const {
}
void QuicConnection::QueueUndecryptablePacket(
- const QuicEncryptedPacket& packet) {
+ const QuicEncryptedPacket& packet,
+ EncryptionLevel decryption_level) {
for (const auto& saved_packet : undecryptable_packets_) {
- if (packet.data() == saved_packet->data() &&
- packet.length() == saved_packet->length()) {
+ if (packet.data() == saved_packet.packet->data() &&
+ packet.length() == saved_packet.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());
+ undecryptable_packets_.emplace_back(packet, decryption_level);
}
void QuicConnection::MaybeProcessUndecryptablePackets() {
@@ -2868,8 +2944,12 @@ void QuicConnection::MaybeProcessUndecryptablePackets() {
return;
}
QUIC_DVLOG(1) << ENDPOINT << "Attempting to process undecryptable packet";
- QuicEncryptedPacket* packet = undecryptable_packets_.front().get();
- if (!framer_.ProcessPacket(*packet) &&
+ const auto& undecryptable_packet = undecryptable_packets_.front();
+ if (debug_visitor_ != nullptr) {
+ debug_visitor_->OnAttemptingToProcessUndecryptablePacket(
+ undecryptable_packet.encryption_level);
+ }
+ if (!framer_.ProcessPacket(*undecryptable_packet.packet) &&
framer_.error() == QUIC_DECRYPTION_FAILURE) {
QUIC_DVLOG(1) << ENDPOINT << "Unable to process undecryptable packet...";
break;
@@ -2884,11 +2964,9 @@ void QuicConnection::MaybeProcessUndecryptablePackets() {
// never be able to be decrypted.
if (encryption_level_ == ENCRYPTION_FORWARD_SECURE) {
if (debug_visitor_ != nullptr) {
- // TODO(rtenneti): perhaps more efficient to pass the number of
- // undecryptable packets as the argument to OnUndecryptablePacket so that
- // we just need to call OnUndecryptablePacket once?
- for (size_t i = 0; i < undecryptable_packets_.size(); ++i) {
- debug_visitor_->OnUndecryptablePacket();
+ for (const auto& undecryptable_packet : undecryptable_packets_) {
+ debug_visitor_->OnUndecryptablePacket(
+ undecryptable_packet.encryption_level, /*dropped=*/true);
}
}
undecryptable_packets_.clear();
@@ -3064,12 +3142,8 @@ void QuicConnection::CancelAllAlarms() {
send_alarm_->Cancel();
timeout_alarm_->Cancel();
mtu_discovery_alarm_->Cancel();
- path_degrading_alarm_->Cancel();
process_undecryptable_packets_alarm_->Cancel();
- if (use_blackhole_detector_) {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_use_blackhole_detector, 4, 4);
- blackhole_detector_.StopDetection();
- }
+ blackhole_detector_.StopDetection();
if (use_idle_network_detector_) {
QUIC_RELOADABLE_FLAG_COUNT_N(quic_use_idle_network_detector, 3, 6);
idle_network_detector_.StopDetection();
@@ -3151,7 +3225,7 @@ void QuicConnection::CheckForTimeout() {
}
QuicTime time_of_last_packet =
- std::max(time_of_last_received_packet_,
+ std::max(GetTimeOfLastReceivedPacket(),
time_of_first_packet_sent_after_receiving_);
// |delta| can be < 0 as |now| is approximate time but |time_of_last_packet|
@@ -3187,7 +3261,7 @@ void QuicConnection::CheckForTimeout() {
void QuicConnection::SetTimeoutAlarm() {
DCHECK(!use_idle_network_detector_);
QuicTime time_of_last_packet =
- std::max(time_of_last_received_packet_,
+ std::max(GetTimeOfLastReceivedPacket(),
time_of_first_packet_sent_after_receiving_);
QuicTime deadline = time_of_last_packet + idle_network_timeout_;
@@ -3270,16 +3344,6 @@ void QuicConnection::SetRetransmissionAlarm() {
kAlarmGranularity);
}
-void QuicConnection::SetPathDegradingAlarm() {
- DCHECK(!use_blackhole_detector_);
- if (perspective_ == Perspective::IS_SERVER) {
- return;
- }
- const QuicTime::Delta delay = sent_packet_manager_.GetPathDegradingDelay();
- path_degrading_alarm_->Update(clock_->ApproximateNow() + delay,
- kAlarmGranularity);
-}
-
void QuicConnection::MaybeSetMtuAlarm(QuicPacketNumber sent_packet_number) {
if (mtu_discovery_alarm_->IsSet() ||
!mtu_discoverer_.ShouldProbeMtu(sent_packet_number)) {
@@ -3505,7 +3569,7 @@ bool QuicConnection::SendGenericPathProbePacket(
<< "Sending path probe packet for connection_id = "
<< server_connection_id_;
- OwningSerializedPacketPointer probing_packet;
+ std::unique_ptr<SerializedPacket> probing_packet;
if (!version().HasIetfQuicFrames()) {
// Non-IETF QUIC, generate a padded ping regardless of whether this is a
// request or a response.
@@ -3788,32 +3852,31 @@ void QuicConnection::UpdatePacketContent(PacketContent type) {
void QuicConnection::PostProcessAfterAckFrame(bool send_stop_waiting,
bool acked_new_packet) {
if (no_stop_waiting_frames_) {
- uber_received_packet_manager_.DontWaitForPacketsBefore(
- last_decrypted_packet_level_,
- SupportsMultiplePacketNumberSpaces()
- ? sent_packet_manager_.GetLargestPacketPeerKnowsIsAcked(
- last_decrypted_packet_level_)
- : sent_packet_manager_.largest_packet_peer_knows_is_acked());
+ if (GetQuicReloadableFlag(quic_donot_change_queued_ack) &&
+ packet_creator_.has_ack()) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_donot_change_queued_ack);
+ } else {
+ uber_received_packet_manager_.DontWaitForPacketsBefore(
+ last_decrypted_packet_level_,
+ SupportsMultiplePacketNumberSpaces()
+ ? sent_packet_manager_.GetLargestPacketPeerKnowsIsAcked(
+ last_decrypted_packet_level_)
+ : sent_packet_manager_.largest_packet_peer_knows_is_acked());
+ }
}
// Always reset the retransmission alarm when an ack comes in, since we now
// have a better estimate of the current rtt than when it was set.
SetRetransmissionAlarm();
- if (use_blackhole_detector_) {
- if (acked_new_packet) {
- is_path_degrading_ = false;
- if (sent_packet_manager_.HasInFlightPackets()) {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_use_blackhole_detector, 2, 4);
- // Restart detections if forward progress has been made.
- blackhole_detector_.RestartDetection(GetPathDegradingDeadline(),
- GetNetworkBlackholeDeadline());
- } else {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_use_blackhole_detector, 3, 4);
- // Stop detections in quiecense.
- blackhole_detector_.StopDetection();
- }
+ if (acked_new_packet) {
+ is_path_degrading_ = false;
+ if (sent_packet_manager_.HasInFlightPackets()) {
+ // Restart detections if forward progress has been made.
+ blackhole_detector_.RestartDetection(GetPathDegradingDeadline(),
+ GetNetworkBlackholeDeadline());
+ } else {
+ // Stop detections in quiecense.
+ blackhole_detector_.StopDetection();
}
- } else {
- MaybeSetPathDegradingAlarm(acked_new_packet);
}
if (send_stop_waiting) {
@@ -3823,21 +3886,6 @@ void QuicConnection::PostProcessAfterAckFrame(bool send_stop_waiting,
}
}
-void QuicConnection::MaybeSetPathDegradingAlarm(bool acked_new_packet) {
- DCHECK(!use_blackhole_detector_);
- if (!sent_packet_manager_.HasInFlightPackets()) {
- // There are no retransmittable packets on the wire, so it's impossible to
- // say if the connection has degraded.
- path_degrading_alarm_->Cancel();
- } else if (acked_new_packet) {
- // A previously-unacked packet has been acked, which means forward progress
- // has been made. Unset |is_path_degrading| if the path was considered as
- // degrading previously. Set/update the path degrading alarm.
- is_path_degrading_ = false;
- SetPathDegradingAlarm();
- }
-}
-
void QuicConnection::SetSessionNotifier(
SessionNotifierInterface* session_notifier) {
sent_packet_manager_.SetSessionNotifier(session_notifier);
@@ -3855,6 +3903,7 @@ void QuicConnection::SetTransmissionType(TransmissionType type) {
void QuicConnection::UpdateReleaseTimeIntoFuture() {
DCHECK(supports_release_time_);
+ const QuicTime::Delta prior_max_release_time = release_time_into_future_;
release_time_into_future_ = std::max(
QuicTime::Delta::FromMilliseconds(kMinReleaseTimeIntoFutureMs),
std::min(
@@ -3862,6 +3911,9 @@ void QuicConnection::UpdateReleaseTimeIntoFuture() {
GetQuicFlag(FLAGS_quic_max_pace_time_into_future_ms)),
sent_packet_manager_.GetRttStats()->SmoothedOrInitialRtt() *
GetQuicFlag(FLAGS_quic_pace_time_into_future_srtt_fraction)));
+ QUIC_DVLOG(3) << "Updated max release time delay from "
+ << prior_max_release_time << " to "
+ << release_time_into_future_;
}
void QuicConnection::ResetAckStates() {
@@ -3998,7 +4050,6 @@ bool QuicConnection::ShouldBundleRetransmittableFrameWithAck() const {
if (bundle_retransmittable_with_pto_ack_ &&
(sent_packet_manager_.GetConsecutiveRtoCount() > 0 ||
sent_packet_manager_.GetConsecutivePtoCount() > 0)) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_bundle_retransmittable_with_pto_ack);
// Bundle a retransmittable frame with an ACK if the PTO or RTO has fired
// in order to recover more quickly in cases of temporary network outage.
return true;
@@ -4032,6 +4083,12 @@ bool QuicConnection::FlushCoalescedPacket() {
if (debug_visitor_ != nullptr) {
debug_visitor_->OnCoalescedPacketSent(coalesced_packet_, length);
}
+ if (coalesced_packet_.ContainsPacketOfEncryptionLevel(
+ ENCRYPTION_HANDSHAKE)) {
+ // This is only called in coalescer because all ENCRYPTION_HANDSHAKE
+ // packets go through the coalescer.
+ visitor_->OnHandshakePacketSent();
+ }
return true;
}
@@ -4055,6 +4112,11 @@ bool QuicConnection::FlushCoalescedPacket() {
if (debug_visitor_ != nullptr) {
debug_visitor_->OnCoalescedPacketSent(coalesced_packet_, length);
}
+ if (coalesced_packet_.ContainsPacketOfEncryptionLevel(ENCRYPTION_HANDSHAKE)) {
+ // This is only called in coalescer because all ENCRYPTION_HANDSHAKE
+ // packets go through the coalescer.
+ visitor_->OnHandshakePacketSent();
+ }
// Account for added padding.
if (length > coalesced_packet_.length()) {
size_t padding_size = length - coalesced_packet_.length();
@@ -4202,13 +4264,11 @@ void QuicConnection::set_client_connection_id(
}
void QuicConnection::OnPathDegradingDetected() {
- DCHECK(use_blackhole_detector_);
is_path_degrading_ = true;
visitor_->OnPathDegrading();
}
void QuicConnection::OnBlackholeDetected() {
- DCHECK(use_blackhole_detector_);
CloseConnection(QUIC_TOO_MANY_RTOS, "Network blackhole detected.",
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
}
@@ -4250,8 +4310,19 @@ void QuicConnection::OnIdleNetworkDetected() {
idle_timeout_connection_close_behavior_);
}
+void QuicConnection::MaybeUpdateAckTimeout() {
+ DCHECK(advance_ack_timeout_update_);
+ if (should_last_packet_instigate_acks_) {
+ return;
+ }
+ should_last_packet_instigate_acks_ = true;
+ uber_received_packet_manager_.MaybeUpdateAckTimeout(
+ /*should_last_packet_instigate_acks=*/true, last_decrypted_packet_level_,
+ last_header_.packet_number, GetTimeOfLastReceivedPacket(),
+ clock_->ApproximateNow(), sent_packet_manager_.GetRttStats());
+}
+
QuicTime QuicConnection::GetPathDegradingDeadline() const {
- DCHECK(use_blackhole_detector_);
if (!ShouldDetectPathDegrading()) {
return QuicTime::Zero();
}
@@ -4260,7 +4331,6 @@ QuicTime QuicConnection::GetPathDegradingDeadline() const {
}
bool QuicConnection::ShouldDetectPathDegrading() const {
- DCHECK(use_blackhole_detector_);
if (!connected_) {
return false;
}
@@ -4272,7 +4342,6 @@ bool QuicConnection::ShouldDetectPathDegrading() const {
}
QuicTime QuicConnection::GetNetworkBlackholeDeadline() const {
- DCHECK(use_blackhole_detector_);
if (!ShouldDetectBlackhole()) {
return QuicTime::Zero();
}
@@ -4281,7 +4350,6 @@ QuicTime QuicConnection::GetNetworkBlackholeDeadline() const {
}
bool QuicConnection::ShouldDetectBlackhole() const {
- DCHECK(use_blackhole_detector_);
if (!connected_) {
return false;
}
@@ -4304,6 +4372,11 @@ QuicTime QuicConnection::GetTimeOfLastReceivedPacket() const {
if (use_idle_network_detector_) {
return idle_network_detector_.time_of_last_received_packet();
}
+ if (extend_idle_time_on_decryptable_packets_) {
+ DCHECK(time_of_last_decryptable_packet_ == time_of_last_received_packet_ ||
+ !last_packet_decrypted_);
+ return time_of_last_decryptable_packet_;
+ }
return time_of_last_received_packet_;
}
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 a6be992badd..6586fb2870a 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
@@ -49,6 +49,7 @@
#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_socket_address.h"
+#include "net/third_party/quiche/src/common/platform/api/quiche_optional.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
@@ -181,6 +182,9 @@ class QUIC_EXPORT_PRIVATE QuicConnectionVisitorInterface {
// Called when a 1RTT packet has been acknowledged.
virtual void OnOneRttPacketAcknowledged() = 0;
+
+ // Called when a packet of ENCRYPTION_HANDSHAKE gets sent.
+ virtual void OnHandshakePacketSent() = 0;
};
// Interface which gets callbacks from the QuicConnection at interesting
@@ -217,8 +221,15 @@ class QUIC_EXPORT_PRIVATE QuicConnectionDebugVisitor
// match the ID of this connection.
virtual void OnIncorrectConnectionId(QuicConnectionId /*connection_id*/) {}
- // Called when an undecryptable packet has been received.
- virtual void OnUndecryptablePacket() {}
+ // Called when an undecryptable packet has been received. If |dropped| is
+ // true, the packet has been dropped. Otherwise, the packet will be queued and
+ // connection will attempt to process it later.
+ virtual void OnUndecryptablePacket(EncryptionLevel /*decryption_level*/,
+ bool /*dropped*/) {}
+
+ // Called when attempting to process a previously undecryptable packet.
+ virtual void OnAttemptingToProcessUndecryptablePacket(
+ EncryptionLevel /*decryption_level*/) {}
// Called when a duplicate packet has been received.
virtual void OnDuplicatePacket(QuicPacketNumber /*packet_number*/) {}
@@ -373,6 +384,12 @@ class QUIC_EXPORT_PRIVATE QuicConnection
// Sets connection parameters from the supplied |config|.
void SetFromConfig(const QuicConfig& config);
+ // Apply |connection_options| for this connection. Unlike SetFromConfig, this
+ // can happen at anytime in the life of a connection.
+ // Note there is no guarantee that all options can be applied. Components will
+ // only apply cherrypicked options that make sense at the time of the call.
+ void ApplyConnectionOptions(const QuicTagVector& connection_options);
+
// Called by the session when sending connection state to the client.
virtual void OnSendConnectionState(
const CachedNetworkParameters& cached_network_params);
@@ -571,7 +588,7 @@ class QUIC_EXPORT_PRIVATE QuicConnection
IsHandshake handshake) override;
const QuicFrames MaybeBundleAckOpportunistically() override;
char* GetPacketBuffer() override;
- void OnSerializedPacket(SerializedPacket* packet) override;
+ void OnSerializedPacket(SerializedPacket packet) override;
void OnUnrecoverableError(QuicErrorCode error,
const std::string& error_details) override;
@@ -954,7 +971,7 @@ class QUIC_EXPORT_PRIVATE QuicConnection
// Send a packet to the peer, and takes ownership of the packet if the packet
// cannot be written immediately.
- virtual void SendOrQueuePacket(SerializedPacket* packet);
+ virtual void SendOrQueuePacket(SerializedPacket packet);
// Called after a packet is received from a new effective peer address and is
// decrypted. Starts validation of effective peer's address change. Calls
@@ -1053,6 +1070,19 @@ class QUIC_EXPORT_PRIVATE QuicConnection
const QuicSocketAddress peer_address;
};
+ // UndecrytablePacket comprises a undecryptable packet and the its encryption
+ // level.
+ struct QUIC_EXPORT_PRIVATE UndecryptablePacket {
+ UndecryptablePacket(const QuicEncryptedPacket& packet,
+ EncryptionLevel encryption_level)
+ : packet(packet.Clone()), encryption_level(encryption_level) {}
+
+ std::unique_ptr<QuicEncryptedPacket> packet;
+ // Currently, |encryption_level| is only used for logging and does not
+ // affect processing of the packet.
+ EncryptionLevel encryption_level;
+ };
+
// Notifies the visitor of the close and marks the connection as disconnected.
// Does not send a connection close frame to the peer. It should only be
// called by CloseConnection or OnConnectionCloseFrame, OnPublicResetPacket,
@@ -1102,7 +1132,8 @@ class QUIC_EXPORT_PRIVATE QuicConnection
// Queues |packet| in the hopes that it can be decrypted in the
// future, when a new key is installed.
- void QueueUndecryptablePacket(const QuicEncryptedPacket& packet);
+ void QueueUndecryptablePacket(const QuicEncryptedPacket& packet,
+ EncryptionLevel decryption_level);
// Sends any packets which are a response to the last packet, including both
// acks and pending writes if an ack opened the congestion window.
@@ -1121,9 +1152,6 @@ class QUIC_EXPORT_PRIVATE QuicConnection
// Sets the retransmission alarm based on SentPacketManager.
void SetRetransmissionAlarm();
- // Sets the path degrading alarm.
- void SetPathDegradingAlarm();
-
// Sets the MTU discovery alarm if necessary.
// |sent_packet_number| is the recently sent packet number.
void MaybeSetMtuAlarm(QuicPacketNumber sent_packet_number);
@@ -1166,10 +1194,6 @@ class QUIC_EXPORT_PRIVATE QuicConnection
// |acked_new_packet| is true if a previously-unacked packet was acked.
void PostProcessAfterAckFrame(bool send_stop_waiting, bool acked_new_packet);
- // Called when an ACK is received to set the path degrading alarm or
- // retransmittable on wire alarm.
- void MaybeSetPathDegradingAlarm(bool acked_new_packet);
-
// Updates the release time into the future.
void UpdateReleaseTimeIntoFuture();
@@ -1195,6 +1219,9 @@ class QUIC_EXPORT_PRIVATE QuicConnection
// and flags.
void MaybeEnableMultiplePacketNumberSpacesSupport();
+ // Called to update ACK timeout when an retransmittable frame has been parsed.
+ void MaybeUpdateAckTimeout();
+
// Returns packet fate when trying to write a packet via WritePacket().
SerializedPacketFate DeterminePacketFate(bool is_mtu_discovery);
@@ -1228,6 +1255,13 @@ class QUIC_EXPORT_PRIVATE QuicConnection
// Whether connection is limited by amplification factor.
bool LimitedByAmplificationFactor() const;
+ // Called before sending a packet to get packet send time and to set the
+ // release time delay in |per_packet_options_|. Return the time when the
+ // packet is scheduled to be released(a.k.a send time), which is NOW + delay.
+ // Returns Now() and does not update release time delay if
+ // |supports_release_time_| is false.
+ QuicTime CalculatePacketSentTime();
+
// We've got a packet write error, should we ignore it?
// NOTE: This is not a const function - if return true, the max packet size is
// reverted to a previous(smaller) value to avoid write errors in the future.
@@ -1331,8 +1365,7 @@ class QUIC_EXPORT_PRIVATE QuicConnection
// established, but which could not be decrypted. We buffer these on
// the assumption that they could not be processed because they were
// sent with the INITIAL encryption and the CHLO message was lost.
- QuicCircularDeque<std::unique_ptr<QuicEncryptedPacket>>
- undecryptable_packets_;
+ QuicCircularDeque<UndecryptablePacket> undecryptable_packets_;
// Collection of coalesced packets which were received while processing
// the current packet.
@@ -1357,9 +1390,8 @@ class QUIC_EXPORT_PRIVATE QuicConnection
termination_packets_;
// Determines whether or not a connection close packet is sent to the peer
- // after idle timeout due to lack of network activity.
- // This is particularly important on mobile, where waking up the radio is
- // undesirable.
+ // after idle timeout due to lack of network activity. During the handshake,
+ // a connection close packet is sent, but not after.
ConnectionCloseBehavior idle_timeout_connection_close_behavior_;
// When true, close the QUIC connection after 5 RTOs. Due to the min rto of
@@ -1409,10 +1441,6 @@ class QUIC_EXPORT_PRIVATE QuicConnection
QuicArenaScopedPtr<QuicAlarm> ping_alarm_;
// An alarm that fires when an MTU probe should be sent.
QuicArenaScopedPtr<QuicAlarm> mtu_discovery_alarm_;
- // An alarm that fires when this connection is considered degrading.
- // TODO(fayang): Remove this when deprecating quic_use_blackhole_detector
- // flag.
- QuicArenaScopedPtr<QuicAlarm> path_degrading_alarm_;
// An alarm that fires to process undecryptable packets when new decyrption
// keys are available.
QuicArenaScopedPtr<QuicAlarm> process_undecryptable_packets_alarm_;
@@ -1435,13 +1463,20 @@ class QUIC_EXPORT_PRIVATE QuicConnection
// Timestamps used for timeouts.
// The time of the first retransmittable packet that was sent after the most
// recently received packet.
- // TODO(fayang): Remove these two when deprecating
- // quic_use_idle_network_detector.
+ // TODO(fayang): Remove time_of_first_packet_sent_after_receiving_ when
+ // deprecating quic_use_idle_network_detector.
QuicTime time_of_first_packet_sent_after_receiving_;
// The time that a packet is received for this connection. Initialized to
// connection creation time.
- // This is used for timeouts, and does not indicate the packet was processed.
+ // This does not indicate the packet was processed.
QuicTime time_of_last_received_packet_;
+ // This gets set to time_of_last_received_packet_ when a packet gets
+ // decrypted. Please note, this is not necessarily the original receive time
+ // of this decrypt packet because connection can decryptable packet out of
+ // order.
+ // TODO(fayang): Remove time_of_last_decryptable_packet_ when
+ // deprecating quic_use_idle_network_detector.
+ QuicTime time_of_last_decryptable_packet_;
// Sent packet manager which tracks the status of packets sent by this
// connection and contains the send and receive algorithms to determine when
@@ -1566,6 +1601,11 @@ class QUIC_EXPORT_PRIVATE QuicConnection
// vector to improve performance since it is expected to be very small.
std::vector<QuicConnectionId> incoming_connection_ids_;
+ // When we receive a RETRY packet, we replace |server_connection_id_| with the
+ // value from the RETRY packet and save off the original value of
+ // |server_connection_id_| into |original_connection_id_| for validation.
+ quiche::QuicheOptional<QuicConnectionId> original_connection_id_;
+
// Indicates whether received RETRY packets should be dropped.
bool drop_incoming_retry_packets_;
@@ -1604,12 +1644,14 @@ class QUIC_EXPORT_PRIVATE QuicConnection
QuicIdleNetworkDetector idle_network_detector_;
- const bool use_blackhole_detector_ =
- GetQuicReloadableFlag(quic_use_blackhole_detector);
-
const bool use_idle_network_detector_ =
- use_blackhole_detector_ &&
GetQuicReloadableFlag(quic_use_idle_network_detector);
+
+ const bool extend_idle_time_on_decryptable_packets_ =
+ GetQuicReloadableFlag(quic_extend_idle_time_on_decryptable_packets);
+
+ const bool advance_ack_timeout_update_ =
+ GetQuicReloadableFlag(quic_advance_ack_timeout_update);
};
} // namespace quic
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 911ea6dac75..3b0c85d2228 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
@@ -102,6 +102,9 @@ struct QUIC_EXPORT_PRIVATE QuicConnectionStats {
// Maximum reordering observed in microseconds
int64_t max_time_reordering_us = 0;
+ // Maximum sequence reordering observed from acked packets.
+ QuicPacketCount sent_packets_max_sequence_reordering = 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.
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 e5faa3586da..24f233ef233 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
@@ -382,7 +382,8 @@ class TestPacketWriter : public QuicPacketWriter {
ENCRYPTION_FORWARD_SECURE,
std::make_unique<NullDecrypter>(Perspective::IS_SERVER));
}
- EXPECT_TRUE(framer_.ProcessPacket(packet));
+ EXPECT_TRUE(framer_.ProcessPacket(packet))
+ << framer_.framer()->detailed_error();
if (block_on_next_write_) {
write_blocked_ = true;
block_on_next_write_ = false;
@@ -673,7 +674,7 @@ class TestConnection : public QuicConnection {
serialized_packet.retransmittable_frames.push_back(
QuicFrame(QuicPingFrame()));
}
- OnSerializedPacket(&serialized_packet);
+ OnSerializedPacket(std::move(serialized_packet));
}
QuicConsumedData SaveAndSendStreamData(QuicStreamId id,
@@ -844,8 +845,7 @@ class TestConnection : public QuicConnection {
}
TestAlarmFactory::TestAlarm* GetTimeoutAlarm() {
- if (GetQuicReloadableFlag(quic_use_blackhole_detector) &&
- GetQuicReloadableFlag(quic_use_idle_network_detector)) {
+ if (GetQuicReloadableFlag(quic_use_idle_network_detector)) {
return reinterpret_cast<TestAlarmFactory::TestAlarm*>(
QuicConnectionPeer::GetIdleNetworkDetectorAlarm(this));
}
@@ -858,40 +858,26 @@ class TestConnection : public QuicConnection {
QuicConnectionPeer::GetMtuDiscoveryAlarm(this));
}
- TestAlarmFactory::TestAlarm* GetPathDegradingAlarm() {
- return reinterpret_cast<TestAlarmFactory::TestAlarm*>(
- QuicConnectionPeer::GetPathDegradingAlarm(this));
- }
-
TestAlarmFactory::TestAlarm* GetProcessUndecryptablePacketsAlarm() {
return reinterpret_cast<TestAlarmFactory::TestAlarm*>(
QuicConnectionPeer::GetProcessUndecryptablePacketsAlarm(this));
}
TestAlarmFactory::TestAlarm* GetBlackholeDetectorAlarm() {
- DCHECK(GetQuicReloadableFlag(quic_use_blackhole_detector));
return reinterpret_cast<TestAlarmFactory::TestAlarm*>(
QuicConnectionPeer::GetBlackholeDetectorAlarm(this));
}
void PathDegradingTimeout() {
DCHECK(PathDegradingDetectionInProgress());
- if (GetQuicReloadableFlag(quic_use_blackhole_detector)) {
- GetBlackholeDetectorAlarm()->Fire();
- } else {
- GetPathDegradingAlarm()->Fire();
- }
+ GetBlackholeDetectorAlarm()->Fire();
}
bool PathDegradingDetectionInProgress() {
- if (GetQuicReloadableFlag(quic_use_blackhole_detector)) {
- return QuicConnectionPeer::GetPathDegradingDeadline(this).IsInitialized();
- }
- return GetPathDegradingAlarm()->IsSet();
+ return QuicConnectionPeer::GetPathDegradingDeadline(this).IsInitialized();
}
bool BlackholeDetectionInProgress() {
- DCHECK(GetQuicReloadableFlag(quic_use_blackhole_detector));
return QuicConnectionPeer::GetBlackholeDetectionDeadline(this)
.IsInitialized();
}
@@ -915,7 +901,8 @@ class TestConnection : public QuicConnection {
if (QuicConnectionPeer::GetSentPacketManager(this)->pto_enabled()) {
// PTO mode is default enabled for T099. And TLP/RTO related tests are
// stale.
- DCHECK_EQ(PROTOCOL_TLS1_3, version().handshake_protocol);
+ DCHECK(PROTOCOL_TLS1_3 == version().handshake_protocol ||
+ GetQuicReloadableFlag(quic_default_on_pto));
return true;
}
return false;
@@ -1094,8 +1081,6 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> {
.WillRepeatedly(Return(kDefaultTCPMSS));
EXPECT_CALL(*send_algorithm_, PacingRate(_))
.WillRepeatedly(Return(QuicBandwidth::Zero()));
- EXPECT_CALL(*send_algorithm_, HasReliableBandwidthEstimate())
- .Times(AnyNumber());
EXPECT_CALL(*send_algorithm_, BandwidthEstimate())
.Times(AnyNumber())
.WillRepeatedly(Return(QuicBandwidth::Zero()));
@@ -1176,6 +1161,15 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> {
}
}
+ QuicFrame MakeCryptoFrame() const {
+ if (QuicVersionUsesCryptoFrames(connection_.transport_version())) {
+ return QuicFrame(new QuicCryptoFrame(crypto_frame_));
+ }
+ return QuicFrame(QuicStreamFrame(
+ QuicUtils::GetCryptoStreamId(connection_.transport_version()), false,
+ 0u, quiche::QuicheStringPiece()));
+ }
+
void ProcessFramePacket(QuicFrame frame) {
ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress);
}
@@ -1522,7 +1516,7 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> {
return ConstructPacket(header, frames);
}
- OwningSerializedPacketPointer ConstructProbingPacket() {
+ std::unique_ptr<SerializedPacket> ConstructProbingPacket() {
if (VersionHasIetfQuicFrames(version().transport_version)) {
QuicPathFrameBuffer payload = {
{0xde, 0xad, 0xbe, 0xef, 0xba, 0xdc, 0x0f, 0xfe}};
@@ -1670,8 +1664,13 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> {
const std::vector<QuicConnectionCloseFrame>& connection_close_frames =
writer_->connection_close_frames();
ASSERT_EQ(1u, connection_close_frames.size());
+
+ EXPECT_THAT(connection_close_frames[0].quic_error_code,
+ IsError(expected_code));
+
if (!VersionHasIetfQuicFrames(version().transport_version)) {
- EXPECT_EQ(expected_code, connection_close_frames[0].quic_error_code);
+ EXPECT_THAT(connection_close_frames[0].wire_error_code,
+ IsError(expected_code));
EXPECT_EQ(GOOGLE_QUIC_CONNECTION_CLOSE,
connection_close_frames[0].close_type);
return;
@@ -1680,22 +1679,16 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> {
QuicErrorCodeToIetfMapping mapping =
QuicErrorCodeToTransportErrorCode(expected_code);
- if (mapping.is_transport_close_) {
+ if (mapping.is_transport_close) {
// This Google QUIC Error Code maps to a transport close,
EXPECT_EQ(IETF_QUIC_TRANSPORT_CONNECTION_CLOSE,
connection_close_frames[0].close_type);
- EXPECT_EQ(mapping.transport_error_code_,
- connection_close_frames[0].transport_error_code);
- // TODO(fkastenholz): when the extracted error code CL lands,
- // need to test that extracted==expected.
} else {
// This maps to an application close.
- EXPECT_EQ(expected_code, connection_close_frames[0].quic_error_code);
EXPECT_EQ(IETF_QUIC_APPLICATION_CONNECTION_CLOSE,
connection_close_frames[0].close_type);
- // TODO(fkastenholz): when the extracted error code CL lands,
- // need to test that extracted==expected.
}
+ EXPECT_EQ(mapping.error_code, connection_close_frames[0].wire_error_code);
}
void MtuDiscoveryTestInit() {
@@ -1719,6 +1712,10 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> {
EXPECT_TRUE(connection_.connected());
}
+ void TestClientRetryHandling(bool invalid_retry_tag,
+ bool missing_id_in_config,
+ bool wrong_id_in_config);
+
QuicConnectionId connection_id_;
QuicFramer framer_;
@@ -1752,7 +1749,7 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> {
};
// Run all end to end tests with all supported versions.
-INSTANTIATE_TEST_SUITE_P(SupportedVersion,
+INSTANTIATE_TEST_SUITE_P(QuicConnectionTests,
QuicConnectionTest,
::testing::ValuesIn(GetTestParams()),
::testing::PrintToStringParamName());
@@ -1763,7 +1760,7 @@ INSTANTIATE_TEST_SUITE_P(SupportedVersion,
// close, the second an application connection close.
// The connection close codes for the two tests are manually chosen;
// they are expected to always map to transport- and application-
-// closes, respectively. If that changes, mew codes should be chosen.
+// closes, respectively. If that changes, new codes should be chosen.
TEST_P(QuicConnectionTest, CloseErrorCodeTestTransport) {
EXPECT_TRUE(connection_.connected());
EXPECT_CALL(visitor_, OnConnectionClosed(_, _));
@@ -1793,17 +1790,13 @@ TEST_P(QuicConnectionTest, SelfAddressChangeAtClient) {
EXPECT_EQ(Perspective::IS_CLIENT, connection_.perspective());
EXPECT_TRUE(connection_.connected());
- QuicFrame frame;
if (QuicVersionUsesCryptoFrames(connection_.transport_version())) {
- frame = QuicFrame(&crypto_frame_);
EXPECT_CALL(visitor_, OnCryptoFrame(_));
} else {
- frame = QuicFrame(QuicStreamFrame(
- QuicUtils::GetCryptoStreamId(connection_.transport_version()), false,
- 0u, quiche::QuicheStringPiece()));
EXPECT_CALL(visitor_, OnStreamFrame(_));
}
- ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress);
+ ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress,
+ kPeerAddress);
// Cause change in self_address.
QuicIpAddress host;
host.FromString("1.1.1.1");
@@ -1813,7 +1806,8 @@ TEST_P(QuicConnectionTest, SelfAddressChangeAtClient) {
} else {
EXPECT_CALL(visitor_, OnStreamFrame(_));
}
- ProcessFramePacketWithAddresses(frame, self_address, kPeerAddress);
+ ProcessFramePacketWithAddresses(MakeCryptoFrame(), self_address,
+ kPeerAddress);
EXPECT_TRUE(connection_.connected());
}
@@ -1824,24 +1818,21 @@ TEST_P(QuicConnectionTest, SelfAddressChangeAtServer) {
EXPECT_EQ(Perspective::IS_SERVER, connection_.perspective());
EXPECT_TRUE(connection_.connected());
- QuicFrame frame;
if (QuicVersionUsesCryptoFrames(connection_.transport_version())) {
- frame = QuicFrame(&crypto_frame_);
EXPECT_CALL(visitor_, OnCryptoFrame(_));
} else {
- frame = QuicFrame(QuicStreamFrame(
- QuicUtils::GetCryptoStreamId(connection_.transport_version()), false,
- 0u, quiche::QuicheStringPiece()));
EXPECT_CALL(visitor_, OnStreamFrame(_));
}
- ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress);
+ ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress,
+ kPeerAddress);
// Cause change in self_address.
QuicIpAddress host;
host.FromString("1.1.1.1");
QuicSocketAddress self_address(host, 123);
EXPECT_CALL(visitor_, AllowSelfAddressChange()).WillOnce(Return(false));
EXPECT_CALL(visitor_, OnConnectionClosed(_, _));
- ProcessFramePacketWithAddresses(frame, self_address, kPeerAddress);
+ ProcessFramePacketWithAddresses(MakeCryptoFrame(), self_address,
+ kPeerAddress);
EXPECT_FALSE(connection_.connected());
TestConnectionCloseQuicErrorCode(QUIC_ERROR_MIGRATING_ADDRESS);
}
@@ -1853,29 +1844,27 @@ TEST_P(QuicConnectionTest, AllowSelfAddressChangeToMappedIpv4AddressAtServer) {
EXPECT_EQ(Perspective::IS_SERVER, connection_.perspective());
EXPECT_TRUE(connection_.connected());
- QuicFrame frame;
if (QuicVersionUsesCryptoFrames(connection_.transport_version())) {
- frame = QuicFrame(&crypto_frame_);
EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(3);
} else {
- frame = QuicFrame(QuicStreamFrame(
- QuicUtils::GetCryptoStreamId(connection_.transport_version()), false,
- 0u, quiche::QuicheStringPiece()));
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(3);
}
QuicIpAddress host;
host.FromString("1.1.1.1");
QuicSocketAddress self_address1(host, 443);
- ProcessFramePacketWithAddresses(frame, self_address1, kPeerAddress);
+ ProcessFramePacketWithAddresses(MakeCryptoFrame(), self_address1,
+ kPeerAddress);
// Cause self_address change to mapped Ipv4 address.
QuicIpAddress host2;
host2.FromString(quiche::QuicheStrCat(
"::ffff:", connection_.self_address().host().ToString()));
QuicSocketAddress self_address2(host2, connection_.self_address().port());
- ProcessFramePacketWithAddresses(frame, self_address2, kPeerAddress);
+ ProcessFramePacketWithAddresses(MakeCryptoFrame(), self_address2,
+ kPeerAddress);
EXPECT_TRUE(connection_.connected());
// self_address change back to Ipv4 address.
- ProcessFramePacketWithAddresses(frame, self_address1, kPeerAddress);
+ ProcessFramePacketWithAddresses(MakeCryptoFrame(), self_address1,
+ kPeerAddress);
EXPECT_TRUE(connection_.connected());
}
@@ -1890,21 +1879,17 @@ TEST_P(QuicConnectionTest, ClientAddressChangeAndPacketReordered) {
QuicConnectionPeer::SetEffectivePeerAddress(&connection_,
QuicSocketAddress());
- QuicFrame frame;
if (QuicVersionUsesCryptoFrames(connection_.transport_version())) {
- frame = QuicFrame(&crypto_frame_);
EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber());
} else {
- frame = QuicFrame(QuicStreamFrame(
- QuicUtils::GetCryptoStreamId(connection_.transport_version()), false,
- 0u, quiche::QuicheStringPiece()));
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber());
}
QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 5);
const QuicSocketAddress kNewPeerAddress =
QuicSocketAddress(QuicIpAddress::Loopback6(),
/*port=*/23456);
- ProcessFramePacketWithAddresses(frame, kSelfAddress, kNewPeerAddress);
+ ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress,
+ kNewPeerAddress);
EXPECT_EQ(kNewPeerAddress, connection_.peer_address());
EXPECT_EQ(kNewPeerAddress, connection_.effective_peer_address());
@@ -1912,7 +1897,8 @@ TEST_P(QuicConnectionTest, ClientAddressChangeAndPacketReordered) {
QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 4);
// This is an old packet, do not migrate.
EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(0);
- ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress);
+ ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress,
+ kPeerAddress);
EXPECT_EQ(kNewPeerAddress, connection_.peer_address());
EXPECT_EQ(kNewPeerAddress, connection_.effective_peer_address());
}
@@ -1930,17 +1916,13 @@ TEST_P(QuicConnectionTest, PeerAddressChangeAtServer) {
QuicSocketAddress());
EXPECT_FALSE(connection_.effective_peer_address().IsInitialized());
- QuicFrame frame;
if (QuicVersionUsesCryptoFrames(connection_.transport_version())) {
- frame = QuicFrame(&crypto_frame_);
EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber());
} else {
- frame = QuicFrame(QuicStreamFrame(
- QuicUtils::GetCryptoStreamId(connection_.transport_version()), false,
- 0u, quiche::QuicheStringPiece()));
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber());
}
- ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress);
+ ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress,
+ kPeerAddress);
EXPECT_EQ(kPeerAddress, connection_.peer_address());
EXPECT_EQ(kPeerAddress, connection_.effective_peer_address());
@@ -1949,7 +1931,8 @@ TEST_P(QuicConnectionTest, PeerAddressChangeAtServer) {
const QuicSocketAddress kNewPeerAddress =
QuicSocketAddress(QuicIpAddress::Loopback6(), /*port=*/23456);
EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(1);
- ProcessFramePacketWithAddresses(frame, kSelfAddress, kNewPeerAddress);
+ ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress,
+ kNewPeerAddress);
EXPECT_EQ(kNewPeerAddress, connection_.peer_address());
EXPECT_EQ(kNewPeerAddress, connection_.effective_peer_address());
}
@@ -1969,17 +1952,13 @@ TEST_P(QuicConnectionTest, EffectivePeerAddressChangeAtServer) {
QuicSocketAddress(QuicIpAddress::Loopback6(), /*port=*/43210);
connection_.ReturnEffectivePeerAddressForNextPacket(kEffectivePeerAddress);
- QuicFrame frame;
if (QuicVersionUsesCryptoFrames(connection_.transport_version())) {
- frame = QuicFrame(&crypto_frame_);
EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber());
} else {
- frame = QuicFrame(QuicStreamFrame(
- QuicUtils::GetCryptoStreamId(connection_.transport_version()), false,
- 0u, quiche::QuicheStringPiece()));
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber());
}
- ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress);
+ ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress,
+ kPeerAddress);
EXPECT_EQ(kPeerAddress, connection_.peer_address());
EXPECT_EQ(kEffectivePeerAddress, connection_.effective_peer_address());
@@ -1989,7 +1968,8 @@ TEST_P(QuicConnectionTest, EffectivePeerAddressChangeAtServer) {
QuicSocketAddress(QuicIpAddress::Loopback6(), /*port=*/54321);
connection_.ReturnEffectivePeerAddressForNextPacket(kNewEffectivePeerAddress);
EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(1);
- ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress);
+ ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress,
+ kPeerAddress);
EXPECT_EQ(kPeerAddress, connection_.peer_address());
EXPECT_EQ(kNewEffectivePeerAddress, connection_.effective_peer_address());
@@ -2018,7 +1998,8 @@ TEST_P(QuicConnectionTest, EffectivePeerAddressChangeAtServer) {
connection_.ReturnEffectivePeerAddressForNextPacket(
kNewerEffectivePeerAddress);
EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(1);
- ProcessFramePacketWithAddresses(frame, kSelfAddress, kFinalPeerAddress);
+ ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress,
+ kFinalPeerAddress);
EXPECT_EQ(kFinalPeerAddress, connection_.peer_address());
EXPECT_EQ(kNewerEffectivePeerAddress, connection_.effective_peer_address());
EXPECT_EQ(PORT_CHANGE, connection_.active_effective_peer_migration_type());
@@ -2032,7 +2013,8 @@ TEST_P(QuicConnectionTest, EffectivePeerAddressChangeAtServer) {
kNewestEffectivePeerAddress);
EXPECT_CALL(visitor_, OnConnectionMigration(IPV6_TO_IPV4_CHANGE)).Times(1);
EXPECT_CALL(*send_algorithm_, OnConnectionMigration()).Times(1);
- ProcessFramePacketWithAddresses(frame, kSelfAddress, kFinalPeerAddress);
+ ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress,
+ kFinalPeerAddress);
EXPECT_EQ(kFinalPeerAddress, connection_.peer_address());
EXPECT_EQ(kNewestEffectivePeerAddress, connection_.effective_peer_address());
EXPECT_EQ(IPV6_TO_IPV4_CHANGE,
@@ -2052,17 +2034,13 @@ TEST_P(QuicConnectionTest, ReceivePathProbeWithNoAddressChangeAtServer) {
QuicSocketAddress());
EXPECT_FALSE(connection_.effective_peer_address().IsInitialized());
- QuicFrame frame;
if (QuicVersionUsesCryptoFrames(connection_.transport_version())) {
- frame = QuicFrame(&crypto_frame_);
EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber());
} else {
- frame = QuicFrame(QuicStreamFrame(
- QuicUtils::GetCryptoStreamId(connection_.transport_version()), false,
- 0u, quiche::QuicheStringPiece()));
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber());
}
- ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress);
+ ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress,
+ kPeerAddress);
EXPECT_EQ(kPeerAddress, connection_.peer_address());
EXPECT_EQ(kPeerAddress, connection_.effective_peer_address());
@@ -2071,7 +2049,7 @@ TEST_P(QuicConnectionTest, ReceivePathProbeWithNoAddressChangeAtServer) {
// Process a padded PING or PATH CHALLENGE packet with no peer address change
// on server side will be ignored.
- OwningSerializedPacketPointer probing_packet = ConstructProbingPacket();
+ std::unique_ptr<SerializedPacket> probing_packet = ConstructProbingPacket();
std::unique_ptr<QuicReceivedPacket> received(ConstructReceivedPacket(
QuicEncryptedPacket(probing_packet->encrypted_buffer,
@@ -2088,6 +2066,24 @@ TEST_P(QuicConnectionTest, ReceivePathProbeWithNoAddressChangeAtServer) {
EXPECT_EQ(kPeerAddress, connection_.effective_peer_address());
}
+// Regression test for b/150161358.
+TEST_P(QuicConnectionTest, BufferedMtuPacketTooBig) {
+ if (!GetQuicReloadableFlag(quic_ignore_msg_too_big_from_buffered_packets)) {
+ return;
+ }
+ EXPECT_CALL(visitor_, OnWriteBlocked()).Times(1);
+ writer_->SetWriteBlocked();
+
+ // Send a MTU packet while blocked. It should be buffered.
+ connection_.SendMtuDiscoveryPacket(kMaxOutgoingPacketSize);
+ EXPECT_EQ(1u, connection_.NumQueuedPackets());
+ EXPECT_TRUE(writer_->IsWriteBlocked());
+
+ writer_->AlwaysGetPacketTooLarge();
+ writer_->SetWritable();
+ connection_.OnCanWrite();
+}
+
TEST_P(QuicConnectionTest, WriteOutOfOrderQueuedPackets) {
// EXPECT_QUIC_BUG tests are expensive so only run one instance of them.
if (!IsDefaultTestConfiguration()) {
@@ -2154,17 +2150,13 @@ TEST_P(QuicConnectionTest, ReceivePathProbingAtServer) {
QuicSocketAddress());
EXPECT_FALSE(connection_.effective_peer_address().IsInitialized());
- QuicFrame frame;
if (QuicVersionUsesCryptoFrames(connection_.transport_version())) {
- frame = QuicFrame(&crypto_frame_);
EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber());
} else {
- frame = QuicFrame(QuicStreamFrame(
- QuicUtils::GetCryptoStreamId(connection_.transport_version()), false,
- 0u, quiche::QuicheStringPiece()));
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber());
}
- ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress);
+ ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress,
+ kPeerAddress);
EXPECT_EQ(kPeerAddress, connection_.peer_address());
EXPECT_EQ(kPeerAddress, connection_.effective_peer_address());
@@ -2181,7 +2173,7 @@ TEST_P(QuicConnectionTest, ReceivePathProbingAtServer) {
const QuicSocketAddress kNewPeerAddress =
QuicSocketAddress(QuicIpAddress::Loopback6(), /*port=*/23456);
- OwningSerializedPacketPointer probing_packet = ConstructProbingPacket();
+ std::unique_ptr<SerializedPacket> probing_packet = ConstructProbingPacket();
std::unique_ptr<QuicReceivedPacket> received(ConstructReceivedPacket(
QuicEncryptedPacket(probing_packet->encrypted_buffer,
probing_packet->encrypted_length),
@@ -2199,7 +2191,8 @@ TEST_P(QuicConnectionTest, ReceivePathProbingAtServer) {
// Process another packet with the old peer address on server side will not
// start peer migration.
EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(0);
- ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress);
+ ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress,
+ kPeerAddress);
EXPECT_EQ(kPeerAddress, connection_.peer_address());
EXPECT_EQ(kPeerAddress, connection_.effective_peer_address());
}
@@ -2218,17 +2211,13 @@ TEST_P(QuicConnectionTest, ReceivePaddedPingWithPortChangeAtServer) {
QuicSocketAddress());
EXPECT_FALSE(connection_.effective_peer_address().IsInitialized());
- QuicFrame frame;
if (GetParam().version.UsesCryptoFrames()) {
- frame = QuicFrame(&crypto_frame_);
EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber());
} else {
- frame = QuicFrame(QuicStreamFrame(
- QuicUtils::GetCryptoStreamId(connection_.transport_version()), false,
- 0u, quiche::QuicheStringPiece()));
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber());
}
- ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress);
+ ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress,
+ kPeerAddress);
EXPECT_EQ(kPeerAddress, connection_.peer_address());
EXPECT_EQ(kPeerAddress, connection_.effective_peer_address());
@@ -2282,7 +2271,8 @@ TEST_P(QuicConnectionTest, ReceivePaddedPingWithPortChangeAtServer) {
} else {
EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(0);
}
- ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress);
+ ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress,
+ kPeerAddress);
EXPECT_EQ(kPeerAddress, connection_.peer_address());
EXPECT_EQ(kPeerAddress, connection_.effective_peer_address());
}
@@ -2300,18 +2290,14 @@ TEST_P(QuicConnectionTest, ReceiveReorderedPathProbingAtServer) {
QuicSocketAddress());
EXPECT_FALSE(connection_.effective_peer_address().IsInitialized());
- QuicFrame frame;
if (QuicVersionUsesCryptoFrames(connection_.transport_version())) {
- frame = QuicFrame(&crypto_frame_);
EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber());
} else {
- frame = QuicFrame(QuicStreamFrame(
- QuicUtils::GetCryptoStreamId(connection_.transport_version()), false,
- 0u, quiche::QuicheStringPiece()));
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber());
}
QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 5);
- ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress);
+ ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress,
+ kPeerAddress);
EXPECT_EQ(kPeerAddress, connection_.peer_address());
EXPECT_EQ(kPeerAddress, connection_.effective_peer_address());
@@ -2333,7 +2319,7 @@ TEST_P(QuicConnectionTest, ReceiveReorderedPathProbingAtServer) {
const QuicSocketAddress kNewPeerAddress =
QuicSocketAddress(QuicIpAddress::Loopback6(), /*port=*/23456);
- OwningSerializedPacketPointer probing_packet = ConstructProbingPacket();
+ std::unique_ptr<SerializedPacket> probing_packet = ConstructProbingPacket();
std::unique_ptr<QuicReceivedPacket> received(ConstructReceivedPacket(
QuicEncryptedPacket(probing_packet->encrypted_buffer,
probing_packet->encrypted_length),
@@ -2362,17 +2348,13 @@ TEST_P(QuicConnectionTest, MigrateAfterProbingAtServer) {
QuicSocketAddress());
EXPECT_FALSE(connection_.effective_peer_address().IsInitialized());
- QuicFrame frame;
if (QuicVersionUsesCryptoFrames(connection_.transport_version())) {
- frame = QuicFrame(&crypto_frame_);
EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber());
} else {
- frame = QuicFrame(QuicStreamFrame(
- QuicUtils::GetCryptoStreamId(connection_.transport_version()), false,
- 0u, quiche::QuicheStringPiece()));
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber());
}
- ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress);
+ ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress,
+ kPeerAddress);
EXPECT_EQ(kPeerAddress, connection_.peer_address());
EXPECT_EQ(kPeerAddress, connection_.effective_peer_address());
@@ -2390,7 +2372,7 @@ TEST_P(QuicConnectionTest, MigrateAfterProbingAtServer) {
const QuicSocketAddress kNewPeerAddress =
QuicSocketAddress(QuicIpAddress::Loopback6(), /*port=*/23456);
- OwningSerializedPacketPointer probing_packet = ConstructProbingPacket();
+ std::unique_ptr<SerializedPacket> probing_packet = ConstructProbingPacket();
std::unique_ptr<QuicReceivedPacket> received(ConstructReceivedPacket(
QuicEncryptedPacket(probing_packet->encrypted_buffer,
probing_packet->encrypted_length),
@@ -2403,7 +2385,8 @@ TEST_P(QuicConnectionTest, MigrateAfterProbingAtServer) {
// side will start peer migration.
EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(1);
- ProcessFramePacketWithAddresses(frame, kSelfAddress, kNewPeerAddress);
+ ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress,
+ kNewPeerAddress);
EXPECT_EQ(kNewPeerAddress, connection_.peer_address());
EXPECT_EQ(kNewPeerAddress, connection_.effective_peer_address());
}
@@ -2421,17 +2404,13 @@ TEST_P(QuicConnectionTest, ReceivePaddedPingAtClient) {
QuicSocketAddress());
EXPECT_FALSE(connection_.effective_peer_address().IsInitialized());
- QuicFrame frame;
if (QuicVersionUsesCryptoFrames(connection_.transport_version())) {
- frame = QuicFrame(&crypto_frame_);
EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber());
} else {
- frame = QuicFrame(QuicStreamFrame(
- QuicUtils::GetCryptoStreamId(connection_.transport_version()), false,
- 0u, quiche::QuicheStringPiece()));
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber());
}
- ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress);
+ ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress,
+ kPeerAddress);
EXPECT_EQ(kPeerAddress, connection_.peer_address());
EXPECT_EQ(kPeerAddress, connection_.effective_peer_address());
@@ -2440,7 +2419,7 @@ TEST_P(QuicConnectionTest, ReceivePaddedPingAtClient) {
EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(0);
EXPECT_CALL(visitor_, OnPacketReceived(_, _, false)).Times(1);
- OwningSerializedPacketPointer probing_packet = ConstructProbingPacket();
+ std::unique_ptr<SerializedPacket> probing_packet = ConstructProbingPacket();
std::unique_ptr<QuicReceivedPacket> received(ConstructReceivedPacket(
QuicEncryptedPacket(probing_packet->encrypted_buffer,
probing_packet->encrypted_length),
@@ -2474,17 +2453,13 @@ TEST_P(QuicConnectionTest, ReceiveConnectivityProbingResponseAtClient) {
QuicSocketAddress());
EXPECT_FALSE(connection_.effective_peer_address().IsInitialized());
- QuicFrame frame;
if (QuicVersionUsesCryptoFrames(connection_.transport_version())) {
- frame = QuicFrame(&crypto_frame_);
EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber());
} else {
- frame = QuicFrame(QuicStreamFrame(
- QuicUtils::GetCryptoStreamId(connection_.transport_version()), false,
- 0u, quiche::QuicheStringPiece()));
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber());
}
- ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress);
+ ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress,
+ kPeerAddress);
EXPECT_EQ(kPeerAddress, connection_.peer_address());
EXPECT_EQ(kPeerAddress, connection_.effective_peer_address());
@@ -2502,7 +2477,7 @@ TEST_P(QuicConnectionTest, ReceiveConnectivityProbingResponseAtClient) {
const QuicSocketAddress kNewSelfAddress =
QuicSocketAddress(QuicIpAddress::Loopback6(), /*port=*/23456);
- OwningSerializedPacketPointer probing_packet = ConstructProbingPacket();
+ std::unique_ptr<SerializedPacket> probing_packet = ConstructProbingPacket();
std::unique_ptr<QuicReceivedPacket> received(ConstructReceivedPacket(
QuicEncryptedPacket(probing_packet->encrypted_buffer,
probing_packet->encrypted_length),
@@ -2530,17 +2505,13 @@ TEST_P(QuicConnectionTest, PeerAddressChangeAtClient) {
QuicSocketAddress());
EXPECT_FALSE(connection_.effective_peer_address().IsInitialized());
- QuicFrame frame;
if (QuicVersionUsesCryptoFrames(connection_.transport_version())) {
- frame = QuicFrame(&crypto_frame_);
EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber());
} else {
- frame = QuicFrame(QuicStreamFrame(
- QuicUtils::GetCryptoStreamId(connection_.transport_version()), false,
- 0u, quiche::QuicheStringPiece()));
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber());
}
- ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress);
+ ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress,
+ kPeerAddress);
EXPECT_EQ(kPeerAddress, connection_.peer_address());
EXPECT_EQ(kPeerAddress, connection_.effective_peer_address());
@@ -2549,7 +2520,8 @@ TEST_P(QuicConnectionTest, PeerAddressChangeAtClient) {
const QuicSocketAddress kNewPeerAddress =
QuicSocketAddress(QuicIpAddress::Loopback6(), /*port=*/23456);
EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(0);
- ProcessFramePacketWithAddresses(frame, kSelfAddress, kNewPeerAddress);
+ ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress,
+ kNewPeerAddress);
EXPECT_EQ(kNewPeerAddress, connection_.peer_address());
EXPECT_EQ(kNewPeerAddress, connection_.effective_peer_address());
}
@@ -2866,7 +2838,8 @@ TEST_P(QuicConnectionTest, AckReceiptCausesAckSend) {
LostPacketVector lost_packets;
lost_packets.push_back(LostPacket(original, kMaxOutgoingPacketSize));
EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _))
- .WillOnce(SetArgPointee<5>(lost_packets));
+ .WillOnce(DoAll(SetArgPointee<5>(lost_packets),
+ Return(LossDetectionInterface::DetectionStats())));
EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
QuicPacketNumber retransmission;
// Packet 1 is short header for IETF QUIC because the encryption level
@@ -3019,7 +2992,6 @@ TEST_P(QuicConnectionTest, AckNeedsRetransmittableFrames) {
}
TEST_P(QuicConnectionTest, AckNeedsRetransmittableFramesAfterPto) {
- SetQuicReloadableFlag(quic_bundle_retransmittable_with_pto_ack, true);
// Disable TLP so the RTO fires immediately.
connection_.SetMaxTailLossProbes(0);
EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
@@ -3587,7 +3559,8 @@ TEST_P(QuicConnectionTest, RetransmitOnNack) {
lost_packets.push_back(
LostPacket(QuicPacketNumber(2), kMaxOutgoingPacketSize));
EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _))
- .WillOnce(SetArgPointee<5>(lost_packets));
+ .WillOnce(DoAll(SetArgPointee<5>(lost_packets),
+ Return(LossDetectionInterface::DetectionStats())));
EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
EXPECT_FALSE(QuicPacketCreatorPeer::SendVersionInPacket(creator_));
@@ -3669,7 +3642,8 @@ TEST_P(QuicConnectionTest, RetransmitForQuicRstStreamNoErrorOnNack) {
LostPacketVector lost_packets;
lost_packets.push_back(LostPacket(last_packet - 1, kMaxOutgoingPacketSize));
EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _))
- .WillOnce(SetArgPointee<5>(lost_packets));
+ .WillOnce(DoAll(SetArgPointee<5>(lost_packets),
+ Return(LossDetectionInterface::DetectionStats())));
EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(1));
ProcessAckPacket(&nack_two);
@@ -3789,7 +3763,8 @@ TEST_P(QuicConnectionTest, SendPendingRetransmissionForQuicRstStreamNoError) {
LostPacketVector lost_packets;
lost_packets.push_back(LostPacket(last_packet - 1, kMaxOutgoingPacketSize));
EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _))
- .WillOnce(SetArgPointee<5>(lost_packets));
+ .WillOnce(DoAll(SetArgPointee<5>(lost_packets),
+ Return(LossDetectionInterface::DetectionStats())));
EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
ProcessAckPacket(&ack);
@@ -3828,7 +3803,8 @@ TEST_P(QuicConnectionTest, RetransmitAckedPacket) {
lost_packets.push_back(
LostPacket(QuicPacketNumber(2), kMaxOutgoingPacketSize));
EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _))
- .WillOnce(SetArgPointee<5>(lost_packets));
+ .WillOnce(DoAll(SetArgPointee<5>(lost_packets),
+ Return(LossDetectionInterface::DetectionStats())));
EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(4), _, _))
.Times(1);
@@ -3865,7 +3841,8 @@ TEST_P(QuicConnectionTest, RetransmitNackedLargestObserved) {
LostPacketVector lost_packets;
lost_packets.push_back(LostPacket(original, kMaxOutgoingPacketSize));
EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _))
- .WillOnce(SetArgPointee<5>(lost_packets));
+ .WillOnce(DoAll(SetArgPointee<5>(lost_packets),
+ Return(LossDetectionInterface::DetectionStats())));
EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
// Packet 1 is short header for IETF QUIC because the encryption level
// switched to ENCRYPTION_FORWARD_SECURE in SendStreamDataToPeer.
@@ -3960,8 +3937,10 @@ TEST_P(QuicConnectionTest, RetransmitWriteBlockedAckedOriginalThenSent) {
writer_->SetWritable();
connection_.OnCanWrite();
EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
- const uint64_t retransmission =
- connection_.SupportsMultiplePacketNumberSpaces() ? 3 : 2;
+ uint64_t retransmission = connection_.SupportsMultiplePacketNumberSpaces() &&
+ !GetQuicReloadableFlag(quic_default_on_pto)
+ ? 3
+ : 2;
EXPECT_FALSE(QuicConnectionPeer::HasRetransmittableFrames(&connection_,
retransmission));
}
@@ -4082,7 +4061,8 @@ TEST_P(QuicConnectionTest, NoLimitPacketsPerNack) {
LostPacket(QuicPacketNumber(i), kMaxOutgoingPacketSize));
}
EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _))
- .WillOnce(SetArgPointee<5>(lost_packets));
+ .WillOnce(DoAll(SetArgPointee<5>(lost_packets),
+ Return(LossDetectionInterface::DetectionStats())));
EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
ProcessAckPacket(&nack);
@@ -4190,6 +4170,9 @@ TEST_P(QuicConnectionTest, DontLatchUnackedPacket) {
}
TEST_P(QuicConnectionTest, TLP) {
+ if (connection_.PtoEnabled()) {
+ return;
+ }
connection_.SetMaxTailLossProbes(1);
SendStreamDataToPeer(3, "foo", 0, NO_FIN, nullptr);
@@ -4257,8 +4240,7 @@ TEST_P(QuicConnectionTest, TailLossProbeDelayForNonStreamDataInTLPR) {
QuicTagVector options;
options.push_back(kTLPR);
config.SetConnectionOptionsToSend(options);
- QuicConfigPeer::ReceiveIdleNetworkTimeout(&config, SERVER,
- kDefaultIdleTimeoutSecs);
+ QuicConfigPeer::SetNegotiated(&config, true);
connection_.SetFromConfig(config);
connection_.SetMaxTailLossProbes(1);
@@ -4795,8 +4777,7 @@ TEST_P(QuicConnectionTest, IdleTimeoutAfterFirstSentPacket) {
EXPECT_CALL(visitor_, OnConnectionClosed(_, _)).Times(0);
QuicTime::Delta delay = initial_ddl - clock_.ApproximateNow();
clock_.AdvanceTime(delay);
- if (!GetQuicReloadableFlag(quic_use_blackhole_detector) ||
- !GetQuicReloadableFlag(quic_use_idle_network_detector)) {
+ if (!GetQuicReloadableFlag(quic_use_idle_network_detector)) {
connection_.GetTimeoutAlarm()->Fire();
}
// Verify the timeout alarm deadline is updated.
@@ -4887,8 +4868,7 @@ TEST_P(QuicConnectionTest, HandshakeTimeout) {
EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
ProcessAckPacket(&frame);
- if (!GetQuicReloadableFlag(quic_use_blackhole_detector) ||
- !GetQuicReloadableFlag(quic_use_idle_network_detector)) {
+ if (!GetQuicReloadableFlag(quic_use_idle_network_detector)) {
// Fire early to verify it wouldn't timeout yet.
connection_.GetTimeoutAlarm()->Fire();
}
@@ -5167,23 +5147,21 @@ TEST_P(QuicConnectionTest, MtuDiscoveryEnabled) {
// The last probe size should be equal to the target.
EXPECT_EQ(probe_size, kMtuDiscoveryTargetPacketSizeHigh);
- if (GetQuicReloadableFlag(quic_ignore_one_write_error_after_mtu_probe)) {
- writer_->SetShouldWriteFail();
+ writer_->SetShouldWriteFail();
- // Ignore PACKET_WRITE_ERROR once.
- SendStreamDataToPeer(3, "(", stream_offset++, NO_FIN, nullptr);
- EXPECT_EQ(last_probe_size, connection_.max_packet_length());
- EXPECT_TRUE(connection_.connected());
+ // Ignore PACKET_WRITE_ERROR once.
+ SendStreamDataToPeer(3, "(", stream_offset++, NO_FIN, nullptr);
+ EXPECT_EQ(last_probe_size, connection_.max_packet_length());
+ EXPECT_TRUE(connection_.connected());
- // Close connection on another PACKET_WRITE_ERROR.
- EXPECT_CALL(visitor_, OnConnectionClosed(_, _))
- .WillOnce(Invoke(this, &QuicConnectionTest::SaveConnectionCloseFrame));
- SendStreamDataToPeer(3, ")", stream_offset++, NO_FIN, nullptr);
- EXPECT_EQ(last_probe_size, connection_.max_packet_length());
- EXPECT_FALSE(connection_.connected());
- EXPECT_THAT(saved_connection_close_frame_.quic_error_code,
- IsError(QUIC_PACKET_WRITE_ERROR));
- }
+ // Close connection on another PACKET_WRITE_ERROR.
+ EXPECT_CALL(visitor_, OnConnectionClosed(_, _))
+ .WillOnce(Invoke(this, &QuicConnectionTest::SaveConnectionCloseFrame));
+ SendStreamDataToPeer(3, ")", stream_offset++, NO_FIN, nullptr);
+ EXPECT_EQ(last_probe_size, connection_.max_packet_length());
+ EXPECT_FALSE(connection_.connected());
+ EXPECT_THAT(saved_connection_close_frame_.quic_error_code,
+ IsError(QUIC_PACKET_WRITE_ERROR));
}
// After a successful MTU probe, one and only one write error should be ignored
@@ -5232,31 +5210,29 @@ TEST_P(QuicConnectionTest,
EXPECT_EQ(1u, connection_.mtu_probe_count());
- if (GetQuicReloadableFlag(quic_ignore_one_write_error_after_mtu_probe)) {
- writer_->SetShouldWriteFail();
+ writer_->SetShouldWriteFail();
- // Ignore PACKET_WRITE_ERROR once.
- {
- QuicConnection::ScopedPacketFlusher flusher(&connection_);
- // flusher's destructor will call connection_.FlushPackets, which should
- // get a WRITE_STATUS_ERROR from the writer and ignore it.
- }
- EXPECT_EQ(original_max_packet_length, connection_.max_packet_length());
- EXPECT_TRUE(connection_.connected());
+ // Ignore PACKET_WRITE_ERROR once.
+ {
+ QuicConnection::ScopedPacketFlusher flusher(&connection_);
+ // flusher's destructor will call connection_.FlushPackets, which should
+ // get a WRITE_STATUS_ERROR from the writer and ignore it.
+ }
+ EXPECT_EQ(original_max_packet_length, connection_.max_packet_length());
+ EXPECT_TRUE(connection_.connected());
- // Close connection on another PACKET_WRITE_ERROR.
- EXPECT_CALL(visitor_, OnConnectionClosed(_, _))
- .WillOnce(Invoke(this, &QuicConnectionTest::SaveConnectionCloseFrame));
- {
- QuicConnection::ScopedPacketFlusher flusher(&connection_);
- // flusher's destructor will call connection_.FlushPackets, which should
- // get a WRITE_STATUS_ERROR from the writer and ignore it.
- }
- EXPECT_EQ(original_max_packet_length, connection_.max_packet_length());
- EXPECT_FALSE(connection_.connected());
- EXPECT_THAT(saved_connection_close_frame_.quic_error_code,
- IsError(QUIC_PACKET_WRITE_ERROR));
+ // Close connection on another PACKET_WRITE_ERROR.
+ EXPECT_CALL(visitor_, OnConnectionClosed(_, _))
+ .WillOnce(Invoke(this, &QuicConnectionTest::SaveConnectionCloseFrame));
+ {
+ QuicConnection::ScopedPacketFlusher flusher(&connection_);
+ // flusher's destructor will call connection_.FlushPackets, which should
+ // get a WRITE_STATUS_ERROR from the writer and ignore it.
}
+ EXPECT_EQ(original_max_packet_length, connection_.max_packet_length());
+ EXPECT_FALSE(connection_.connected());
+ EXPECT_THAT(saved_connection_close_frame_.quic_error_code,
+ IsError(QUIC_PACKET_WRITE_ERROR));
}
// Simulate the case where the first attempt to send a probe is write blocked,
@@ -5620,12 +5596,11 @@ TEST_P(QuicConnectionTest, NoMtuDiscoveryAfterConnectionClosed) {
EXPECT_FALSE(connection_.GetMtuDiscoveryAlarm()->IsSet());
}
-TEST_P(QuicConnectionTest, TimeoutAfterSend) {
+TEST_P(QuicConnectionTest, TimeoutAfterSendDuringHandshake) {
EXPECT_TRUE(connection_.connected());
EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
QuicConfig config;
connection_.SetFromConfig(config);
- EXPECT_FALSE(QuicConnectionPeer::IsSilentCloseEnabled(&connection_));
const QuicTime::Delta initial_idle_timeout =
QuicTime::Delta::FromSeconds(kInitialIdleTimeoutSecs - 1);
@@ -5638,8 +5613,7 @@ TEST_P(QuicConnectionTest, TimeoutAfterSend) {
SendStreamDataToPeer(
GetNthClientInitiatedStreamId(1, connection_.transport_version()), "foo",
0, FIN, nullptr);
- if (GetQuicReloadableFlag(quic_use_blackhole_detector) &&
- GetQuicReloadableFlag(quic_use_idle_network_detector)) {
+ if (GetQuicReloadableFlag(quic_use_idle_network_detector)) {
EXPECT_EQ(default_timeout + five_ms,
connection_.GetTimeoutAlarm()->deadline());
} else {
@@ -5652,8 +5626,7 @@ TEST_P(QuicConnectionTest, TimeoutAfterSend) {
SendStreamDataToPeer(
GetNthClientInitiatedStreamId(1, connection_.transport_version()), "foo",
3, FIN, nullptr);
- if (GetQuicReloadableFlag(quic_use_blackhole_detector) &&
- GetQuicReloadableFlag(quic_use_idle_network_detector)) {
+ if (GetQuicReloadableFlag(quic_use_idle_network_detector)) {
EXPECT_EQ(default_timeout + five_ms,
connection_.GetTimeoutAlarm()->deadline());
} else {
@@ -5664,8 +5637,7 @@ TEST_P(QuicConnectionTest, TimeoutAfterSend) {
// network event at t=5ms. The alarm will reregister.
clock_.AdvanceTime(initial_idle_timeout - five_ms - five_ms);
EXPECT_EQ(default_timeout, clock_.ApproximateNow());
- if (!GetQuicReloadableFlag(quic_use_blackhole_detector) ||
- !GetQuicReloadableFlag(quic_use_idle_network_detector)) {
+ if (!GetQuicReloadableFlag(quic_use_idle_network_detector)) {
connection_.GetTimeoutAlarm()->Fire();
}
EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet());
@@ -5694,7 +5666,6 @@ TEST_P(QuicConnectionTest, TimeoutAfterRetransmission) {
EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
QuicConfig config;
connection_.SetFromConfig(config);
- EXPECT_FALSE(QuicConnectionPeer::IsSilentCloseEnabled(&connection_));
const QuicTime start_time = clock_.Now();
const QuicTime::Delta initial_idle_timeout =
@@ -5716,8 +5687,7 @@ TEST_P(QuicConnectionTest, TimeoutAfterRetransmission) {
SendStreamDataToPeer(
GetNthClientInitiatedStreamId(1, connection_.transport_version()), "foo",
0, FIN, nullptr);
- if (GetQuicReloadableFlag(quic_use_blackhole_detector) &&
- GetQuicReloadableFlag(quic_use_idle_network_detector)) {
+ if (GetQuicReloadableFlag(quic_use_idle_network_detector)) {
EXPECT_EQ(default_timeout + five_ms,
connection_.GetTimeoutAlarm()->deadline());
} else {
@@ -5751,8 +5721,7 @@ TEST_P(QuicConnectionTest, TimeoutAfterRetransmission) {
ASSERT_EQ(default_timeout.ToDebuggingValue(),
clock_.Now().ToDebuggingValue());
EXPECT_EQ(default_timeout, clock_.Now());
- if (!GetQuicReloadableFlag(quic_use_blackhole_detector) ||
- !GetQuicReloadableFlag(quic_use_idle_network_detector)) {
+ if (!GetQuicReloadableFlag(quic_use_idle_network_detector)) {
connection_.GetTimeoutAlarm()->Fire();
}
EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet());
@@ -5773,9 +5742,9 @@ TEST_P(QuicConnectionTest, TimeoutAfterRetransmission) {
TestConnectionCloseQuicErrorCode(QUIC_NETWORK_IDLE_TIMEOUT);
}
-TEST_P(QuicConnectionTest, NewTimeoutAfterSendSilentClose) {
- // Same test as above, but complete a handshake which enables silent close,
- // causing no connection close packet to be sent.
+TEST_P(QuicConnectionTest, TimeoutAfterSendAfterHandshake) {
+ // When the idle timeout fires, verify that by default we do not send any
+ // connection close packets.
EXPECT_TRUE(connection_.connected());
EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
QuicConfig config;
@@ -5789,18 +5758,16 @@ TEST_P(QuicConnectionTest, NewTimeoutAfterSendSilentClose) {
client_config.SetInitialSessionFlowControlWindowToSend(
kInitialSessionFlowControlWindowForTest);
client_config.SetIdleNetworkTimeout(
- QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs),
- QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs));
+ QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs));
client_config.ToHandshakeMessage(&msg, connection_.transport_version());
const QuicErrorCode error =
config.ProcessPeerHello(msg, CLIENT, &error_details);
EXPECT_THAT(error, IsQuicNoError());
connection_.SetFromConfig(config);
- EXPECT_TRUE(QuicConnectionPeer::IsSilentCloseEnabled(&connection_));
const QuicTime::Delta default_idle_timeout =
- QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs - 1);
+ QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs - 1);
const QuicTime::Delta five_ms = QuicTime::Delta::FromMilliseconds(5);
QuicTime default_timeout = clock_.ApproximateNow() + default_idle_timeout;
@@ -5810,8 +5777,7 @@ TEST_P(QuicConnectionTest, NewTimeoutAfterSendSilentClose) {
SendStreamDataToPeer(
GetNthClientInitiatedStreamId(1, connection_.transport_version()), "foo",
0, FIN, nullptr);
- if (GetQuicReloadableFlag(quic_use_blackhole_detector) &&
- GetQuicReloadableFlag(quic_use_idle_network_detector)) {
+ if (GetQuicReloadableFlag(quic_use_idle_network_detector)) {
EXPECT_EQ(default_timeout + five_ms,
connection_.GetTimeoutAlarm()->deadline());
} else {
@@ -5824,8 +5790,7 @@ TEST_P(QuicConnectionTest, NewTimeoutAfterSendSilentClose) {
SendStreamDataToPeer(
GetNthClientInitiatedStreamId(1, connection_.transport_version()), "foo",
3, FIN, nullptr);
- if (GetQuicReloadableFlag(quic_use_blackhole_detector) &&
- GetQuicReloadableFlag(quic_use_idle_network_detector)) {
+ if (GetQuicReloadableFlag(quic_use_idle_network_detector)) {
EXPECT_EQ(default_timeout + five_ms,
connection_.GetTimeoutAlarm()->deadline());
} else {
@@ -5836,8 +5801,7 @@ TEST_P(QuicConnectionTest, NewTimeoutAfterSendSilentClose) {
// network event at t=5ms. The alarm will reregister.
clock_.AdvanceTime(default_idle_timeout - five_ms - five_ms);
EXPECT_EQ(default_timeout, clock_.ApproximateNow());
- if (!GetQuicReloadableFlag(quic_use_blackhole_detector) ||
- !GetQuicReloadableFlag(quic_use_idle_network_detector)) {
+ if (!GetQuicReloadableFlag(quic_use_idle_network_detector)) {
connection_.GetTimeoutAlarm()->Fire();
}
EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet());
@@ -5866,8 +5830,7 @@ TEST_P(QuicConnectionTest, TimeoutAfterSendSilentCloseAndTLP) {
if (connection_.PtoEnabled()) {
return;
}
- // Same test as above, but complete a handshake which enables silent close,
- // but sending TLPs causes the connection close to be sent.
+ // Same test as above, but sending TLPs causes a connection close to be sent.
EXPECT_TRUE(connection_.connected());
EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
QuicConfig config;
@@ -5881,18 +5844,16 @@ TEST_P(QuicConnectionTest, TimeoutAfterSendSilentCloseAndTLP) {
client_config.SetInitialSessionFlowControlWindowToSend(
kInitialSessionFlowControlWindowForTest);
client_config.SetIdleNetworkTimeout(
- QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs),
- QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs));
+ QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs));
client_config.ToHandshakeMessage(&msg, connection_.transport_version());
const QuicErrorCode error =
config.ProcessPeerHello(msg, CLIENT, &error_details);
EXPECT_THAT(error, IsQuicNoError());
connection_.SetFromConfig(config);
- EXPECT_TRUE(QuicConnectionPeer::IsSilentCloseEnabled(&connection_));
const QuicTime::Delta default_idle_timeout =
- QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs - 1);
+ QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs - 1);
const QuicTime::Delta five_ms = QuicTime::Delta::FromMilliseconds(5);
QuicTime default_timeout = clock_.ApproximateNow() + default_idle_timeout;
@@ -5902,8 +5863,7 @@ TEST_P(QuicConnectionTest, TimeoutAfterSendSilentCloseAndTLP) {
SendStreamDataToPeer(
GetNthClientInitiatedStreamId(1, connection_.transport_version()), "foo",
0, FIN, nullptr);
- if (GetQuicReloadableFlag(quic_use_blackhole_detector) &&
- GetQuicReloadableFlag(quic_use_idle_network_detector)) {
+ if (GetQuicReloadableFlag(quic_use_idle_network_detector)) {
EXPECT_EQ(default_timeout + five_ms,
connection_.GetTimeoutAlarm()->deadline());
} else {
@@ -5929,8 +5889,8 @@ TEST_P(QuicConnectionTest, TimeoutAfterSendSilentCloseAndTLP) {
}
TEST_P(QuicConnectionTest, TimeoutAfterSendSilentCloseWithOpenStreams) {
- // Same test as above, but complete a handshake which enables silent close,
- // but having open streams causes the connection close to be sent.
+ // Same test as above, but having open streams causes a connection close
+ // to be sent.
EXPECT_TRUE(connection_.connected());
EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
QuicConfig config;
@@ -5944,18 +5904,16 @@ TEST_P(QuicConnectionTest, TimeoutAfterSendSilentCloseWithOpenStreams) {
client_config.SetInitialSessionFlowControlWindowToSend(
kInitialSessionFlowControlWindowForTest);
client_config.SetIdleNetworkTimeout(
- QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs),
- QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs));
+ QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs));
client_config.ToHandshakeMessage(&msg, connection_.transport_version());
const QuicErrorCode error =
config.ProcessPeerHello(msg, CLIENT, &error_details);
EXPECT_THAT(error, IsQuicNoError());
connection_.SetFromConfig(config);
- EXPECT_TRUE(QuicConnectionPeer::IsSilentCloseEnabled(&connection_));
const QuicTime::Delta default_idle_timeout =
- QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs - 1);
+ QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs - 1);
const QuicTime::Delta five_ms = QuicTime::Delta::FromMilliseconds(5);
QuicTime default_timeout = clock_.ApproximateNow() + default_idle_timeout;
@@ -5965,8 +5923,7 @@ TEST_P(QuicConnectionTest, TimeoutAfterSendSilentCloseWithOpenStreams) {
SendStreamDataToPeer(
GetNthClientInitiatedStreamId(1, connection_.transport_version()), "foo",
0, FIN, nullptr);
- if (GetQuicReloadableFlag(quic_use_blackhole_detector) &&
- GetQuicReloadableFlag(quic_use_idle_network_detector)) {
+ if (GetQuicReloadableFlag(quic_use_idle_network_detector)) {
EXPECT_EQ(default_timeout + five_ms,
connection_.GetTimeoutAlarm()->deadline());
} else {
@@ -5995,7 +5952,6 @@ TEST_P(QuicConnectionTest, TimeoutAfterReceive) {
EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
QuicConfig config;
connection_.SetFromConfig(config);
- EXPECT_FALSE(QuicConnectionPeer::IsSilentCloseEnabled(&connection_));
const QuicTime::Delta initial_idle_timeout =
QuicTime::Delta::FromSeconds(kInitialIdleTimeoutSecs - 1);
@@ -6022,8 +5978,7 @@ TEST_P(QuicConnectionTest, TimeoutAfterReceive) {
// network event at t=5ms. The alarm will reregister.
clock_.AdvanceTime(initial_idle_timeout - five_ms);
EXPECT_EQ(default_timeout, clock_.ApproximateNow());
- if (!GetQuicReloadableFlag(quic_use_blackhole_detector) ||
- !GetQuicReloadableFlag(quic_use_idle_network_detector)) {
+ if (!GetQuicReloadableFlag(quic_use_idle_network_detector)) {
connection_.GetTimeoutAlarm()->Fire();
}
EXPECT_TRUE(connection_.connected());
@@ -6049,7 +6004,6 @@ TEST_P(QuicConnectionTest, TimeoutAfterReceiveNotSendWhenUnacked) {
EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
QuicConfig config;
connection_.SetFromConfig(config);
- EXPECT_FALSE(QuicConnectionPeer::IsSilentCloseEnabled(&connection_));
const QuicTime::Delta initial_idle_timeout =
QuicTime::Delta::FromSeconds(kInitialIdleTimeoutSecs - 1);
@@ -6082,8 +6036,7 @@ TEST_P(QuicConnectionTest, TimeoutAfterReceiveNotSendWhenUnacked) {
// network event at t=5ms. The alarm will reregister.
clock_.AdvanceTime(initial_idle_timeout - five_ms);
EXPECT_EQ(default_timeout, clock_.ApproximateNow());
- if (!GetQuicReloadableFlag(quic_use_blackhole_detector) ||
- !GetQuicReloadableFlag(quic_use_idle_network_detector)) {
+ if (!GetQuicReloadableFlag(quic_use_idle_network_detector)) {
connection_.GetTimeoutAlarm()->Fire();
}
EXPECT_TRUE(connection_.connected());
@@ -6120,8 +6073,7 @@ TEST_P(QuicConnectionTest, TimeoutAfter5ClientRTOs) {
QuicTagVector connection_options;
connection_options.push_back(k5RTO);
config.SetConnectionOptionsToSend(connection_options);
- QuicConfigPeer::ReceiveIdleNetworkTimeout(&config, SERVER,
- kDefaultIdleTimeoutSecs);
+ QuicConfigPeer::SetNegotiated(&config, true);
connection_.SetFromConfig(config);
// Send stream data.
@@ -6136,10 +6088,8 @@ TEST_P(QuicConnectionTest, TimeoutAfter5ClientRTOs) {
EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet());
EXPECT_TRUE(connection_.connected());
}
- if (GetQuicReloadableFlag(quic_use_blackhole_detector)) {
- EXPECT_CALL(visitor_, OnPathDegrading());
- connection_.PathDegradingTimeout();
- }
+ EXPECT_CALL(visitor_, OnPathDegrading());
+ connection_.PathDegradingTimeout();
EXPECT_EQ(2u, connection_.sent_packet_manager().GetConsecutiveTlpCount());
EXPECT_EQ(4u, connection_.sent_packet_manager().GetConsecutiveRtoCount());
@@ -6147,12 +6097,8 @@ TEST_P(QuicConnectionTest, TimeoutAfter5ClientRTOs) {
EXPECT_CALL(visitor_,
OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF));
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(1));
- if (GetQuicReloadableFlag(quic_use_blackhole_detector)) {
- ASSERT_TRUE(connection_.BlackholeDetectionInProgress());
- connection_.GetBlackholeDetectorAlarm()->Fire();
- } else {
- connection_.GetRetransmissionAlarm()->Fire();
- }
+ ASSERT_TRUE(connection_.BlackholeDetectionInProgress());
+ connection_.GetBlackholeDetectorAlarm()->Fire();
EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet());
EXPECT_FALSE(connection_.connected());
TestConnectionCloseQuicErrorCode(QUIC_TOO_MANY_RTOS);
@@ -7207,7 +7153,8 @@ TEST_P(QuicConnectionTest, BundleAckWithDataOnIncomingAck) {
lost_packets.push_back(
LostPacket(QuicPacketNumber(1), kMaxOutgoingPacketSize));
EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _))
- .WillOnce(SetArgPointee<5>(lost_packets));
+ .WillOnce(DoAll(SetArgPointee<5>(lost_packets),
+ Return(LossDetectionInterface::DetectionStats())));
EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
ProcessAckPacket(&ack);
size_t padding_frame_count = writer_->padding_frames().size();
@@ -7425,31 +7372,31 @@ TEST_P(QuicConnectionTest, GoAway) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- QuicGoAwayFrame goaway;
- goaway.last_good_stream_id = 1;
- goaway.error_code = QUIC_PEER_GOING_AWAY;
- goaway.reason_phrase = "Going away.";
+ QuicGoAwayFrame* goaway = new QuicGoAwayFrame();
+ goaway->last_good_stream_id = 1;
+ goaway->error_code = QUIC_PEER_GOING_AWAY;
+ goaway->reason_phrase = "Going away.";
EXPECT_CALL(visitor_, OnGoAway(_));
- ProcessGoAwayPacket(&goaway);
+ ProcessGoAwayPacket(goaway);
}
TEST_P(QuicConnectionTest, WindowUpdate) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- QuicWindowUpdateFrame window_update;
- window_update.stream_id = 3;
- window_update.max_data = 1234;
+ QuicWindowUpdateFrame* window_update = new QuicWindowUpdateFrame();
+ window_update->stream_id = 3;
+ window_update->max_data = 1234;
EXPECT_CALL(visitor_, OnWindowUpdateFrame(_));
- ProcessFramePacket(QuicFrame(&window_update));
+ ProcessFramePacket(QuicFrame(window_update));
}
TEST_P(QuicConnectionTest, Blocked) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- QuicBlockedFrame blocked;
- blocked.stream_id = 3;
+ QuicBlockedFrame* blocked = new QuicBlockedFrame();
+ blocked->stream_id = 3;
EXPECT_CALL(visitor_, OnBlockedFrame(_));
- ProcessFramePacket(QuicFrame(&blocked));
+ ProcessFramePacket(QuicFrame(blocked));
EXPECT_EQ(1u, connection_.GetStats().blocked_frames_received);
EXPECT_EQ(0u, connection_.GetStats().blocked_frames_sent);
}
@@ -7552,7 +7499,8 @@ TEST_P(QuicConnectionTest, CheckSendStats) {
lost_packets.push_back(
LostPacket(QuicPacketNumber(3), kMaxOutgoingPacketSize));
EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _))
- .WillOnce(SetArgPointee<5>(lost_packets));
+ .WillOnce(DoAll(SetArgPointee<5>(lost_packets),
+ Return(LossDetectionInterface::DetectionStats())));
EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
ProcessAckPacket(&nack_three);
@@ -7621,7 +7569,7 @@ TEST_P(QuicConnectionTest, ProcessFramesIfPacketClosedConnection) {
kSelfAddress, kPeerAddress,
QuicReceivedPacket(buffer, encrypted_length, QuicTime::Zero(), false));
EXPECT_EQ(1, connection_close_frame_count_);
- EXPECT_THAT(saved_connection_close_frame_.extracted_error_code,
+ EXPECT_THAT(saved_connection_close_frame_.quic_error_code,
IsError(QUIC_PEER_GOING_AWAY));
}
@@ -7726,11 +7674,11 @@ TEST_P(QuicConnectionTest, WindowUpdateInstigateAcks) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
// Send a WINDOW_UPDATE frame.
- QuicWindowUpdateFrame window_update;
- window_update.stream_id = 3;
- window_update.max_data = 1234;
+ QuicWindowUpdateFrame* window_update = new QuicWindowUpdateFrame();
+ window_update->stream_id = 3;
+ window_update->max_data = 1234;
EXPECT_CALL(visitor_, OnWindowUpdateFrame(_));
- ProcessFramePacket(QuicFrame(&window_update));
+ ProcessFramePacket(QuicFrame(window_update));
// Ensure that this has caused the ACK alarm to be set.
QuicAlarm* ack_alarm = QuicConnectionPeer::GetAckAlarm(&connection_);
@@ -7741,10 +7689,10 @@ TEST_P(QuicConnectionTest, BlockedFrameInstigateAcks) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
// Send a BLOCKED frame.
- QuicBlockedFrame blocked;
- blocked.stream_id = 3;
+ QuicBlockedFrame* blocked = new QuicBlockedFrame();
+ blocked->stream_id = 3;
EXPECT_CALL(visitor_, OnBlockedFrame(_));
- ProcessFramePacket(QuicFrame(&blocked));
+ ProcessFramePacket(QuicFrame(blocked));
// Ensure that this has caused the ACK alarm to be set.
QuicAlarm* ack_alarm = QuicConnectionPeer::GetAckAlarm(&connection_);
@@ -7902,13 +7850,8 @@ TEST_P(QuicConnectionTest, PathDegradingAlarmForCryptoPacket) {
EXPECT_FALSE(connection_.IsPathDegrading());
QuicTime::Delta delay = QuicConnectionPeer::GetSentPacketManager(&connection_)
->GetPathDegradingDelay();
- if (GetQuicReloadableFlag(quic_use_blackhole_detector)) {
- EXPECT_EQ(delay, connection_.GetBlackholeDetectorAlarm()->deadline() -
- clock_.ApproximateNow());
- } else {
- EXPECT_EQ(delay, connection_.GetPathDegradingAlarm()->deadline() -
- clock_.ApproximateNow());
- }
+ EXPECT_EQ(delay, connection_.GetBlackholeDetectorAlarm()->deadline() -
+ clock_.ApproximateNow());
// Fire the path degrading alarm, path degrading signal should be sent to
// the visitor.
@@ -7941,33 +7884,22 @@ TEST_P(QuicConnectionTest, PathDegradingAlarmForNonCryptoPackets) {
QuicTime::Delta delay =
QuicConnectionPeer::GetSentPacketManager(&connection_)
->GetPathDegradingDelay();
- if (GetQuicReloadableFlag(quic_use_blackhole_detector)) {
- EXPECT_EQ(delay, connection_.GetBlackholeDetectorAlarm()->deadline() -
- clock_.ApproximateNow());
- } else {
- EXPECT_EQ(delay, connection_.GetPathDegradingAlarm()->deadline() -
- clock_.ApproximateNow());
- }
+ EXPECT_EQ(delay, connection_.GetBlackholeDetectorAlarm()->deadline() -
+ clock_.ApproximateNow());
// Send a second packet. The path degrading alarm's deadline should remain
// the same.
// Regression test for b/69979024.
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
- QuicTime prev_deadline = connection_.GetPathDegradingAlarm()->deadline();
- if (GetQuicReloadableFlag(quic_use_blackhole_detector)) {
- prev_deadline = connection_.GetBlackholeDetectorAlarm()->deadline();
- }
+ QuicTime prev_deadline =
+ connection_.GetBlackholeDetectorAlarm()->deadline();
connection_.SendStreamDataWithString(
GetNthClientInitiatedStreamId(1, connection_.transport_version()), data,
offset, NO_FIN);
offset += data_size;
EXPECT_TRUE(connection_.PathDegradingDetectionInProgress());
- if (GetQuicReloadableFlag(quic_use_blackhole_detector)) {
- EXPECT_EQ(prev_deadline,
- connection_.GetBlackholeDetectorAlarm()->deadline());
- } else {
- EXPECT_EQ(prev_deadline, connection_.GetPathDegradingAlarm()->deadline());
- }
+ EXPECT_EQ(prev_deadline,
+ connection_.GetBlackholeDetectorAlarm()->deadline());
// Now receive an ACK of the first packet. This should advance the path
// degrading alarm's deadline since forward progress has been made.
@@ -7983,13 +7915,8 @@ TEST_P(QuicConnectionTest, PathDegradingAlarmForNonCryptoPackets) {
// Check the deadline of the path degrading alarm.
delay = QuicConnectionPeer::GetSentPacketManager(&connection_)
->GetPathDegradingDelay();
- if (GetQuicReloadableFlag(quic_use_blackhole_detector)) {
- EXPECT_EQ(delay, connection_.GetBlackholeDetectorAlarm()->deadline() -
- clock_.ApproximateNow());
- } else {
- EXPECT_EQ(delay, connection_.GetPathDegradingAlarm()->deadline() -
- clock_.ApproximateNow());
- }
+ EXPECT_EQ(delay, connection_.GetBlackholeDetectorAlarm()->deadline() -
+ clock_.ApproximateNow());
if (i == 0) {
// Now receive an ACK of the second packet. Since there are no more
@@ -8039,13 +7966,8 @@ TEST_P(QuicConnectionTest, RetransmittableOnWireSetsPingAlarm) {
EXPECT_TRUE(connection_.PathDegradingDetectionInProgress());
QuicTime::Delta delay = QuicConnectionPeer::GetSentPacketManager(&connection_)
->GetPathDegradingDelay();
- if (GetQuicReloadableFlag(quic_use_blackhole_detector)) {
- EXPECT_EQ(delay, connection_.GetBlackholeDetectorAlarm()->deadline() -
- clock_.ApproximateNow());
- } else {
- EXPECT_EQ(delay, connection_.GetPathDegradingAlarm()->deadline() -
- clock_.ApproximateNow());
- }
+ EXPECT_EQ(delay, connection_.GetBlackholeDetectorAlarm()->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.
@@ -8081,13 +8003,8 @@ TEST_P(QuicConnectionTest, RetransmittableOnWireSetsPingAlarm) {
EXPECT_TRUE(connection_.PathDegradingDetectionInProgress());
delay = QuicConnectionPeer::GetSentPacketManager(&connection_)
->GetPathDegradingDelay();
- if (GetQuicReloadableFlag(quic_use_blackhole_detector)) {
- EXPECT_EQ(delay, connection_.GetBlackholeDetectorAlarm()->deadline() -
- clock_.ApproximateNow());
- } else {
- EXPECT_EQ(delay, connection_.GetPathDegradingAlarm()->deadline() -
- clock_.ApproximateNow());
- }
+ EXPECT_EQ(delay, connection_.GetBlackholeDetectorAlarm()->deadline() -
+ clock_.ApproximateNow());
}
// This test verifies that the connection marks path as degrading and does not
@@ -8110,30 +8027,17 @@ TEST_P(QuicConnectionTest, NoPathDegradingAlarmIfPathIsDegrading) {
// Check the deadline of the path degrading alarm.
QuicTime::Delta delay = QuicConnectionPeer::GetSentPacketManager(&connection_)
->GetPathDegradingDelay();
- if (GetQuicReloadableFlag(quic_use_blackhole_detector)) {
- EXPECT_EQ(delay, connection_.GetBlackholeDetectorAlarm()->deadline() -
- clock_.ApproximateNow());
- } else {
- EXPECT_EQ(delay, connection_.GetPathDegradingAlarm()->deadline() -
- clock_.ApproximateNow());
- }
+ EXPECT_EQ(delay, connection_.GetBlackholeDetectorAlarm()->deadline() -
+ clock_.ApproximateNow());
// Send a second packet. The path degrading alarm's deadline should remain
// the same.
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
- QuicTime prev_deadline = connection_.GetPathDegradingAlarm()->deadline();
- if (GetQuicReloadableFlag(quic_use_blackhole_detector)) {
- prev_deadline = connection_.GetBlackholeDetectorAlarm()->deadline();
- }
+ QuicTime prev_deadline = connection_.GetBlackholeDetectorAlarm()->deadline();
connection_.SendStreamDataWithString(1, data, offset, NO_FIN);
offset += data_size;
EXPECT_TRUE(connection_.PathDegradingDetectionInProgress());
- if (GetQuicReloadableFlag(quic_use_blackhole_detector)) {
- EXPECT_EQ(prev_deadline,
- connection_.GetBlackholeDetectorAlarm()->deadline());
- } else {
- EXPECT_EQ(prev_deadline, connection_.GetPathDegradingAlarm()->deadline());
- }
+ EXPECT_EQ(prev_deadline, connection_.GetBlackholeDetectorAlarm()->deadline());
// Now receive an ACK of the first packet. This should advance the path
// degrading alarm's deadline since forward progress has been made.
@@ -8147,13 +8051,8 @@ TEST_P(QuicConnectionTest, NoPathDegradingAlarmIfPathIsDegrading) {
// Check the deadline of the path degrading alarm.
delay = QuicConnectionPeer::GetSentPacketManager(&connection_)
->GetPathDegradingDelay();
- if (GetQuicReloadableFlag(quic_use_blackhole_detector)) {
- EXPECT_EQ(delay, connection_.GetBlackholeDetectorAlarm()->deadline() -
- clock_.ApproximateNow());
- } else {
- EXPECT_EQ(delay, connection_.GetPathDegradingAlarm()->deadline() -
- clock_.ApproximateNow());
- }
+ EXPECT_EQ(delay, connection_.GetBlackholeDetectorAlarm()->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
@@ -8194,30 +8093,17 @@ TEST_P(QuicConnectionTest, UnmarkPathDegradingOnForwardProgress) {
// Check the deadline of the path degrading alarm.
QuicTime::Delta delay = QuicConnectionPeer::GetSentPacketManager(&connection_)
->GetPathDegradingDelay();
- if (GetQuicReloadableFlag(quic_use_blackhole_detector)) {
- EXPECT_EQ(delay, connection_.GetBlackholeDetectorAlarm()->deadline() -
- clock_.ApproximateNow());
- } else {
- EXPECT_EQ(delay, connection_.GetPathDegradingAlarm()->deadline() -
- clock_.ApproximateNow());
- }
+ EXPECT_EQ(delay, connection_.GetBlackholeDetectorAlarm()->deadline() -
+ clock_.ApproximateNow());
// Send a second packet. The path degrading alarm's deadline should remain
// the same.
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
- QuicTime prev_deadline = connection_.GetPathDegradingAlarm()->deadline();
- if (GetQuicReloadableFlag(quic_use_blackhole_detector)) {
- prev_deadline = connection_.GetBlackholeDetectorAlarm()->deadline();
- }
+ QuicTime prev_deadline = connection_.GetBlackholeDetectorAlarm()->deadline();
connection_.SendStreamDataWithString(1, data, offset, NO_FIN);
offset += data_size;
EXPECT_TRUE(connection_.PathDegradingDetectionInProgress());
- if (GetQuicReloadableFlag(quic_use_blackhole_detector)) {
- EXPECT_EQ(prev_deadline,
- connection_.GetBlackholeDetectorAlarm()->deadline());
- } else {
- EXPECT_EQ(prev_deadline, connection_.GetPathDegradingAlarm()->deadline());
- }
+ EXPECT_EQ(prev_deadline, connection_.GetBlackholeDetectorAlarm()->deadline());
// Now receive an ACK of the first packet. This should advance the path
// degrading alarm's deadline since forward progress has been made.
@@ -8231,13 +8117,8 @@ TEST_P(QuicConnectionTest, UnmarkPathDegradingOnForwardProgress) {
// Check the deadline of the path degrading alarm.
delay = QuicConnectionPeer::GetSentPacketManager(&connection_)
->GetPathDegradingDelay();
- if (GetQuicReloadableFlag(quic_use_blackhole_detector)) {
- EXPECT_EQ(delay, connection_.GetBlackholeDetectorAlarm()->deadline() -
- clock_.ApproximateNow());
- } else {
- EXPECT_EQ(delay, connection_.GetPathDegradingAlarm()->deadline() -
- clock_.ApproximateNow());
- }
+ EXPECT_EQ(delay, connection_.GetBlackholeDetectorAlarm()->deadline() -
+ clock_.ApproximateNow());
// Advance time to the path degrading alarm's deadline and simulate
// firing the alarm.
@@ -9166,6 +9047,13 @@ TEST_P(QuicConnectionTest, SendMessage) {
if (!VersionSupportsMessageFrames(connection_.transport_version())) {
return;
}
+ if (connection_.version().UsesTls()) {
+ QuicConfig config;
+ QuicConfigPeer::SetReceivedMaxDatagramFrameSize(
+ &config, kMaxAcceptedDatagramFrameSize);
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ connection_.SetFromConfig(config);
+ }
std::string message(connection_.GetCurrentLargestMessagePayload() * 2, 'a');
quiche::QuicheStringPiece message_data(message);
QuicMemSliceStorage storage(nullptr, 0, nullptr, 0);
@@ -9208,6 +9096,94 @@ TEST_P(QuicConnectionTest, SendMessage) {
false));
}
+TEST_P(QuicConnectionTest, GetCurrentLargestMessagePayload) {
+ if (!connection_.version().SupportsMessageFrames()) {
+ return;
+ }
+ // Force use of this encrypter to simplify test expectations by making sure
+ // that the encryption overhead is constant across versions.
+ connection_.SetEncrypter(ENCRYPTION_INITIAL,
+ std::make_unique<TaggingEncrypter>(0x00));
+ QuicPacketLength expected_largest_payload = 1319;
+ if (connection_.version().SendsVariableLengthPacketNumberInLongHeader()) {
+ expected_largest_payload += 3;
+ }
+ if (connection_.version().HasLongHeaderLengths()) {
+ expected_largest_payload -= 2;
+ }
+ if (connection_.version().HasLengthPrefixedConnectionIds()) {
+ expected_largest_payload -= 1;
+ }
+ if (connection_.version().UsesTls()) {
+ // QUIC+TLS disallows DATAGRAM/MESSAGE frames before the handshake.
+ EXPECT_EQ(connection_.GetCurrentLargestMessagePayload(), 0);
+ QuicConfig config;
+ QuicConfigPeer::SetReceivedMaxDatagramFrameSize(
+ &config, kMaxAcceptedDatagramFrameSize);
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ connection_.SetFromConfig(config);
+ // Verify the value post-handshake.
+ EXPECT_EQ(connection_.GetCurrentLargestMessagePayload(),
+ expected_largest_payload);
+ } else {
+ EXPECT_EQ(connection_.GetCurrentLargestMessagePayload(),
+ expected_largest_payload);
+ }
+}
+
+TEST_P(QuicConnectionTest, GetGuaranteedLargestMessagePayload) {
+ if (!connection_.version().SupportsMessageFrames()) {
+ return;
+ }
+ // Force use of this encrypter to simplify test expectations by making sure
+ // that the encryption overhead is constant across versions.
+ connection_.SetEncrypter(ENCRYPTION_INITIAL,
+ std::make_unique<TaggingEncrypter>(0x00));
+ QuicPacketLength expected_largest_payload = 1319;
+ if (connection_.version().HasLongHeaderLengths()) {
+ expected_largest_payload -= 2;
+ }
+ if (connection_.version().HasLengthPrefixedConnectionIds()) {
+ expected_largest_payload -= 1;
+ }
+ if (connection_.version().UsesTls()) {
+ // QUIC+TLS disallows DATAGRAM/MESSAGE frames before the handshake.
+ EXPECT_EQ(connection_.GetGuaranteedLargestMessagePayload(), 0);
+ QuicConfig config;
+ QuicConfigPeer::SetReceivedMaxDatagramFrameSize(
+ &config, kMaxAcceptedDatagramFrameSize);
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ connection_.SetFromConfig(config);
+ // Verify the value post-handshake.
+ EXPECT_EQ(connection_.GetGuaranteedLargestMessagePayload(),
+ expected_largest_payload);
+ } else {
+ EXPECT_EQ(connection_.GetGuaranteedLargestMessagePayload(),
+ expected_largest_payload);
+ }
+}
+
+TEST_P(QuicConnectionTest, LimitedLargestMessagePayload) {
+ if (!connection_.version().SupportsMessageFrames() ||
+ !connection_.version().UsesTls()) {
+ return;
+ }
+ constexpr QuicPacketLength kFrameSizeLimit = 1000;
+ constexpr QuicPacketLength kPayloadSizeLimit =
+ kFrameSizeLimit - kQuicFrameTypeSize;
+ // QUIC+TLS disallows DATAGRAM/MESSAGE frames before the handshake.
+ EXPECT_EQ(connection_.GetCurrentLargestMessagePayload(), 0);
+ EXPECT_EQ(connection_.GetGuaranteedLargestMessagePayload(), 0);
+ QuicConfig config;
+ QuicConfigPeer::SetReceivedMaxDatagramFrameSize(&config, kFrameSizeLimit);
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ connection_.SetFromConfig(config);
+ // Verify the value post-handshake.
+ EXPECT_EQ(connection_.GetCurrentLargestMessagePayload(), kPayloadSizeLimit);
+ EXPECT_EQ(connection_.GetGuaranteedLargestMessagePayload(),
+ kPayloadSizeLimit);
+}
+
// Test to check that the path challenge/path response logic works
// correctly. This test is only for version-99
TEST_P(QuicConnectionTest, PathChallengeResponse) {
@@ -9318,17 +9294,13 @@ TEST_P(QuicConnectionTest, StopProcessingGQuicPacketInIetfQuicConnection) {
return;
}
set_perspective(Perspective::IS_SERVER);
- QuicFrame frame;
if (QuicVersionUsesCryptoFrames(connection_.transport_version())) {
- frame = QuicFrame(&crypto_frame_);
EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(1);
} else {
- frame = QuicFrame(QuicStreamFrame(
- QuicUtils::GetCryptoStreamId(connection_.transport_version()), false,
- 0u, quiche::QuicheStringPiece()));
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
}
- ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress);
+ ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress,
+ kPeerAddress);
// Let connection process a Google QUIC packet.
peer_framer_.set_version_for_tests(
@@ -9639,20 +9611,16 @@ TEST_P(QuicConnectionTest, CheckConnectedBeforeFlush) {
/*transport_close_frame_type=*/0));
// Received 2 packets.
- QuicFrame frame;
if (QuicVersionUsesCryptoFrames(connection_.transport_version())) {
- frame = QuicFrame(&crypto_frame_);
EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber());
} else {
- frame = QuicFrame(QuicStreamFrame(
- QuicUtils::GetCryptoStreamId(connection_.transport_version()), false,
- 0u, quiche::QuicheStringPiece()));
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber());
}
- ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress);
+ ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress,
+ kPeerAddress);
QuicAlarm* ack_alarm = QuicConnectionPeer::GetAckAlarm(&connection_);
EXPECT_TRUE(ack_alarm->IsSet());
- ProcessFramePacketWithAddresses(QuicFrame(connection_close_frame.get()),
+ ProcessFramePacketWithAddresses(QuicFrame(connection_close_frame.release()),
kSelfAddress, kPeerAddress);
// Verify ack alarm is not set.
EXPECT_FALSE(ack_alarm->IsSet());
@@ -9892,8 +9860,7 @@ TEST_P(QuicConnectionTest, CloseConnectionAfter6ClientPTOs) {
connection_options.push_back(k1PTO);
connection_options.push_back(k6PTO);
config.SetConnectionOptionsToSend(connection_options);
- QuicConfigPeer::ReceiveIdleNetworkTimeout(&config, SERVER,
- kDefaultIdleTimeoutSecs);
+ QuicConfigPeer::SetNegotiated(&config, true);
EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
connection_.SetFromConfig(config);
EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
@@ -9903,32 +9870,26 @@ TEST_P(QuicConnectionTest, CloseConnectionAfter6ClientPTOs) {
GetNthClientInitiatedStreamId(1, connection_.transport_version()), "foo",
0, FIN, nullptr);
- // 5PTO + 1 connection close.
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(6));
-
// Fire the retransmission alarm 5 times.
for (int i = 0; i < 5; ++i) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
connection_.GetRetransmissionAlarm()->Fire();
EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet());
EXPECT_TRUE(connection_.connected());
}
- if (GetQuicReloadableFlag(quic_use_blackhole_detector)) {
- EXPECT_CALL(visitor_, OnPathDegrading());
- connection_.PathDegradingTimeout();
- }
+ EXPECT_CALL(visitor_, OnPathDegrading());
+ connection_.PathDegradingTimeout();
EXPECT_EQ(0u, connection_.sent_packet_manager().GetConsecutiveTlpCount());
EXPECT_EQ(0u, connection_.sent_packet_manager().GetConsecutiveRtoCount());
EXPECT_EQ(5u, connection_.sent_packet_manager().GetConsecutivePtoCount());
// Closes connection on 6th PTO.
+ // May send multiple connecction close packets with multiple PN spaces.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(1));
EXPECT_CALL(visitor_,
OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF));
- if (GetQuicReloadableFlag(quic_use_blackhole_detector)) {
- ASSERT_TRUE(connection_.BlackholeDetectionInProgress());
- connection_.GetBlackholeDetectorAlarm()->Fire();
- } else {
- connection_.GetRetransmissionAlarm()->Fire();
- }
+ ASSERT_TRUE(connection_.BlackholeDetectionInProgress());
+ connection_.GetBlackholeDetectorAlarm()->Fire();
EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet());
EXPECT_FALSE(connection_.connected());
TestConnectionCloseQuicErrorCode(QUIC_TOO_MANY_RTOS);
@@ -9940,8 +9901,7 @@ TEST_P(QuicConnectionTest, CloseConnectionAfter7ClientPTOs) {
connection_options.push_back(k2PTO);
connection_options.push_back(k7PTO);
config.SetConnectionOptionsToSend(connection_options);
- QuicConfigPeer::ReceiveIdleNetworkTimeout(&config, SERVER,
- kDefaultIdleTimeoutSecs);
+ QuicConfigPeer::SetNegotiated(&config, true);
EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
connection_.SetFromConfig(config);
EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
@@ -9958,10 +9918,8 @@ TEST_P(QuicConnectionTest, CloseConnectionAfter7ClientPTOs) {
EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet());
EXPECT_TRUE(connection_.connected());
}
- if (GetQuicReloadableFlag(quic_use_blackhole_detector)) {
- EXPECT_CALL(visitor_, OnPathDegrading());
- connection_.PathDegradingTimeout();
- }
+ EXPECT_CALL(visitor_, OnPathDegrading());
+ connection_.PathDegradingTimeout();
EXPECT_EQ(0u, connection_.sent_packet_manager().GetConsecutiveTlpCount());
EXPECT_EQ(0u, connection_.sent_packet_manager().GetConsecutiveRtoCount());
@@ -9970,12 +9928,8 @@ TEST_P(QuicConnectionTest, CloseConnectionAfter7ClientPTOs) {
EXPECT_CALL(visitor_,
OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF));
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(1));
- if (GetQuicReloadableFlag(quic_use_blackhole_detector)) {
- ASSERT_TRUE(connection_.BlackholeDetectionInProgress());
- connection_.GetBlackholeDetectorAlarm()->Fire();
- } else {
- connection_.GetRetransmissionAlarm()->Fire();
- }
+ ASSERT_TRUE(connection_.BlackholeDetectionInProgress());
+ connection_.GetBlackholeDetectorAlarm()->Fire();
EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet());
EXPECT_FALSE(connection_.connected());
TestConnectionCloseQuicErrorCode(QUIC_TOO_MANY_RTOS);
@@ -9986,8 +9940,7 @@ TEST_P(QuicConnectionTest, CloseConnectionAfter8ClientPTOs) {
QuicTagVector connection_options;
connection_options.push_back(k2PTO);
connection_options.push_back(k8PTO);
- QuicConfigPeer::ReceiveIdleNetworkTimeout(&config, SERVER,
- kDefaultIdleTimeoutSecs);
+ QuicConfigPeer::SetNegotiated(&config, true);
config.SetConnectionOptionsToSend(connection_options);
EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
connection_.SetFromConfig(config);
@@ -10005,10 +9958,8 @@ TEST_P(QuicConnectionTest, CloseConnectionAfter8ClientPTOs) {
EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet());
EXPECT_TRUE(connection_.connected());
}
- if (GetQuicReloadableFlag(quic_use_blackhole_detector)) {
- EXPECT_CALL(visitor_, OnPathDegrading());
- connection_.PathDegradingTimeout();
- }
+ EXPECT_CALL(visitor_, OnPathDegrading());
+ connection_.PathDegradingTimeout();
EXPECT_EQ(0u, connection_.sent_packet_manager().GetConsecutiveTlpCount());
EXPECT_EQ(0u, connection_.sent_packet_manager().GetConsecutiveRtoCount());
@@ -10017,12 +9968,8 @@ TEST_P(QuicConnectionTest, CloseConnectionAfter8ClientPTOs) {
EXPECT_CALL(visitor_,
OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF));
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(1));
- if (GetQuicReloadableFlag(quic_use_blackhole_detector)) {
- ASSERT_TRUE(connection_.BlackholeDetectionInProgress());
- connection_.GetBlackholeDetectorAlarm()->Fire();
- } else {
- connection_.GetRetransmissionAlarm()->Fire();
- }
+ ASSERT_TRUE(connection_.BlackholeDetectionInProgress());
+ connection_.GetBlackholeDetectorAlarm()->Fire();
EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet());
EXPECT_FALSE(connection_.connected());
TestConnectionCloseQuicErrorCode(QUIC_TOO_MANY_RTOS);
@@ -10032,7 +9979,6 @@ TEST_P(QuicConnectionTest, DeprecateHandshakeMode) {
if (!connection_.version().SupportsAntiAmplificationLimit()) {
return;
}
- SetQuicReloadableFlag(quic_send_ping_when_pto_skips_packet_number, true);
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
@@ -10054,7 +10000,12 @@ TEST_P(QuicConnectionTest, DeprecateHandshakeMode) {
EXPECT_EQ(0u, connection_.GetStats().crypto_retransmit_count);
// PTO fires, verify a PING packet gets sent because there is no data to send.
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(3), _, _));
+ EXPECT_CALL(*send_algorithm_,
+ OnPacketSent(_, _,
+ GetQuicReloadableFlag(quic_default_on_pto)
+ ? QuicPacketNumber(2)
+ : QuicPacketNumber(3),
+ _, _));
EXPECT_CALL(visitor_, SendPing()).WillOnce(Invoke([this]() { SendPing(); }));
connection_.GetRetransmissionAlarm()->Fire();
EXPECT_EQ(1u, connection_.GetStats().pto_count);
@@ -10134,7 +10085,7 @@ TEST_P(QuicConnectionTest, ConnectionCloseFrameType) {
ASSERT_EQ(1u, connection_close_frames.size());
EXPECT_EQ(IETF_QUIC_TRANSPORT_CONNECTION_CLOSE,
connection_close_frames[0].close_type);
- EXPECT_EQ(kQuicErrorCode, connection_close_frames[0].extracted_error_code);
+ EXPECT_EQ(kQuicErrorCode, connection_close_frames[0].quic_error_code);
EXPECT_EQ(kTransportCloseFrameType,
connection_close_frames[0].transport_close_frame_type);
}
@@ -10216,6 +10167,7 @@ TEST_P(QuicConnectionTest, SendCoalescedPackets) {
connection_.set_debug_visitor(&debug_visitor);
EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _)).Times(3);
EXPECT_CALL(debug_visitor, OnCoalescedPacketSent(_, _)).Times(1);
+ EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1);
{
QuicConnection::ScopedPacketFlusher flusher(&connection_);
use_tagging_decrypter();
@@ -10287,6 +10239,7 @@ TEST_P(QuicConnectionTest, MultiplePacketNumberSpacePto) {
connection_.SetEncrypter(ENCRYPTION_HANDSHAKE,
std::make_unique<TaggingEncrypter>(0x02));
connection_.SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE);
+ EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1);
connection_.SendCryptoDataWithString("foo", 0, ENCRYPTION_HANDSHAKE);
EXPECT_EQ(0x02020202u, writer_->final_bytes_of_last_packet());
@@ -10300,7 +10253,13 @@ TEST_P(QuicConnectionTest, MultiplePacketNumberSpacePto) {
// Retransmit handshake data.
clock_.AdvanceTime(retransmission_time - clock_.Now());
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(4), _, _));
+ EXPECT_CALL(*send_algorithm_,
+ OnPacketSent(_, _,
+ GetQuicReloadableFlag(quic_default_on_pto)
+ ? QuicPacketNumber(3)
+ : QuicPacketNumber(4),
+ _, _));
+ EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1);
connection_.GetRetransmissionAlarm()->Fire();
EXPECT_EQ(0x02020202u, writer_->final_bytes_of_last_packet());
@@ -10313,7 +10272,13 @@ TEST_P(QuicConnectionTest, MultiplePacketNumberSpacePto) {
// Retransmit handshake data again.
clock_.AdvanceTime(retransmission_time - clock_.Now());
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(7), _, _));
+ EXPECT_CALL(*send_algorithm_,
+ OnPacketSent(_, _,
+ GetQuicReloadableFlag(quic_default_on_pto)
+ ? QuicPacketNumber(5)
+ : QuicPacketNumber(7),
+ _, _));
+ EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1);
connection_.GetRetransmissionAlarm()->Fire();
EXPECT_EQ(0x02020202u, writer_->final_bytes_of_last_packet());
@@ -10324,27 +10289,55 @@ TEST_P(QuicConnectionTest, MultiplePacketNumberSpacePto) {
// Retransmit application data.
clock_.AdvanceTime(retransmission_time - clock_.Now());
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(9), _, _));
+ EXPECT_CALL(*send_algorithm_,
+ OnPacketSent(_, _,
+ GetQuicReloadableFlag(quic_default_on_pto)
+ ? QuicPacketNumber(6)
+ : QuicPacketNumber(9),
+ _, _));
connection_.GetRetransmissionAlarm()->Fire();
EXPECT_EQ(0x01010101u, writer_->final_bytes_of_last_packet());
}
-TEST_P(QuicConnectionTest, ClientParsesRetry) {
+void QuicConnectionTest::TestClientRetryHandling(bool invalid_retry_tag,
+ bool missing_id_in_config,
+ bool wrong_id_in_config) {
+ if (invalid_retry_tag) {
+ ASSERT_FALSE(missing_id_in_config);
+ ASSERT_FALSE(wrong_id_in_config);
+ } else {
+ ASSERT_FALSE(missing_id_in_config && wrong_id_in_config);
+ }
if (!version().HasRetryIntegrityTag()) {
return;
}
- if (version() !=
- ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_25)) {
+
+ // These values come from draft-ietf-quic-tls Appendix A.4.
+ char retry_packet25[] = {
+ 0xff, 0xff, 0x00, 0x00, 0x19, 0x00, 0x08, 0xf0, 0x67, 0xa5, 0x50, 0x2a,
+ 0x42, 0x62, 0xb5, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x1e, 0x5e, 0xc5, 0xb0,
+ 0x14, 0xcb, 0xb1, 0xf0, 0xfd, 0x93, 0xdf, 0x40, 0x48, 0xc4, 0x46, 0xa6};
+ char retry_packet27[] = {
+ 0xff, 0xff, 0x00, 0x00, 0x1b, 0x00, 0x08, 0xf0, 0x67, 0xa5, 0x50, 0x2a,
+ 0x42, 0x62, 0xb5, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0xa5, 0x23, 0xcb, 0x5b,
+ 0xa5, 0x24, 0x69, 0x5f, 0x65, 0x69, 0xf2, 0x93, 0xa1, 0x35, 0x9d, 0x8e};
+
+ char* retry_packet;
+ size_t retry_packet_length;
+ if (version() ==
+ ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27)) {
+ retry_packet = retry_packet27;
+ retry_packet_length = QUICHE_ARRAYSIZE(retry_packet27);
+ } else if (version() ==
+ ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_25)) {
+ retry_packet = retry_packet25;
+ retry_packet_length = QUICHE_ARRAYSIZE(retry_packet25);
+ } else {
// TODO(dschinazi) generate retry packets for all versions once we have
// server-side support for generating these programmatically.
return;
}
- // These values come from draft-ietf-quic-tls Appendix A.4.
- char retry_packet[] = {0xff, 0xff, 0x00, 0x00, 0x19, 0x00, 0x08, 0xf0, 0x67,
- 0xa5, 0x50, 0x2a, 0x42, 0x62, 0xb5, 0x74, 0x6f, 0x6b,
- 0x65, 0x6e, 0x1e, 0x5e, 0xc5, 0xb0, 0x14, 0xcb, 0xb1,
- 0xf0, 0xfd, 0x93, 0xdf, 0x40, 0x48, 0xc4, 0x46, 0xa6};
char original_connection_id_bytes[] = {0x83, 0x94, 0xc8, 0xf0,
0x3e, 0x51, 0x57, 0x08};
char new_connection_id_bytes[] = {0xf0, 0x67, 0xa5, 0x50,
@@ -10360,43 +10353,110 @@ TEST_P(QuicConnectionTest, ClientParsesRetry) {
std::string retry_token(retry_token_bytes,
QUICHE_ARRAYSIZE(retry_token_bytes));
- {
- TestConnection connection1(
- original_connection_id, kPeerAddress, helper_.get(),
- alarm_factory_.get(), writer_.get(), Perspective::IS_CLIENT, version());
- connection1.set_visitor(&visitor_);
+ if (invalid_retry_tag) {
+ // Flip the last bit of the retry packet to prevent the integrity tag
+ // from validating correctly.
+ retry_packet[retry_packet_length - 1] ^= 1;
+ }
- connection1.ProcessUdpPacket(
- kSelfAddress, kPeerAddress,
- QuicReceivedPacket(retry_packet, QUICHE_ARRAYSIZE(retry_packet),
- clock_.Now()));
- EXPECT_TRUE(connection1.GetStats().retry_packet_processed);
- EXPECT_EQ(connection1.connection_id(), new_connection_id);
- EXPECT_EQ(QuicPacketCreatorPeer::GetRetryToken(
- QuicConnectionPeer::GetPacketCreator(&connection1)),
- retry_token);
+ QuicConnectionId config_original_connection_id = original_connection_id;
+ if (wrong_id_in_config) {
+ // Flip the first bit of the connection ID.
+ ASSERT_FALSE(config_original_connection_id.IsEmpty());
+ config_original_connection_id.mutable_data()[0] ^= 0x80;
}
- // Now flip the last bit of the retry packet to prevent the integrity tag
- // from validating correctly.
- retry_packet[QUICHE_ARRAYSIZE(retry_packet) - 1] ^= 1;
+ // Make sure the connection uses the connection ID from the test vectors,
+ QuicConnectionPeer::SetServerConnectionId(&connection_,
+ original_connection_id);
- {
- TestConnection connection2(
- original_connection_id, kPeerAddress, helper_.get(),
- alarm_factory_.get(), writer_.get(), Perspective::IS_CLIENT, version());
- connection2.set_visitor(&visitor_);
+ // Process the RETRY packet.
+ connection_.ProcessUdpPacket(
+ kSelfAddress, kPeerAddress,
+ QuicReceivedPacket(retry_packet, retry_packet_length, clock_.Now()));
- connection2.ProcessUdpPacket(
- kSelfAddress, kPeerAddress,
- QuicReceivedPacket(retry_packet, QUICHE_ARRAYSIZE(retry_packet),
- clock_.Now()));
- EXPECT_FALSE(connection2.GetStats().retry_packet_processed);
- EXPECT_EQ(connection2.connection_id(), original_connection_id);
+ if (invalid_retry_tag) {
+ // Make sure we refuse to process a RETRY with invalid tag.
+ EXPECT_FALSE(connection_.GetStats().retry_packet_processed);
+ EXPECT_EQ(connection_.connection_id(), original_connection_id);
EXPECT_TRUE(QuicPacketCreatorPeer::GetRetryToken(
- QuicConnectionPeer::GetPacketCreator(&connection2))
+ QuicConnectionPeer::GetPacketCreator(&connection_))
.empty());
+ return;
}
+
+ // Make sure we correctly parsed the RETRY.
+ EXPECT_TRUE(connection_.GetStats().retry_packet_processed);
+ EXPECT_EQ(connection_.connection_id(), new_connection_id);
+ EXPECT_EQ(QuicPacketCreatorPeer::GetRetryToken(
+ QuicConnectionPeer::GetPacketCreator(&connection_)),
+ retry_token);
+ // Make sure our fake framer has the new post-retry INITIAL keys.
+ writer_->framer()->framer()->SetInitialObfuscators(new_connection_id);
+
+ // Test validating the original_connection_id from the config.
+ QuicConfig received_config;
+ QuicConfigPeer::SetNegotiated(&received_config, true);
+ if (!missing_id_in_config) {
+ QuicConfigPeer::SetReceivedOriginalConnectionId(
+ &received_config, config_original_connection_id);
+ }
+ if (missing_id_in_config || wrong_id_in_config) {
+ EXPECT_CALL(visitor_,
+ OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF))
+ .Times(1);
+ } else {
+ EXPECT_CALL(visitor_,
+ OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF))
+ .Times(0);
+ }
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)).Times(AnyNumber());
+ connection_.SetFromConfig(received_config);
+ if (missing_id_in_config || wrong_id_in_config) {
+ EXPECT_FALSE(connection_.connected());
+ TestConnectionCloseQuicErrorCode(IETF_QUIC_PROTOCOL_VIOLATION);
+ } else {
+ EXPECT_TRUE(connection_.connected());
+ }
+}
+
+TEST_P(QuicConnectionTest, ClientParsesRetry) {
+ TestClientRetryHandling(/*invalid_retry_tag=*/false,
+ /*missing_id_in_config=*/false,
+ /*wrong_id_in_config=*/false);
+}
+
+TEST_P(QuicConnectionTest, ClientParsesInvalidRetry) {
+ TestClientRetryHandling(/*invalid_retry_tag=*/true,
+ /*missing_id_in_config=*/false,
+ /*wrong_id_in_config=*/false);
+}
+
+TEST_P(QuicConnectionTest, ClientParsesRetryMissingId) {
+ TestClientRetryHandling(/*invalid_retry_tag=*/false,
+ /*missing_id_in_config=*/true,
+ /*wrong_id_in_config=*/false);
+}
+
+TEST_P(QuicConnectionTest, ClientParsesRetryWrongId) {
+ TestClientRetryHandling(/*invalid_retry_tag=*/false,
+ /*missing_id_in_config=*/false,
+ /*wrong_id_in_config=*/true);
+}
+
+TEST_P(QuicConnectionTest, ClientReceivesOriginalConnectionIdWithoutRetry) {
+ // Make sure that receiving the original_connection_id transport parameter
+ // fails the handshake when no RETRY packet was received before it.
+ QuicConfig received_config;
+ QuicConfigPeer::SetNegotiated(&received_config, true);
+ QuicConfigPeer::SetReceivedOriginalConnectionId(&received_config,
+ TestConnectionId(0x12345));
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)).Times(AnyNumber());
+ EXPECT_CALL(visitor_, OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF))
+ .Times(1);
+ connection_.SetFromConfig(received_config);
+ EXPECT_FALSE(connection_.connected());
+ TestConnectionCloseQuicErrorCode(IETF_QUIC_PROTOCOL_VIOLATION);
}
// Regression test for http://crbug/1047977
@@ -10501,6 +10561,10 @@ TEST_P(QuicConnectionTest, SendPingWhenSkipPacketNumberForPto) {
connection_options.push_back(kPTOS);
connection_options.push_back(k1PTO);
config.SetConnectionOptionsToSend(connection_options);
+ if (connection_.version().UsesTls()) {
+ QuicConfigPeer::SetReceivedMaxDatagramFrameSize(
+ &config, kMaxAcceptedDatagramFrameSize);
+ }
EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
connection_.SetFromConfig(config);
EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
@@ -10508,24 +10572,116 @@ TEST_P(QuicConnectionTest, SendPingWhenSkipPacketNumberForPto) {
EXPECT_EQ(MESSAGE_STATUS_SUCCESS, SendMessage("message"));
EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
- // Although there are bytes in flight, no packet gets sent on PTO firing.
- if (GetQuicReloadableFlag(quic_send_ping_when_pto_skips_packet_number)) {
- // PTO fires, verify a PING packet gets sent because there is no data to
- // send.
- EXPECT_CALL(*send_algorithm_,
- OnPacketSent(_, _, QuicPacketNumber(3), _, _));
- EXPECT_CALL(visitor_, SendPing()).WillOnce(Invoke([this]() {
- SendPing();
- }));
+ // PTO fires, verify a PING packet gets sent because there is no data to
+ // send.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(3), _, _));
+ EXPECT_CALL(visitor_, SendPing()).WillOnce(Invoke([this]() { SendPing(); }));
+ connection_.GetRetransmissionAlarm()->Fire();
+ EXPECT_EQ(1u, connection_.GetStats().pto_count);
+ EXPECT_EQ(0u, connection_.GetStats().crypto_retransmit_count);
+ EXPECT_EQ(1u, writer_->ping_frames().size());
+}
+
+// Regression test for b/155757133
+TEST_P(QuicConnectionTest, DonotChangeQueuedAcks) {
+ if (!connection_.SupportsMultiplePacketNumberSpaces()) {
+ return;
+ }
+ const size_t kMinRttMs = 40;
+ RttStats* rtt_stats = const_cast<RttStats*>(manager_->GetRttStats());
+ rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kMinRttMs),
+ QuicTime::Delta::Zero(), QuicTime::Zero());
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(_, _, _, _, _));
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+
+ ProcessPacket(2);
+ ProcessPacket(3);
+ ProcessPacket(4);
+ // Process a packet containing stream frame followed by ACK of packets 1.
+ QuicFrames frames;
+ frames.push_back(QuicFrame(QuicStreamFrame(
+ QuicUtils::GetFirstBidirectionalStreamId(
+ connection_.version().transport_version, Perspective::IS_CLIENT),
+ false, 0u, quiche::QuicheStringPiece())));
+ QuicAckFrame ack_frame = InitAckFrame(1);
+ frames.push_back(QuicFrame(&ack_frame));
+ // Receiving stream frame causes something to send.
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).WillOnce(Invoke([this]() {
+ connection_.SendControlFrame(QuicFrame(new QuicWindowUpdateFrame(1, 0, 0)));
+ // Verify now the queued ACK contains packet number 2.
+ EXPECT_TRUE(QuicPacketCreatorPeer::QueuedFrames(
+ QuicConnectionPeer::GetPacketCreator(&connection_))[0]
+ .ack_frame->packets.Contains(QuicPacketNumber(2)));
+ }));
+ ProcessFramesPacketAtLevel(9, frames, ENCRYPTION_FORWARD_SECURE);
+ if (GetQuicReloadableFlag(quic_donot_change_queued_ack)) {
+ EXPECT_TRUE(writer_->ack_frames()[0].packets.Contains(QuicPacketNumber(2)));
} else {
- // No packet gets sent.
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+ // ACK frame changes mid packet serialiation!
+ EXPECT_FALSE(
+ writer_->ack_frames()[0].packets.Contains(QuicPacketNumber(2)));
}
- connection_.GetRetransmissionAlarm()->Fire();
- if (GetQuicReloadableFlag(quic_send_ping_when_pto_skips_packet_number)) {
- EXPECT_EQ(1u, connection_.GetStats().pto_count);
- EXPECT_EQ(0u, connection_.GetStats().crypto_retransmit_count);
- EXPECT_EQ(1u, writer_->ping_frames().size());
+}
+
+TEST_P(QuicConnectionTest, DonotExtendIdleTimeOnUndecryptablePackets) {
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ QuicConfig config;
+ connection_.SetFromConfig(config);
+ // Subtract a second from the idle timeout on the client side.
+ QuicTime initial_deadline =
+ clock_.ApproximateNow() +
+ QuicTime::Delta::FromSeconds(kInitialIdleTimeoutSecs - 1);
+ EXPECT_EQ(initial_deadline, connection_.GetTimeoutAlarm()->deadline());
+
+ // Received an undecryptable packet.
+ clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
+ const uint8_t tag = 0x07;
+ peer_framer_.SetEncrypter(ENCRYPTION_FORWARD_SECURE,
+ std::make_unique<TaggingEncrypter>(tag));
+ ProcessDataPacketAtLevel(1, !kHasStopWaiting, ENCRYPTION_FORWARD_SECURE);
+ if (GetQuicReloadableFlag(quic_extend_idle_time_on_decryptable_packets)) {
+ // Verify deadline does not get extended.
+ EXPECT_EQ(initial_deadline, connection_.GetTimeoutAlarm()->deadline());
+ }
+ if (GetQuicReloadableFlag(quic_extend_idle_time_on_decryptable_packets)) {
+ EXPECT_CALL(visitor_, OnConnectionClosed(_, _)).Times(1);
+ } else {
+ EXPECT_CALL(visitor_, OnConnectionClosed(_, _)).Times(0);
+ }
+ QuicTime::Delta delay = initial_deadline - clock_.ApproximateNow();
+ clock_.AdvanceTime(delay);
+ if (GetQuicReloadableFlag(quic_extend_idle_time_on_decryptable_packets)) {
+ connection_.GetTimeoutAlarm()->Fire();
+ }
+ if (GetQuicReloadableFlag(quic_extend_idle_time_on_decryptable_packets)) {
+ // Verify connection gets closed.
+ EXPECT_FALSE(connection_.connected());
+ } else {
+ // Verify the timeout alarm deadline is updated.
+ EXPECT_TRUE(connection_.connected());
+ EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet());
+ }
+}
+
+TEST_P(QuicConnectionTest, BundleAckWithImmediateResponse) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).WillOnce(Invoke([this]() {
+ connection_.SendControlFrame(QuicFrame(new QuicWindowUpdateFrame(1, 0, 0)));
+ }));
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ ProcessDataPacket(1);
+ QuicAlarm* ack_alarm = QuicConnectionPeer::GetAckAlarm(&connection_);
+ if (GetQuicReloadableFlag(quic_advance_ack_timeout_update)) {
+ // Verify ACK is bundled with WINDOW_UPDATE.
+ EXPECT_FALSE(writer_->ack_frames().empty());
+ EXPECT_FALSE(ack_alarm->IsSet());
+ } else {
+ // ACK is pending.
+ EXPECT_TRUE(writer_->ack_frames().empty());
+ EXPECT_TRUE(ack_alarm->IsSet());
}
}
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 15f0abbad5a..51ad0f0c084 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
@@ -72,9 +72,9 @@ const QuicPacketCount kMinInitialCongestionWindow = 10;
// Minimum size of initial flow control window, for both stream and session.
// This is only enforced when version.AllowsLowFlowControlLimits() is false.
-const uint32_t kMinimumFlowControlSendWindow = 16 * 1024; // 16 KB
+const QuicByteCount kMinimumFlowControlSendWindow = 16 * 1024; // 16 KB
// Default size of initial flow control window, for both stream and session.
-const uint32_t kDefaultFlowControlSendWindow = 16 * 1024; // 16 KB
+const QuicByteCount kDefaultFlowControlSendWindow = 16 * 1024; // 16 KB
// Maximum flow control receive window limits for connection and stream.
const QuicByteCount kStreamReceiveWindowLimit = 16 * 1024 * 1024; // 16 MB
@@ -131,8 +131,6 @@ static const int64_t kMinTailLossProbeTimeoutMs = 10;
// The timeout before the handshake succeeds.
const int64_t kInitialIdleTimeoutSecs = 5;
-// The default idle timeout.
-const int64_t kDefaultIdleTimeoutSecs = 30;
// The maximum idle timeout that can be negotiated.
const int64_t kMaximumIdleTimeoutSecs = 60 * 10; // 10 minutes.
// The default timeout for a connection until the crypto handshake succeeds.
@@ -250,6 +248,9 @@ const size_t kMaxNewTokenTokenLength = 0xffff;
// Default initial rtt used before any samples are received.
const int kInitialRttMs = 100;
+// Default threshold of packet reordering before a packet is declared lost.
+static const QuicPacketCount kDefaultPacketReorderingThreshold = 3;
+
// Default fraction (1/4) of an RTT the algorithm waits before determining a
// packet is lost due to early retransmission by time based loss detection.
static const int kDefaultLossDelayShift = 2;
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 f4b01ff3333..ba00b8816b0 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
@@ -292,9 +292,6 @@ void QuicControlFrameManager::WriteBufferedFrames() {
DCHECK(session_->connection()->connected())
<< ENDPOINT << "Try to write control frames when connection is closed.";
while (HasBufferedFrames()) {
- if (!session_->write_with_transmission()) {
- 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_crypto_client_handshaker.h b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.h
index 8c33ee91447..5ba93f24848 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
@@ -12,6 +12,7 @@
#include "net/third_party/quiche/src/quic/core/quic_crypto_client_stream.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"
+#include "net/third_party/quiche/src/common/platform/api/quiche_logging.h"
namespace quic {
@@ -50,7 +51,14 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientHandshaker
HandshakeState GetHandshakeState() const override;
size_t BufferSizeLimitForLevel(EncryptionLevel level) const override;
void OnOneRttPacketAcknowledged() override {}
+ void OnHandshakePacketSent() override {}
+ void OnConnectionClosed(QuicErrorCode /*error*/,
+ ConnectionCloseSource /*source*/) override {}
void OnHandshakeDoneReceived() override;
+ void OnApplicationState(
+ std::unique_ptr<ApplicationState> /*application_state*/) override {
+ QUICHE_NOTREACHED();
+ }
// From QuicCryptoHandshaker
void OnHandshakeMessage(const CryptoHandshakeMessage& message) override;
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker_test.cc
index 92de76f300d..3ea08a51941 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker_test.cc
@@ -47,6 +47,7 @@ class InsecureProofVerifier : public ProofVerifier {
QuicAsyncStatus VerifyCertChain(
const std::string& /*hostname*/,
+ const uint16_t /*port*/,
const std::vector<std::string>& /*certs*/,
const std::string& /*ocsp_response*/,
const std::string& /*cert_sct*/,
@@ -69,13 +70,14 @@ class DummyProofSource : public ProofSource {
// ProofSource override.
void GetProof(const QuicSocketAddress& server_address,
+ const QuicSocketAddress& client_address,
const std::string& hostname,
const std::string& /*server_config*/,
QuicTransportVersion /*transport_version*/,
quiche::QuicheStringPiece /*chlo_hash*/,
std::unique_ptr<Callback> callback) override {
QuicReferenceCountedPointer<ProofSource::Chain> chain =
- GetCertChain(server_address, hostname);
+ GetCertChain(server_address, client_address, hostname);
QuicCryptoProof proof;
proof.signature = "Dummy signature";
proof.leaf_cert_scts = "Dummy timestamp";
@@ -84,6 +86,7 @@ class DummyProofSource : public ProofSource {
QuicReferenceCountedPointer<Chain> GetCertChain(
const QuicSocketAddress& /*server_address*/,
+ const QuicSocketAddress& /*client_address*/,
const std::string& /*hostname*/) override {
std::vector<std::string> certs;
certs.push_back("Dummy cert");
@@ -93,12 +96,15 @@ class DummyProofSource : public ProofSource {
void ComputeTlsSignature(
const QuicSocketAddress& /*server_address*/,
+ const QuicSocketAddress& /*client_address*/,
const std::string& /*hostname*/,
uint16_t /*signature_algorit*/,
quiche::QuicheStringPiece /*in*/,
std::unique_ptr<SignatureCallback> callback) override {
callback->Run(true, "Dummy signature", /*details=*/nullptr);
}
+
+ TicketCrypter* GetTicketCrypter() override { return nullptr; }
};
class Handshaker : public QuicCryptoClientHandshaker {
@@ -136,11 +142,13 @@ class QuicCryptoClientHandshakerTest
{version_})),
session_(connection_, false),
crypto_client_config_(std::make_unique<InsecureProofVerifier>()),
- client_stream_(new QuicCryptoClientStream(server_id_,
- &session_,
- nullptr,
- &crypto_client_config_,
- &proof_handler_)),
+ client_stream_(
+ new QuicCryptoClientStream(server_id_,
+ &session_,
+ nullptr,
+ &crypto_client_config_,
+ &proof_handler_,
+ /*has_application_state = */ false)),
handshaker_(server_id_,
client_stream_,
&session_,
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 62990c1faa5..36dc4cdb4c3 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
@@ -11,6 +11,7 @@
#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h"
#include "net/third_party/quiche/src/quic/core/crypto/crypto_utils.h"
#include "net/third_party/quiche/src/quic/core/crypto/null_encrypter.h"
+#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.h"
#include "net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.h"
#include "net/third_party/quiche/src/quic/core/quic_packets.h"
#include "net/third_party/quiche/src/quic/core/quic_session.h"
@@ -31,7 +32,8 @@ QuicCryptoClientStream::QuicCryptoClientStream(
QuicSession* session,
std::unique_ptr<ProofVerifyContext> verify_context,
QuicCryptoClientConfig* crypto_config,
- ProofHandler* proof_handler)
+ ProofHandler* proof_handler,
+ bool has_application_state)
: QuicCryptoClientStreamBase(session) {
DCHECK_EQ(Perspective::IS_CLIENT, session->connection()->perspective());
switch (session->connection()->version().handshake_protocol) {
@@ -43,7 +45,7 @@ QuicCryptoClientStream::QuicCryptoClientStream(
case PROTOCOL_TLS1_3:
handshaker_ = std::make_unique<TlsClientHandshaker>(
server_id, this, session, std::move(verify_context), crypto_config,
- proof_handler);
+ proof_handler, has_application_state);
break;
case PROTOCOL_UNSUPPORTED:
QUIC_BUG << "Attempting to create QuicCryptoClientStream for unknown "
@@ -111,8 +113,22 @@ void QuicCryptoClientStream::OnOneRttPacketAcknowledged() {
handshaker_->OnOneRttPacketAcknowledged();
}
+void QuicCryptoClientStream::OnHandshakePacketSent() {
+ handshaker_->OnHandshakePacketSent();
+}
+
+void QuicCryptoClientStream::OnConnectionClosed(QuicErrorCode error,
+ ConnectionCloseSource source) {
+ handshaker_->OnConnectionClosed(error, source);
+}
+
void QuicCryptoClientStream::OnHandshakeDoneReceived() {
handshaker_->OnHandshakeDoneReceived();
}
+void QuicCryptoClientStream::OnApplicationState(
+ std::unique_ptr<ApplicationState> application_state) {
+ handshaker_->OnApplicationState(std::move(application_state));
+}
+
} // namespace quic
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 5af0a663fd7..23f83c7e390 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
@@ -16,10 +16,15 @@
#include "net/third_party/quiche/src/quic/core/quic_crypto_stream.h"
#include "net/third_party/quiche/src/quic/core/quic_server_id.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"
namespace quic {
+namespace test {
+class QuicCryptoClientStreamPeer;
+} // namespace test
+
class QUIC_EXPORT_PRIVATE QuicCryptoClientStreamBase : public QuicCryptoStream {
public:
explicit QuicCryptoClientStreamBase(QuicSession* session);
@@ -58,6 +63,9 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientStreamBase : public QuicCryptoStream {
// client. Does not count update messages that were received prior
// to handshake confirmation.
virtual int num_scup_messages_received() const = 0;
+
+ virtual void OnApplicationState(
+ std::unique_ptr<ApplicationState> application_state) = 0;
};
class QUIC_EXPORT_PRIVATE QuicCryptoClientStream
@@ -148,8 +156,19 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientStream
// Called when a 1RTT packet has been acknowledged.
virtual void OnOneRttPacketAcknowledged() = 0;
+ // Called when a packet of ENCRYPTION_HANDSHAKE gets sent.
+ virtual void OnHandshakePacketSent() = 0;
+
+ // Called when connection gets closed.
+ virtual void OnConnectionClosed(QuicErrorCode error,
+ ConnectionCloseSource source) = 0;
+
// Called when handshake done has been received.
virtual void OnHandshakeDoneReceived() = 0;
+
+ // Called when application state is received.
+ virtual void OnApplicationState(
+ std::unique_ptr<ApplicationState> application_state) = 0;
};
// ProofHandler is an interface that handles callbacks from the crypto
@@ -175,7 +194,8 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientStream
QuicSession* session,
std::unique_ptr<ProofVerifyContext> verify_context,
QuicCryptoClientConfig* crypto_config,
- ProofHandler* proof_handler);
+ ProofHandler* proof_handler,
+ bool has_application_state);
QuicCryptoClientStream(const QuicCryptoClientStream&) = delete;
QuicCryptoClientStream& operator=(const QuicCryptoClientStream&) = delete;
@@ -198,10 +218,16 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientStream
CryptoMessageParser* crypto_message_parser() override;
void OnPacketDecrypted(EncryptionLevel /*level*/) override {}
void OnOneRttPacketAcknowledged() override;
+ void OnHandshakePacketSent() override;
+ void OnConnectionClosed(QuicErrorCode error,
+ ConnectionCloseSource source) override;
void OnHandshakeDoneReceived() override;
HandshakeState GetHandshakeState() const override;
size_t BufferSizeLimitForLevel(EncryptionLevel level) const override;
+ void OnApplicationState(
+ std::unique_ptr<ApplicationState> application_state) override;
+
std::string chlo_hash() const;
protected:
@@ -210,6 +236,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientStream
}
private:
+ friend class test::QuicCryptoClientStreamPeer;
std::unique_ptr<HandshakerInterface> handshaker_;
};
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 bcd6a1f536e..6542382d670 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
@@ -34,10 +34,12 @@ namespace {
const char kServerHostname[] = "test.example.com";
const uint16_t kServerPort = 443;
+// This test tests the client-side of the QUIC crypto handshake. It does not
+// test the TLS handshake - that is in tls_client_handshaker_test.cc.
class QuicCryptoClientStreamTest : public QuicTest {
public:
QuicCryptoClientStreamTest()
- : supported_versions_(AllSupportedVersions()),
+ : supported_versions_(AllSupportedVersionsWithQuicCrypto()),
server_id_(kServerHostname, kServerPort, false),
crypto_config_(crypto_test_utils::ProofVerifierForTesting(),
std::make_unique<test::SimpleSessionCache>()),
@@ -64,26 +66,6 @@ class QuicCryptoClientStreamTest : public QuicTest {
CreateSession();
}
- void UseTlsHandshake() {
- supported_versions_.clear();
- for (ParsedQuicVersion version : AllSupportedVersions()) {
- if (version.handshake_protocol != PROTOCOL_TLS1_3) {
- continue;
- }
- supported_versions_.push_back(version);
- }
- }
-
- void UseQuicCryptoHandshake() {
- supported_versions_.clear();
- for (ParsedQuicVersion version : AllSupportedVersions()) {
- if (version.handshake_protocol != PROTOCOL_QUIC_CRYPTO) {
- continue;
- }
- supported_versions_.push_back(version);
- }
- }
-
void CompleteCryptoHandshake() {
int proof_verify_details_calls = 1;
if (stream()->handshake_protocol() != PROTOCOL_TLS1_3) {
@@ -127,59 +109,7 @@ TEST_F(QuicCryptoClientStreamTest, ConnectedAfterSHLO) {
EXPECT_FALSE(stream()->IsResumption());
}
-TEST_F(QuicCryptoClientStreamTest, ConnectedAfterTlsHandshake) {
- UseTlsHandshake();
- CreateConnection();
- CompleteCryptoHandshake();
- EXPECT_EQ(PROTOCOL_TLS1_3, stream()->handshake_protocol());
- EXPECT_TRUE(stream()->encryption_established());
- EXPECT_TRUE(stream()->one_rtt_keys_available());
- EXPECT_FALSE(stream()->IsResumption());
-}
-
-TEST_F(QuicCryptoClientStreamTest,
- ProofVerifyDetailsAvailableAfterTlsHandshake) {
- UseTlsHandshake();
- CreateConnection();
-
- EXPECT_CALL(*session_, OnProofVerifyDetailsAvailable(testing::_));
- stream()->CryptoConnect();
- QuicConfig config;
- crypto_test_utils::HandshakeWithFakeServer(
- &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()->one_rtt_keys_available());
-}
-
-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()->one_rtt_keys_available());
- 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()->one_rtt_keys_available());
- EXPECT_TRUE(stream()->IsResumption());
-}
-
TEST_F(QuicCryptoClientStreamTest, MessageAfterHandshake) {
- UseQuicCryptoHandshake();
- CreateConnection();
CompleteCryptoHandshake();
EXPECT_CALL(
@@ -191,8 +121,6 @@ TEST_F(QuicCryptoClientStreamTest, MessageAfterHandshake) {
}
TEST_F(QuicCryptoClientStreamTest, BadMessageType) {
- UseQuicCryptoHandshake();
- CreateConnection();
stream()->CryptoConnect();
message_.set_tag(kCHLO);
@@ -204,8 +132,6 @@ TEST_F(QuicCryptoClientStreamTest, BadMessageType) {
}
TEST_F(QuicCryptoClientStreamTest, NegotiatedParameters) {
- UseQuicCryptoHandshake();
- CreateConnection();
CompleteCryptoHandshake();
const QuicConfig* config = session_->config();
@@ -218,8 +144,6 @@ TEST_F(QuicCryptoClientStreamTest, NegotiatedParameters) {
}
TEST_F(QuicCryptoClientStreamTest, ExpiredServerConfig) {
- UseQuicCryptoHandshake();
- CreateConnection();
// Seed the config with a cached server config.
CompleteCryptoHandshake();
@@ -278,8 +202,6 @@ TEST_F(QuicCryptoClientStreamTest, InvalidCachedServerConfig) {
TEST_F(QuicCryptoClientStreamTest, ServerConfigUpdate) {
// Test that the crypto client stream can receive server config updates after
// the connection has been established.
- UseQuicCryptoHandshake();
- CreateConnection();
CompleteCryptoHandshake();
QuicCryptoClientConfig::CachedState* state =
@@ -331,8 +253,6 @@ TEST_F(QuicCryptoClientStreamTest, ServerConfigUpdate) {
TEST_F(QuicCryptoClientStreamTest, ServerConfigUpdateWithCert) {
// Test that the crypto client stream can receive and use server config
// updates with certificates after the connection has been established.
- UseQuicCryptoHandshake();
- CreateConnection();
CompleteCryptoHandshake();
// Build a server config update message with certificates
@@ -365,7 +285,7 @@ TEST_F(QuicCryptoClientStreamTest, ServerConfigUpdateWithCert) {
crypto_config.BuildServerConfigUpdateMessage(
session_->transport_version(), stream()->chlo_hash(), tokens,
QuicSocketAddress(QuicIpAddress::Loopback6(), 1234),
- QuicIpAddress::Loopback6(), connection_->clock(),
+ QuicSocketAddress(QuicIpAddress::Loopback6(), 4321), connection_->clock(),
QuicRandom::GetInstance(), &cache, stream()->crypto_negotiated_params(),
&network_params,
std::unique_ptr<BuildServerConfigUpdateMessageResultCallback>(
@@ -388,8 +308,6 @@ TEST_F(QuicCryptoClientStreamTest, ServerConfigUpdateWithCert) {
}
TEST_F(QuicCryptoClientStreamTest, ServerConfigUpdateBeforeHandshake) {
- UseQuicCryptoHandshake();
- CreateConnection();
EXPECT_CALL(
*connection_,
CloseConnection(QUIC_CRYPTO_UPDATE_BEFORE_HANDSHAKE_COMPLETE, _, _));
@@ -402,7 +320,6 @@ TEST_F(QuicCryptoClientStreamTest, ServerConfigUpdateBeforeHandshake) {
TEST_F(QuicCryptoClientStreamTest, PreferredVersion) {
// This mimics the case where client receives version negotiation packet, such
// that, the preferred version is different from the packets' version.
- UseQuicCryptoHandshake();
connection_ = new PacketSavingConnection(
&client_helper_, &alarm_factory_, Perspective::IS_CLIENT,
ParsedVersionOfIndex(supported_versions_, 1));
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 c651351702e..66f82298476 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
@@ -129,9 +129,9 @@ void QuicCryptoServerStream::OnHandshakeMessage(
DCHECK(process_client_hello_cb_ == nullptr);
validate_client_hello_cb_ = cb.get();
crypto_config_->ValidateClientHello(
- message, GetClientAddress().host(),
- session()->connection()->self_address(), transport_version(),
- session()->connection()->clock(), signed_config_, std::move(cb));
+ message, GetClientAddress(), session()->connection()->self_address(),
+ transport_version(), session()->connection()->clock(), signed_config_,
+ std::move(cb));
}
void QuicCryptoServerStream::FinishProcessingHandshakeMessage(
@@ -245,7 +245,7 @@ void QuicCryptoServerStream::SendServerConfigUpdate(
crypto_config_->BuildServerConfigUpdateMessage(
session()->transport_version(), chlo_hash_,
previous_source_address_tokens_, session()->connection()->self_address(),
- GetClientAddress().host(), session()->connection()->clock(),
+ GetClientAddress(), session()->connection()->clock(),
session()->connection()->random_generator(), compressed_certs_cache_,
*crypto_negotiated_params_, cached_network_params, std::move(cb));
}
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 fd14d27a270..52d4874994d 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
@@ -42,6 +42,9 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerStream
CachedNetworkParameters cached_network_params) override;
void OnPacketDecrypted(EncryptionLevel level) override;
void OnOneRttPacketAcknowledged() override {}
+ void OnHandshakePacketSent() override {}
+ void OnConnectionClosed(QuicErrorCode /*error*/,
+ ConnectionCloseSource /*source*/) override {}
void OnHandshakeDoneReceived() override;
bool ShouldSendExpectCTHeader() const override;
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_base.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_base.cc
index 0a77ca7aee9..8ea63ba0876 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_base.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_base.cc
@@ -37,8 +37,8 @@ std::unique_ptr<QuicCryptoServerStreamBase> CreateCryptoServerStream(
return std::unique_ptr<QuicCryptoServerStream>(new QuicCryptoServerStream(
crypto_config, compressed_certs_cache, session, helper));
case PROTOCOL_TLS1_3:
- return std::unique_ptr<TlsServerHandshaker>(new TlsServerHandshaker(
- session, crypto_config->ssl_ctx(), crypto_config->proof_source()));
+ return std::unique_ptr<TlsServerHandshaker>(
+ new TlsServerHandshaker(session, *crypto_config));
case PROTOCOL_UNSUPPORTED:
break;
}
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 60882b861e2..debfc3b0f52 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
@@ -50,7 +50,9 @@ namespace {
const char kServerHostname[] = "test.example.com";
const uint16_t kServerPort = 443;
-class QuicCryptoServerStreamTest : public QuicTestWithParam<bool> {
+// This test tests the server-side of the QUIC crypto handshake. It does not
+// test the TLS handshake - that is in tls_server_handshaker_test.cc.
+class QuicCryptoServerStreamTest : public QuicTest {
public:
QuicCryptoServerStreamTest()
: QuicCryptoServerStreamTest(crypto_test_utils::ProofSourceForTesting()) {
@@ -152,28 +154,6 @@ class QuicCryptoServerStreamTest : public QuicTestWithParam<bool> {
server_connection_, server_stream(), 0);
}
- void UseTlsHandshake() {
- client_options_.only_tls_versions = true;
- supported_versions_.clear();
- for (ParsedQuicVersion version : AllSupportedVersions()) {
- if (version.handshake_protocol != PROTOCOL_TLS1_3) {
- continue;
- }
- supported_versions_.push_back(version);
- }
- }
-
- void UseQuicCryptoHandshake() {
- client_options_.only_quic_crypto_versions = true;
- supported_versions_.clear();
- for (ParsedQuicVersion version : AllSupportedVersions()) {
- if (version.handshake_protocol != PROTOCOL_QUIC_CRYPTO) {
- continue;
- }
- supported_versions_.push_back(version);
- }
- }
-
protected:
// Every connection gets its own MockQuicConnectionHelper and
// MockAlarmFactory, tracked separately from the server and client state so
@@ -197,43 +177,28 @@ class QuicCryptoServerStreamTest : public QuicTestWithParam<bool> {
crypto_test_utils::FakeClientOptions client_options_;
// Which QUIC versions the client and server support.
- ParsedQuicVersionVector supported_versions_ = AllSupportedVersions();
+ ParsedQuicVersionVector supported_versions_ =
+ AllSupportedVersionsWithQuicCrypto();
};
-INSTANTIATE_TEST_SUITE_P(Tests,
- QuicCryptoServerStreamTest,
- ::testing::Bool(),
- ::testing::PrintToStringParamName());
-
-TEST_P(QuicCryptoServerStreamTest, NotInitiallyConected) {
+TEST_F(QuicCryptoServerStreamTest, NotInitiallyConected) {
Initialize();
EXPECT_FALSE(server_stream()->encryption_established());
EXPECT_FALSE(server_stream()->one_rtt_keys_available());
}
-TEST_P(QuicCryptoServerStreamTest, ConnectedAfterCHLO) {
+TEST_F(QuicCryptoServerStreamTest, ConnectedAfterCHLO) {
// CompleteCryptoHandshake returns the number of client hellos sent. This
// test should send:
// * One to get a source-address token and certificates.
// * One to complete the handshake.
- UseQuicCryptoHandshake();
Initialize();
EXPECT_EQ(2, CompleteCryptoHandshake());
EXPECT_TRUE(server_stream()->encryption_established());
EXPECT_TRUE(server_stream()->one_rtt_keys_available());
}
-TEST_P(QuicCryptoServerStreamTest, ConnectedAfterTlsHandshake) {
- UseTlsHandshake();
- Initialize();
- CompleteCryptoHandshake();
- EXPECT_EQ(PROTOCOL_TLS1_3, server_stream()->handshake_protocol());
- EXPECT_TRUE(server_stream()->encryption_established());
- EXPECT_TRUE(server_stream()->one_rtt_keys_available());
-}
-
-TEST_P(QuicCryptoServerStreamTest, ForwardSecureAfterCHLO) {
- UseQuicCryptoHandshake();
+TEST_F(QuicCryptoServerStreamTest, ForwardSecureAfterCHLO) {
Initialize();
InitializeFakeClient();
@@ -254,8 +219,7 @@ TEST_P(QuicCryptoServerStreamTest, ForwardSecureAfterCHLO) {
server_session_->connection()->encryption_level());
}
-TEST_P(QuicCryptoServerStreamTest, ZeroRTT) {
- UseQuicCryptoHandshake();
+TEST_F(QuicCryptoServerStreamTest, ZeroRTT) {
Initialize();
InitializeFakeClient();
@@ -286,8 +250,7 @@ TEST_P(QuicCryptoServerStreamTest, ZeroRTT) {
EXPECT_TRUE(server_stream()->ZeroRttAttempted());
}
-TEST_P(QuicCryptoServerStreamTest, FailByPolicy) {
- UseQuicCryptoHandshake();
+TEST_F(QuicCryptoServerStreamTest, FailByPolicy) {
Initialize();
InitializeFakeClient();
@@ -299,8 +262,7 @@ TEST_P(QuicCryptoServerStreamTest, FailByPolicy) {
AdvanceHandshakeWithFakeClient();
}
-TEST_P(QuicCryptoServerStreamTest, MessageAfterHandshake) {
- UseQuicCryptoHandshake();
+TEST_F(QuicCryptoServerStreamTest, MessageAfterHandshake) {
Initialize();
CompleteCryptoHandshake();
EXPECT_CALL(
@@ -311,8 +273,7 @@ TEST_P(QuicCryptoServerStreamTest, MessageAfterHandshake) {
Perspective::IS_CLIENT);
}
-TEST_P(QuicCryptoServerStreamTest, BadMessageType) {
- UseQuicCryptoHandshake();
+TEST_F(QuicCryptoServerStreamTest, BadMessageType) {
Initialize();
message_.set_tag(kSHLO);
@@ -322,7 +283,7 @@ TEST_P(QuicCryptoServerStreamTest, BadMessageType) {
Perspective::IS_SERVER);
}
-TEST_P(QuicCryptoServerStreamTest, OnlySendSCUPAfterHandshakeComplete) {
+TEST_F(QuicCryptoServerStreamTest, OnlySendSCUPAfterHandshakeComplete) {
// An attempt to send a SCUP before completing handshake should fail.
Initialize();
@@ -330,8 +291,7 @@ TEST_P(QuicCryptoServerStreamTest, OnlySendSCUPAfterHandshakeComplete) {
EXPECT_EQ(0, server_stream()->NumServerConfigUpdateMessagesSent());
}
-TEST_P(QuicCryptoServerStreamTest, SendSCUPAfterHandshakeComplete) {
- UseQuicCryptoHandshake();
+TEST_F(QuicCryptoServerStreamTest, SendSCUPAfterHandshakeComplete) {
Initialize();
InitializeFakeClient();
@@ -363,13 +323,7 @@ class QuicCryptoServerStreamTestWithFailingProofSource
std::unique_ptr<FailingProofSource>(new FailingProofSource)) {}
};
-INSTANTIATE_TEST_SUITE_P(MoreTests,
- QuicCryptoServerStreamTestWithFailingProofSource,
- ::testing::Bool(),
- ::testing::PrintToStringParamName());
-
-TEST_P(QuicCryptoServerStreamTestWithFailingProofSource, Test) {
- UseQuicCryptoHandshake();
+TEST_F(QuicCryptoServerStreamTestWithFailingProofSource, Test) {
Initialize();
InitializeFakeClient();
@@ -399,16 +353,10 @@ class QuicCryptoServerStreamTestWithFakeProofSource
QuicCryptoServerConfigPeer crypto_config_peer_;
};
-INSTANTIATE_TEST_SUITE_P(YetMoreTests,
- QuicCryptoServerStreamTestWithFakeProofSource,
- ::testing::Bool(),
- ::testing::PrintToStringParamName());
-
// Regression test for b/35422225, in which multiple CHLOs arriving on the same
// connection in close succession could cause a crash, especially when the use
// of Mentat signing meant that it took a while for each CHLO to be processed.
-TEST_P(QuicCryptoServerStreamTestWithFakeProofSource, MultipleChlo) {
- UseQuicCryptoHandshake();
+TEST_F(QuicCryptoServerStreamTestWithFakeProofSource, MultipleChlo) {
Initialize();
GetFakeProofSource()->Activate();
EXPECT_CALL(*server_session_->helper(), CanAcceptClientHello(_, _, _, _, _))
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 094613c7395..20704fb627a 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
@@ -38,8 +38,7 @@ QuicCryptoStream::QuicCryptoStream(QuicSession* session)
substreams_{{{this, ENCRYPTION_INITIAL},
{this, ENCRYPTION_HANDSHAKE},
{this, ENCRYPTION_ZERO_RTT},
- {this, ENCRYPTION_FORWARD_SECURE}}},
- writevdata_at_level_(GetQuicReloadableFlag(quic_writevdata_at_level)) {
+ {this, ENCRYPTION_FORWARD_SECURE}}} {
// The crypto stream is exempt from connection level flow control.
DisableConnectionFlowControlForThisStream();
}
@@ -200,16 +199,20 @@ void QuicCryptoStream::OnStreamReset(const QuicRstStreamFrame& /*frame*/) {
}
void QuicCryptoStream::NeuterUnencryptedStreamData() {
+ NeuterStreamDataOfEncryptionLevel(ENCRYPTION_INITIAL);
+}
+
+void QuicCryptoStream::NeuterStreamDataOfEncryptionLevel(
+ EncryptionLevel level) {
if (!QuicVersionUsesCryptoFrames(session()->transport_version())) {
- for (const auto& interval : bytes_consumed_[ENCRYPTION_INITIAL]) {
+ for (const auto& interval : bytes_consumed_[level]) {
QuicByteCount newly_acked_length = 0;
send_buffer().OnStreamDataAcked(
interval.min(), interval.max() - interval.min(), &newly_acked_length);
}
return;
}
- QuicStreamSendBuffer* send_buffer =
- &substreams_[ENCRYPTION_INITIAL].send_buffer;
+ QuicStreamSendBuffer* send_buffer = &substreams_[level].send_buffer;
// TODO(nharper): Consider adding a Clear() method to QuicStreamSendBuffer to
// replace the following code.
QuicIntervalSet<QuicStreamOffset> to_ack = send_buffer->bytes_acked();
@@ -221,7 +224,7 @@ void QuicCryptoStream::NeuterUnencryptedStreamData() {
}
}
-void QuicCryptoStream::OnStreamDataConsumed(size_t bytes_consumed) {
+void QuicCryptoStream::OnStreamDataConsumed(QuicByteCount bytes_consumed) {
if (QuicVersionUsesCryptoFrames(session()->transport_version())) {
QUIC_BUG << "Stream data consumed when CRYPTO frames should be in use";
}
@@ -232,12 +235,21 @@ void QuicCryptoStream::OnStreamDataConsumed(size_t bytes_consumed) {
QuicStream::OnStreamDataConsumed(bytes_consumed);
}
+namespace {
+
+constexpr std::array<EncryptionLevel, NUM_ENCRYPTION_LEVELS>
+AllEncryptionLevels() {
+ return {ENCRYPTION_INITIAL, ENCRYPTION_HANDSHAKE, ENCRYPTION_ZERO_RTT,
+ ENCRYPTION_FORWARD_SECURE};
+}
+
+} // namespace
+
bool QuicCryptoStream::HasPendingCryptoRetransmission() const {
if (!QuicVersionUsesCryptoFrames(session()->transport_version())) {
return false;
}
- for (EncryptionLevel level :
- {ENCRYPTION_INITIAL, ENCRYPTION_ZERO_RTT, ENCRYPTION_FORWARD_SECURE}) {
+ for (EncryptionLevel level : AllEncryptionLevels()) {
if (substreams_[level].send_buffer.HasPendingRetransmission()) {
return true;
}
@@ -248,8 +260,7 @@ bool QuicCryptoStream::HasPendingCryptoRetransmission() const {
void QuicCryptoStream::WritePendingCryptoRetransmission() {
QUIC_BUG_IF(!QuicVersionUsesCryptoFrames(session()->transport_version()))
<< "Versions less than 47 don't write CRYPTO frames";
- for (EncryptionLevel level :
- {ENCRYPTION_INITIAL, ENCRYPTION_ZERO_RTT, ENCRYPTION_FORWARD_SECURE}) {
+ for (EncryptionLevel level : AllEncryptionLevels()) {
QuicStreamSendBuffer* send_buffer = &substreams_[level].send_buffer;
while (send_buffer->HasPendingRetransmission()) {
auto pending = send_buffer->NextPendingRetransmission();
@@ -283,33 +294,9 @@ void QuicCryptoStream::WritePendingRetransmission() {
pending.offset = retransmission.begin()->min();
pending.length =
retransmission.begin()->max() - retransmission.begin()->min();
- QuicConsumedData consumed(0, false);
- if (!writevdata_at_level_) {
- EncryptionLevel current_encryption_level =
- session()->connection()->encryption_level();
- // Set appropriate encryption level.
- session()->connection()->SetDefaultEncryptionLevel(
- retransmission_encryption_level);
- consumed = stream_delegate()->WritevData(
- id(), pending.length, pending.offset, NO_FIN,
- HANDSHAKE_RETRANSMISSION, QuicheNullOpt);
- QUIC_DVLOG(1) << ENDPOINT << "stream " << id()
- << " tries to retransmit stream data [" << pending.offset
- << ", " << pending.offset + pending.length
- << ") with encryption level: "
- << retransmission_encryption_level
- << ", consumed: " << consumed;
- OnStreamFrameRetransmitted(pending.offset, consumed.bytes_consumed,
- consumed.fin_consumed);
- // Restore encryption level.
- session()->connection()->SetDefaultEncryptionLevel(
- current_encryption_level);
- } else {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_writevdata_at_level, 1, 2);
- consumed = RetransmitStreamDataAtLevel(pending.offset, pending.length,
- retransmission_encryption_level,
- HANDSHAKE_RETRANSMISSION);
- }
+ QuicConsumedData consumed = RetransmitStreamDataAtLevel(
+ pending.offset, pending.length, retransmission_encryption_level,
+ HANDSHAKE_RETRANSMISSION);
if (consumed.bytes_consumed < pending.length) {
// The connection is write blocked.
break;
@@ -334,35 +321,12 @@ bool QuicCryptoStream::RetransmitStreamData(QuicStreamOffset offset,
}
}
retransmission.Difference(bytes_acked());
- EncryptionLevel current_encryption_level =
- session()->connection()->encryption_level();
for (const auto& interval : retransmission) {
QuicStreamOffset retransmission_offset = interval.min();
QuicByteCount retransmission_length = interval.max() - interval.min();
- QuicConsumedData consumed(0, false);
- if (!writevdata_at_level_) {
- // Set appropriate encryption level.
- session()->connection()->SetDefaultEncryptionLevel(send_encryption_level);
- consumed = stream_delegate()->WritevData(id(), retransmission_length,
- retransmission_offset, NO_FIN,
- type, QuicheNullOpt);
- QUIC_DVLOG(1) << ENDPOINT << "stream " << id()
- << " is forced to retransmit stream data ["
- << retransmission_offset << ", "
- << retransmission_offset + retransmission_length
- << "), with encryption level: " << send_encryption_level
- << ", consumed: " << consumed;
- OnStreamFrameRetransmitted(retransmission_offset, consumed.bytes_consumed,
- consumed.fin_consumed);
- // Restore encryption level.
- session()->connection()->SetDefaultEncryptionLevel(
- current_encryption_level);
- } else {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_writevdata_at_level, 2, 2);
- consumed = RetransmitStreamDataAtLevel(retransmission_offset,
- retransmission_length,
- send_encryption_level, type);
- }
+ QuicConsumedData consumed = RetransmitStreamDataAtLevel(
+ retransmission_offset, retransmission_length, send_encryption_level,
+ type);
if (consumed.bytes_consumed < retransmission_length) {
// The connection is write blocked.
return false;
@@ -378,7 +342,6 @@ QuicConsumedData QuicCryptoStream::RetransmitStreamDataAtLevel(
EncryptionLevel encryption_level,
TransmissionType type) {
DCHECK_EQ(HANDSHAKE_RETRANSMISSION, type);
- DCHECK(writevdata_at_level_);
const auto consumed = stream_delegate()->WritevData(
id(), retransmission_length, retransmission_offset, NO_FIN, type,
encryption_level);
@@ -398,9 +361,11 @@ uint64_t QuicCryptoStream::crypto_bytes_read() const {
if (!QuicVersionUsesCryptoFrames(session()->transport_version())) {
return stream_bytes_read();
}
- return substreams_[ENCRYPTION_INITIAL].sequencer.NumBytesConsumed() +
- substreams_[ENCRYPTION_ZERO_RTT].sequencer.NumBytesConsumed() +
- substreams_[ENCRYPTION_FORWARD_SECURE].sequencer.NumBytesConsumed();
+ uint64_t bytes_read = 0;
+ for (EncryptionLevel level : AllEncryptionLevels()) {
+ bytes_read += substreams_[level].sequencer.NumBytesConsumed();
+ }
+ return bytes_read;
}
uint64_t QuicCryptoStream::BytesReadOnLevel(EncryptionLevel level) const {
@@ -453,8 +418,7 @@ void QuicCryptoStream::RetransmitData(QuicCryptoFrame* crypto_frame,
void QuicCryptoStream::WriteBufferedCryptoFrames() {
QUIC_BUG_IF(!QuicVersionUsesCryptoFrames(session()->transport_version()))
<< "Versions less than 47 don't use CRYPTO frames";
- for (EncryptionLevel level :
- {ENCRYPTION_INITIAL, ENCRYPTION_ZERO_RTT, ENCRYPTION_FORWARD_SECURE}) {
+ for (EncryptionLevel level : AllEncryptionLevels()) {
QuicStreamSendBuffer* send_buffer = &substreams_[level].send_buffer;
const size_t data_length =
send_buffer->stream_offset() - send_buffer->stream_bytes_written();
@@ -476,8 +440,7 @@ void QuicCryptoStream::WriteBufferedCryptoFrames() {
bool QuicCryptoStream::HasBufferedCryptoFrames() const {
QUIC_BUG_IF(!QuicVersionUsesCryptoFrames(session()->transport_version()))
<< "Versions less than 47 don't use CRYPTO frames";
- for (EncryptionLevel level :
- {ENCRYPTION_INITIAL, ENCRYPTION_ZERO_RTT, ENCRYPTION_FORWARD_SECURE}) {
+ for (EncryptionLevel level : AllEncryptionLevels()) {
const QuicStreamSendBuffer& send_buffer = substreams_[level].send_buffer;
DCHECK_GE(send_buffer.stream_offset(), send_buffer.stream_bytes_written());
if (send_buffer.stream_offset() > send_buffer.stream_bytes_written()) {
@@ -506,8 +469,7 @@ bool QuicCryptoStream::IsWaitingForAcks() const {
if (!QuicVersionUsesCryptoFrames(session()->transport_version())) {
return QuicStream::IsWaitingForAcks();
}
- for (EncryptionLevel level :
- {ENCRYPTION_INITIAL, ENCRYPTION_ZERO_RTT, ENCRYPTION_FORWARD_SECURE}) {
+ for (EncryptionLevel level : AllEncryptionLevels()) {
if (substreams_[level].send_buffer.stream_bytes_outstanding()) {
return true;
}
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 82f81fe9832..49d37042390 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
@@ -91,6 +91,9 @@ class QUIC_EXPORT_PRIVATE QuicCryptoStream : public QuicStream {
// Called when a 1RTT packet has been acknowledged.
virtual void OnOneRttPacketAcknowledged() = 0;
+ // Called when a packet of ENCRYPTION_HANDSHAKE gets sent.
+ virtual void OnHandshakePacketSent() = 0;
+
// Called when a handshake done frame has been received.
virtual void OnHandshakeDoneReceived() = 0;
@@ -104,8 +107,11 @@ class QUIC_EXPORT_PRIVATE QuicCryptoStream : public QuicStream {
// Called to cancel retransmission of unencrypted crypto stream data.
void NeuterUnencryptedStreamData();
+ // Called to cancel retransmission of data of encryption |level|.
+ void NeuterStreamDataOfEncryptionLevel(EncryptionLevel level);
+
// Override to record the encryption level of consumed data.
- void OnStreamDataConsumed(size_t bytes_consumed) override;
+ void OnStreamDataConsumed(QuicByteCount bytes_consumed) override;
// Returns whether there are any bytes pending retransmission in CRYPTO
// frames.
@@ -197,9 +203,6 @@ class QUIC_EXPORT_PRIVATE QuicCryptoStream : public QuicStream {
// Keeps state for data sent/received in CRYPTO frames at each encryption
// level.
std::array<CryptoSubstream, NUM_ENCRYPTION_LEVELS> substreams_;
-
- // Latched value of gfe2_reloadable_flag_quic_writevdata_at_level.
- const bool writevdata_at_level_;
};
} // namespace quic
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 436e572308b..5f414e6a98a 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
@@ -58,6 +58,7 @@ class MockQuicCryptoStream : public QuicCryptoStream,
}
void OnPacketDecrypted(EncryptionLevel /*level*/) override {}
void OnOneRttPacketAcknowledged() override {}
+ void OnHandshakePacketSent() override {}
void OnHandshakeDoneReceived() override {}
HandshakeState GetHandshakeState() const override { return HANDSHAKE_START; }
@@ -253,6 +254,48 @@ TEST_F(QuicCryptoStreamTest, RetransmitCryptoDataInCryptoFrames) {
EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, connection_->encryption_level());
}
+// Regression test for handling the missing ENCRYPTION_HANDSHAKE in
+// quic_crypto_stream.cc. This test is essentially the same as
+// RetransmitCryptoDataInCryptoFrames, except it uses ENCRYPTION_HANDSHAKE in
+// place of ENCRYPTION_ZERO_RTT.
+TEST_F(QuicCryptoStreamTest, RetransmitEncryptionHandshakeLevelCryptoFrames) {
+ if (!QuicVersionUsesCryptoFrames(connection_->transport_version())) {
+ return;
+ }
+ EXPECT_CALL(*connection_, SendCryptoData(_, _, _)).Times(0);
+ InSequence s;
+ // Send [0, 1000) in ENCRYPTION_INITIAL.
+ EXPECT_EQ(ENCRYPTION_INITIAL, connection_->encryption_level());
+ std::string data(1000, 'a');
+ EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_INITIAL, 1000, 0))
+ .WillOnce(Invoke(connection_,
+ &MockQuicConnection::QuicConnection_SendCryptoData));
+ stream_->WriteCryptoData(ENCRYPTION_INITIAL, data);
+ // Send [1000, 2000) in ENCRYPTION_HANDSHAKE.
+ connection_->SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE);
+ std::unique_ptr<NullEncrypter> encrypter =
+ std::make_unique<NullEncrypter>(Perspective::IS_CLIENT);
+ connection_->SetEncrypter(ENCRYPTION_HANDSHAKE, std::move(encrypter));
+ EXPECT_EQ(ENCRYPTION_HANDSHAKE, connection_->encryption_level());
+ EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_HANDSHAKE, 1000, 0))
+ .WillOnce(Invoke(connection_,
+ &MockQuicConnection::QuicConnection_SendCryptoData));
+ stream_->WriteCryptoData(ENCRYPTION_HANDSHAKE, data);
+ connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+ EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, connection_->encryption_level());
+
+ // Lost [1000, 1200).
+ QuicCryptoFrame lost_frame(ENCRYPTION_HANDSHAKE, 0, 200);
+ stream_->OnCryptoFrameLost(&lost_frame);
+ EXPECT_TRUE(stream_->HasPendingCryptoRetransmission());
+ // Verify [1000, 1200) is sent.
+ EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_HANDSHAKE, 200, 0))
+ .WillOnce(Invoke(connection_,
+ &MockQuicConnection::QuicConnection_SendCryptoData));
+ stream_->WritePendingCryptoRetransmission();
+ EXPECT_FALSE(stream_->HasPendingCryptoRetransmission());
+}
+
TEST_F(QuicCryptoStreamTest, NeuterUnencryptedStreamData) {
if (QuicVersionUsesCryptoFrames(connection_->transport_version())) {
return;
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 c160ced24b6..c0d39700f41 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
@@ -15,6 +15,7 @@
#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/core/quic_utils.h"
#include "net/third_party/quiche/src/quic/core/quic_versions.h"
+#include "net/third_party/quiche/src/quic/core/tls_chlo_extractor.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"
@@ -60,14 +61,11 @@ class PacketCollector : public QuicPacketCreator::DelegateInterface,
~PacketCollector() override = default;
// QuicPacketCreator::DelegateInterface methods:
- void OnSerializedPacket(SerializedPacket* serialized_packet) override {
+ void OnSerializedPacket(SerializedPacket serialized_packet) override {
// Make a copy of the serialized packet to send later.
packets_.emplace_back(
- new QuicEncryptedPacket(CopyBuffer(*serialized_packet),
- serialized_packet->encrypted_length, true));
- serialized_packet->encrypted_buffer = nullptr;
- DeleteFrames(&(serialized_packet->retransmittable_frames));
- serialized_packet->retransmittable_frames.clear();
+ new QuicEncryptedPacket(CopyBuffer(serialized_packet),
+ serialized_packet.encrypted_length, true));
}
char* GetPacketBuffer() override {
@@ -180,7 +178,7 @@ class StatelessConnectionTerminator {
QuicTimeWaitListManager* time_wait_list_manager_;
};
-// Class which extracts the ALPN from a CHLO packet.
+// Class which extracts the ALPN from a QUIC_CRYPTO CHLO packet.
class ChloAlpnExtractor : public ChloExtractor::Delegate {
public:
void OnChlo(QuicTransportVersion /*version*/,
@@ -310,7 +308,7 @@ void QuicDispatcher::ProcessPacket(const QuicSocketAddress& self_address,
QuicConnectionId QuicDispatcher::MaybeReplaceServerConnectionId(
QuicConnectionId server_connection_id,
- ParsedQuicVersion version) {
+ ParsedQuicVersion version) const {
if (server_connection_id.length() == expected_server_connection_id_length_) {
return server_connection_id;
}
@@ -476,16 +474,42 @@ void QuicDispatcher::ProcessHeader(ReceivedPacketInfo* packet_info) {
QuicConnectionId server_connection_id =
packet_info->destination_connection_id;
// Packet's connection ID is unknown. Apply the validity checks.
- // TODO(wub): Determine the fate completely in ValidityChecks, then call
- // ProcessUnauthenticatedHeaderFate in one place.
QuicPacketFate fate = ValidityChecks(*packet_info);
ChloAlpnExtractor alpn_extractor;
switch (fate) {
case kFateProcess: {
if (packet_info->version.handshake_protocol == PROTOCOL_TLS1_3) {
- // TODO(nharper): Support buffering non-ClientHello packets when using
- // TLS.
- ProcessChlo(/*alpn=*/"", packet_info);
+ bool has_full_tls_chlo = false;
+ std::vector<std::string> alpns;
+ if (buffered_packets_.HasBufferedPackets(
+ packet_info->destination_connection_id)) {
+ // If we already have buffered packets for this connection ID,
+ // use the associated TlsChloExtractor to parse this packet.
+ has_full_tls_chlo =
+ buffered_packets_.IngestPacketForTlsChloExtraction(
+ packet_info->destination_connection_id, packet_info->version,
+ packet_info->packet, &alpns);
+ } else {
+ // If we do not have a BufferedPacketList for this connection ID,
+ // create a single-use one to check whether this packet contains a
+ // full single-packet CHLO.
+ TlsChloExtractor tls_chlo_extractor;
+ tls_chlo_extractor.IngestPacket(packet_info->version,
+ packet_info->packet);
+ if (tls_chlo_extractor.HasParsedFullChlo()) {
+ // This packet contains a full single-packet CHLO.
+ has_full_tls_chlo = true;
+ alpns = tls_chlo_extractor.alpns();
+ }
+ }
+ if (has_full_tls_chlo) {
+ ProcessChlo(alpns, packet_info);
+ } else {
+ // This packet does not contain a full CHLO. It could be a 0-RTT
+ // packet that arrived before the CHLO (due to loss or reordering),
+ // or it could be a fragment of a multi-packet CHLO.
+ BufferEarlyPacket(*packet_info);
+ }
break;
}
if (GetQuicFlag(FLAGS_quic_allow_chlo_buffering) &&
@@ -497,7 +521,7 @@ void QuicDispatcher::ProcessHeader(ReceivedPacketInfo* packet_info) {
BufferEarlyPacket(*packet_info);
break;
}
- ProcessChlo(alpn_extractor.ConsumeAlpn(), packet_info);
+ ProcessChlo({alpn_extractor.ConsumeAlpn()}, packet_info);
} break;
case kFateTimeWait:
// Add this connection_id to the time-wait state, to safely reject
@@ -524,36 +548,55 @@ void QuicDispatcher::ProcessHeader(ReceivedPacketInfo* packet_info) {
}
}
+std::string QuicDispatcher::SelectAlpn(const std::vector<std::string>& alpns) {
+ if (alpns.empty()) {
+ return "";
+ }
+ if (alpns.size() > 1u) {
+ const std::vector<std::string>& supported_alpns =
+ version_manager_->GetSupportedAlpns();
+ for (const std::string& alpn : alpns) {
+ if (std::find(supported_alpns.begin(), supported_alpns.end(), alpn) !=
+ supported_alpns.end()) {
+ return alpn;
+ }
+ }
+ }
+ return alpns[0];
+}
+
QuicDispatcher::QuicPacketFate QuicDispatcher::ValidityChecks(
const ReceivedPacketInfo& packet_info) {
if (!packet_info.version_flag) {
- // 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)
- // - randomized 8-byte connection ID
- // - 0x01 (1-byte packet number)
- // - 0x00 (private flags)
- // - 0x07 (PING frame).
- // That packet is invalid and we would normally drop it but in order to
- // unblock this conformance testing we have the following workaround that
- // will be removed once the fixed test is deployed.
- // TODO(b/139691956) Remove this workaround once fixed test is deployed.
- if (packet_info.packet.length() == 12 &&
- packet_info.packet.data()[0] == 0x0c &&
- packet_info.packet.data()[9] == 0x01 &&
- packet_info.packet.data()[10] == 0x00 &&
- packet_info.packet.data()[11] == 0x07) {
- QUIC_DLOG(INFO) << "Received Android UDP network conformance test "
- "packet with connection ID "
- << packet_info.destination_connection_id;
- // Respond with a public reset that the test will know how to parse
- // then return kFateDrop to stop processing of this packet.
- time_wait_list_manager()->SendPublicReset(
- packet_info.self_address, packet_info.peer_address,
- packet_info.destination_connection_id,
- /*ietf_quic=*/false, GetPerPacketContext());
- return kFateDrop;
- }
+ // 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)
+ // - randomized 8-byte connection ID
+ // - 0x01 (1-byte packet number)
+ // - 0x00 (private flags)
+ // - 0x07 (PING frame).
+ // That packet is invalid and we would normally drop it but in order to
+ // unblock this conformance testing we have the following workaround that
+ // will be removed once the fixed test is deployed.
+ // TODO(b/139691956) Remove this workaround once fixed test is deployed.
+ if (!GetQuicReloadableFlag(
+ quic_remove_android_conformance_test_workaround) &&
+ packet_info.packet.length() == 12 &&
+ packet_info.packet.data()[0] == 0x0c &&
+ packet_info.packet.data()[9] == 0x01 &&
+ packet_info.packet.data()[10] == 0x00 &&
+ packet_info.packet.data()[11] == 0x07) {
+ QUIC_DLOG(INFO) << "Received Android UDP network conformance test "
+ "packet with connection ID "
+ << packet_info.destination_connection_id;
+ // Respond with a public reset that the test will know how to parse
+ // then return kFateDrop to stop processing of this packet.
+ time_wait_list_manager()->SendPublicReset(
+ packet_info.self_address, packet_info.peer_address,
+ packet_info.destination_connection_id,
+ /*ietf_quic=*/false, GetPerPacketContext());
+ return kFateDrop;
+ }
QUIC_DLOG(INFO)
<< "Packet without version arrived for unknown connection ID "
@@ -574,7 +617,12 @@ void QuicDispatcher::CleanUpSession(SessionMap::iterator it,
QuicTimeWaitListManager::SEND_STATELESS_RESET;
if (connection->termination_packets() != nullptr &&
!connection->termination_packets()->empty()) {
- action = QuicTimeWaitListManager::SEND_TERMINATION_PACKETS;
+ if (GetQuicRestartFlag(quic_replace_time_wait_list_encryption_level)) {
+ QUIC_RESTART_FLAG_COUNT(quic_replace_time_wait_list_encryption_level);
+ action = QuicTimeWaitListManager::SEND_CONNECTION_CLOSE_PACKETS;
+ } else {
+ action = QuicTimeWaitListManager::SEND_TERMINATION_PACKETS;
+ }
} else {
if (!connection->IsHandshakeComplete()) {
if (!VersionHasIetfInvariantHeader(connection->transport_version())) {
@@ -831,9 +879,10 @@ void QuicDispatcher::ProcessBufferedChlos(size_t max_connections_to_create) {
QuicConnectionId original_connection_id = server_connection_id;
server_connection_id = MaybeReplaceServerConnectionId(server_connection_id,
packet_list.version);
+ std::string alpn = SelectAlpn(packet_list.alpns);
std::unique_ptr<QuicSession> session =
CreateQuicSession(server_connection_id, packets.front().peer_address,
- packet_list.alpn, packet_list.version);
+ alpn, packet_list.version);
if (original_connection_id != server_connection_id) {
session->connection()->AddIncomingConnectionId(original_connection_id);
session->connection()->InstallInitialCrypters(original_connection_id);
@@ -889,13 +938,13 @@ void QuicDispatcher::BufferEarlyPacket(const ReceivedPacketInfo& packet_info) {
packet_info.destination_connection_id,
packet_info.form != GOOGLE_QUIC_PACKET, packet_info.packet,
packet_info.self_address, packet_info.peer_address, /*is_chlo=*/false,
- /*alpn=*/"", packet_info.version);
+ /*alpns=*/{}, packet_info.version);
if (rs != EnqueuePacketResult::SUCCESS) {
OnBufferPacketFailure(rs, packet_info.destination_connection_id);
}
}
-void QuicDispatcher::ProcessChlo(const std::string& alpn,
+void QuicDispatcher::ProcessChlo(const std::vector<std::string>& alpns,
ReceivedPacketInfo* packet_info) {
if (!buffered_packets_.HasBufferedPackets(
packet_info->destination_connection_id) &&
@@ -911,7 +960,7 @@ void QuicDispatcher::ProcessChlo(const std::string& alpn,
packet_info->destination_connection_id,
packet_info->form != GOOGLE_QUIC_PACKET, packet_info->packet,
packet_info->self_address, packet_info->peer_address,
- /*is_chlo=*/true, alpn, packet_info->version);
+ /*is_chlo=*/true, alpns, packet_info->version);
if (rs != EnqueuePacketResult::SUCCESS) {
OnBufferPacketFailure(rs, packet_info->destination_connection_id);
}
@@ -923,6 +972,7 @@ void QuicDispatcher::ProcessChlo(const std::string& alpn,
packet_info->destination_connection_id = MaybeReplaceServerConnectionId(
original_connection_id, packet_info->version);
// Creates a new session and process all buffered packets for this connection.
+ std::string alpn = SelectAlpn(alpns);
std::unique_ptr<QuicSession> session =
CreateQuicSession(packet_info->destination_connection_id,
packet_info->peer_address, alpn, packet_info->version);
@@ -975,6 +1025,11 @@ const ParsedQuicVersionVector& QuicDispatcher::GetSupportedVersions() {
return version_manager_->GetSupportedVersions();
}
+const ParsedQuicVersionVector&
+QuicDispatcher::GetSupportedVersionsWithQuicCrypto() {
+ return version_manager_->GetSupportedVersionsWithQuicCrypto();
+}
+
void QuicDispatcher::DeliverPacketsToSession(
const std::list<BufferedPacket>& packets,
QuicSession* session) {
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 71cbb5771be..73ab3ec4fd0 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
@@ -196,7 +196,8 @@ class QUIC_NO_EXPORT QuicDispatcher
// Called when |packet_info| is a CHLO packet. Creates a new connection and
// delivers any buffered packets for that connection id.
- void ProcessChlo(const std::string& alpn, ReceivedPacketInfo* packet_info);
+ void ProcessChlo(const std::vector<std::string>& alpns,
+ ReceivedPacketInfo* packet_info);
// Return true if dispatcher wants to destroy session outside of
// OnConnectionClosed() call stack.
@@ -210,6 +211,8 @@ class QUIC_NO_EXPORT QuicDispatcher
const ParsedQuicVersionVector& GetSupportedVersions();
+ const ParsedQuicVersionVector& GetSupportedVersionsWithQuicCrypto();
+
const QuicConfig& config() const { return *config_; }
const QuicCryptoServerConfig* crypto_config() const { return crypto_config_; }
@@ -298,12 +301,22 @@ class QUIC_NO_EXPORT QuicDispatcher
// Called if a packet from an unseen connection is reset or rejected.
virtual void OnNewConnectionRejected() {}
+ // Selects the preferred ALPN from a vector of ALPNs.
+ // This runs through the list of ALPNs provided by the client and picks the
+ // first one it supports. If no supported versions are found, the first
+ // element of the vector is returned.
+ std::string SelectAlpn(const std::vector<std::string>& alpns);
+
+ // If the connection ID length is different from what the dispatcher expects,
+ // replace the connection ID with a random one of the right length,
+ // and save it to make sure the mapping is persistent.
+ QuicConnectionId MaybeReplaceServerConnectionId(
+ QuicConnectionId server_connection_id,
+ ParsedQuicVersion version) const;
+
private:
friend class test::QuicDispatcherPeer;
- typedef QuicUnorderedSet<QuicConnectionId, QuicConnectionIdHash>
- QuicConnectionIdSet;
-
// TODO(fayang): Consider to rename this function to
// ProcessValidatedPacketWithUnknownConnectionId.
void ProcessHeader(ReceivedPacketInfo* packet_info);
@@ -313,13 +326,6 @@ class QUIC_NO_EXPORT QuicDispatcher
const std::list<QuicBufferedPacketStore::BufferedPacket>& packets,
QuicSession* session);
- // If the connection ID length is different from what the dispatcher expects,
- // replace the connection ID with a random one of the right length,
- // and save it to make sure the mapping is persistent.
- QuicConnectionId MaybeReplaceServerConnectionId(
- QuicConnectionId server_connection_id,
- ParsedQuicVersion version);
-
// Returns true if |version| is a supported protocol version.
bool IsSupportedVersion(const ParsedQuicVersion version);
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 7e54dd24cf0..814462e9d01 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
@@ -14,6 +14,7 @@
#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h"
#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h"
#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h"
+#include "net/third_party/quiche/src/quic/core/quic_config.h"
#include "net/third_party/quiche/src/quic/core/quic_connection_id.h"
#include "net/third_party/quiche/src/quic/core/quic_crypto_stream.h"
#include "net/third_party/quiche/src/quic/core/quic_packet_writer_wrapper.h"
@@ -27,6 +28,7 @@
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h"
#include "net/third_party/quiche/src/quic/test_tools/fake_proof_source.h"
+#include "net/third_party/quiche/src/quic/test_tools/first_flight.h"
#include "net/third_party/quiche/src/quic/test_tools/mock_quic_time_wait_list_manager.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_buffered_packet_store_peer.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_crypto_server_config_peer.h"
@@ -78,13 +80,27 @@ class TestQuicSpdyServerSession : public QuicServerSessionBase {
~TestQuicSpdyServerSession() override { DeleteConnection(); }
- MOCK_METHOD2(OnConnectionClosed,
- void(const QuicConnectionCloseFrame& frame,
- ConnectionCloseSource source));
- MOCK_METHOD1(CreateIncomingStream, QuicSpdyStream*(QuicStreamId id));
- MOCK_METHOD1(CreateIncomingStream, QuicSpdyStream*(PendingStream* pending));
- MOCK_METHOD0(CreateOutgoingBidirectionalStream, QuicSpdyStream*());
- MOCK_METHOD0(CreateOutgoingUnidirectionalStream, QuicSpdyStream*());
+ MOCK_METHOD(void,
+ OnConnectionClosed,
+ (const QuicConnectionCloseFrame& frame,
+ ConnectionCloseSource source),
+ (override));
+ MOCK_METHOD(QuicSpdyStream*,
+ CreateIncomingStream,
+ (QuicStreamId id),
+ (override));
+ MOCK_METHOD(QuicSpdyStream*,
+ CreateIncomingStream,
+ (PendingStream*),
+ (override));
+ MOCK_METHOD(QuicSpdyStream*,
+ CreateOutgoingBidirectionalStream,
+ (),
+ (override));
+ MOCK_METHOD(QuicSpdyStream*,
+ CreateOutgoingUnidirectionalStream,
+ (),
+ (override));
std::unique_ptr<QuicCryptoServerStreamBase> CreateQuicCryptoServerStream(
const QuicCryptoServerConfig* crypto_config,
@@ -114,15 +130,18 @@ class TestDispatcher : public QuicDispatcher {
kQuicDefaultConnectionIdLength),
random_(random) {}
- MOCK_METHOD4(
- CreateQuicSession,
- std::unique_ptr<QuicSession>(QuicConnectionId connection_id,
- const QuicSocketAddress& peer_address,
- quiche::QuicheStringPiece alpn,
- const quic::ParsedQuicVersion& version));
+ MOCK_METHOD(std::unique_ptr<QuicSession>,
+ CreateQuicSession,
+ (QuicConnectionId connection_id,
+ const QuicSocketAddress& peer_address,
+ quiche::QuicheStringPiece alpn,
+ const quic::ParsedQuicVersion& version),
+ (override));
- MOCK_METHOD1(ShouldCreateOrBufferPacketForConnection,
- bool(const ReceivedPacketInfo& packet_info));
+ MOCK_METHOD(bool,
+ ShouldCreateOrBufferPacketForConnection,
+ (const ReceivedPacketInfo& packet_info),
+ (override));
struct TestQuicPerPacketContext : public QuicPerPacketContext {
std::string custom_packet_context;
@@ -201,7 +220,7 @@ class QuicDispatcherTestBase : public QuicTestWithParam<ParsedQuicVersion> {
connection_id_(1) {}
void SetUp() override {
- dispatcher_->InitializeWithWriter(new MockPacketWriter());
+ dispatcher_->InitializeWithWriter(new NiceMock<MockPacketWriter>());
// Set the counter to some value to start with.
QuicDispatcherPeer::set_new_sessions_allowed_per_event_loop(
dispatcher_.get(), kMaxNumSessionsToCreate);
@@ -294,17 +313,26 @@ class QuicDispatcherTestBase : public QuicTestWithParam<ParsedQuicVersion> {
client_connection_id_included, packet_number_length, &versions));
std::unique_ptr<QuicReceivedPacket> received_packet(
ConstructReceivedPacket(*packet, mock_helper_.GetClock()->Now()));
+ ProcessReceivedPacket(std::move(received_packet), peer_address, version,
+ server_connection_id);
+ }
- if (ChloExtractor::Extract(*packet, version, {}, nullptr,
+ void ProcessReceivedPacket(
+ std::unique_ptr<QuicReceivedPacket> received_packet,
+ const QuicSocketAddress& peer_address,
+ const ParsedQuicVersion& version,
+ const QuicConnectionId& server_connection_id) {
+ if (version.UsesQuicCrypto() &&
+ ChloExtractor::Extract(*received_packet, version, {}, nullptr,
server_connection_id.length())) {
// Add CHLO packet to the beginning to be verified first, because it is
// also processed first by new session.
data_connection_map_[server_connection_id].push_front(
- std::string(packet->data(), packet->length()));
+ std::string(received_packet->data(), received_packet->length()));
} else {
// For non-CHLO, always append to last.
data_connection_map_[server_connection_id].push_back(
- std::string(packet->data(), packet->length()));
+ std::string(received_packet->data(), received_packet->length()));
}
dispatcher_->ProcessPacket(server_address_, peer_address, *received_packet);
}
@@ -353,16 +381,56 @@ class QuicDispatcherTestBase : public QuicTestWithParam<ParsedQuicVersion> {
std::string SerializeCHLO() {
CryptoHandshakeMessage client_hello;
client_hello.set_tag(kCHLO);
- client_hello.SetStringPiece(kALPN, "hq");
+ client_hello.SetStringPiece(kALPN, ExpectedAlpn());
return std::string(client_hello.GetSerialized().AsStringPiece());
}
- std::string ExpectedAlpnForVersion(ParsedQuicVersion version) {
- if (version.handshake_protocol == PROTOCOL_TLS1_3) {
- // TODO(b/149597791) Remove this once we can parse ALPN with TLS.
- return "";
+ void ProcessUndecryptableEarlyPacket(
+ const QuicSocketAddress& peer_address,
+ const QuicConnectionId& server_connection_id) {
+ ProcessUndecryptableEarlyPacket(version_, peer_address,
+ server_connection_id);
+ }
+
+ void ProcessUndecryptableEarlyPacket(
+ const ParsedQuicVersion& version,
+ const QuicSocketAddress& peer_address,
+ const QuicConnectionId& server_connection_id) {
+ std::unique_ptr<QuicEncryptedPacket> encrypted_packet =
+ GetUndecryptableEarlyPacket(version, server_connection_id);
+ std::unique_ptr<QuicReceivedPacket> received_packet(ConstructReceivedPacket(
+ *encrypted_packet, mock_helper_.GetClock()->Now()));
+ ProcessReceivedPacket(std::move(received_packet), peer_address, version,
+ server_connection_id);
+ }
+
+ void ProcessFirstFlight(const QuicSocketAddress& peer_address,
+ const QuicConnectionId& server_connection_id) {
+ ProcessFirstFlight(version_, peer_address, server_connection_id);
+ }
+
+ void ProcessFirstFlight(const ParsedQuicVersion& version,
+ const QuicSocketAddress& peer_address,
+ const QuicConnectionId& server_connection_id) {
+ ProcessFirstFlight(version, peer_address, server_connection_id,
+ EmptyQuicConnectionId());
+ }
+
+ void ProcessFirstFlight(const ParsedQuicVersion& version,
+ const QuicSocketAddress& peer_address,
+ const QuicConnectionId& server_connection_id,
+ const QuicConnectionId& client_connection_id) {
+ std::vector<std::unique_ptr<QuicReceivedPacket>> packets =
+ GetFirstFlightOfPackets(version, server_connection_id,
+ client_connection_id);
+ for (auto&& packet : packets) {
+ ProcessReceivedPacket(std::move(packet), peer_address, version,
+ server_connection_id);
}
- return "hq";
+ }
+
+ std::string ExpectedAlpnForVersion(ParsedQuicVersion version) {
+ return AlpnForVersion(version);
}
std::string ExpectedAlpn() { return ExpectedAlpnForVersion(version_); }
@@ -388,8 +456,7 @@ class QuicDispatcherTestBase : public QuicTestWithParam<ParsedQuicVersion> {
EXPECT_CALL(*dispatcher_,
ShouldCreateOrBufferPacketForConnection(
ReceivedPacketInfoConnectionIdEquals(connection_id)));
- ProcessPacket(client_address, connection_id, true, version, SerializeCHLO(),
- true, CONNECTION_ID_PRESENT, PACKET_4BYTE_PACKET_NUMBER, 1);
+ ProcessFirstFlight(version, client_address, connection_id);
}
void VerifyVersionNotSupported(ParsedQuicVersion version) {
@@ -398,10 +465,11 @@ class QuicDispatcherTestBase : public QuicTestWithParam<ParsedQuicVersion> {
EXPECT_CALL(*dispatcher_,
CreateQuicSession(connection_id, client_address, _, _))
.Times(0);
- ProcessPacket(client_address, connection_id, true, version, SerializeCHLO(),
- true, CONNECTION_ID_PRESENT, PACKET_4BYTE_PACKET_NUMBER, 1);
+ ProcessFirstFlight(version, client_address, connection_id);
}
+ void TestTlsMultiPacketClientHello(bool add_reordering);
+
ParsedQuicVersion version_;
MockQuicConnectionHelper mock_helper_;
MockAlarmFactory mock_alarm_factory_;
@@ -432,7 +500,7 @@ INSTANTIATE_TEST_SUITE_P(QuicDispatcherTestsOneVersion,
::testing::PrintToStringParamName());
TEST_P(QuicDispatcherTestAllVersions, TlsClientHelloCreatesSession) {
- if (version_.handshake_protocol != PROTOCOL_TLS1_3) {
+ if (version_.UsesQuicCrypto()) {
return;
}
QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
@@ -452,9 +520,64 @@ TEST_P(QuicDispatcherTestAllVersions, TlsClientHelloCreatesSession) {
EXPECT_CALL(*dispatcher_,
ShouldCreateOrBufferPacketForConnection(
ReceivedPacketInfoConnectionIdEquals(TestConnectionId(1))));
- ProcessPacket(client_address, TestConnectionId(1), true, version_,
- SerializeCHLO(), true, CONNECTION_ID_PRESENT,
- PACKET_4BYTE_PACKET_NUMBER, 1);
+
+ ProcessFirstFlight(client_address, TestConnectionId(1));
+}
+
+void QuicDispatcherTestBase::TestTlsMultiPacketClientHello(
+ bool add_reordering) {
+ if (!version_.UsesTls()) {
+ return;
+ }
+ QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
+ QuicConnectionId server_connection_id = TestConnectionId();
+ QuicConfig client_config = DefaultQuicConfig();
+ // Add a 2000-byte custom parameter to increase the length of the CHLO.
+ constexpr auto kCustomParameterId =
+ static_cast<TransportParameters::TransportParameterId>(0xff33);
+ std::string kCustomParameterValue(2000, '-');
+ client_config.custom_transport_parameters_to_send()[kCustomParameterId] =
+ kCustomParameterValue;
+ std::vector<std::unique_ptr<QuicReceivedPacket>> packets =
+ GetFirstFlightOfPackets(version_, client_config, server_connection_id);
+ ASSERT_EQ(packets.size(), 2u);
+ if (add_reordering) {
+ std::swap(packets[0], packets[1]);
+ }
+
+ // Processing the first packet should not create a new session.
+ EXPECT_CALL(*dispatcher_,
+ ShouldCreateOrBufferPacketForConnection(
+ ReceivedPacketInfoConnectionIdEquals(server_connection_id)));
+ ProcessReceivedPacket(std::move(packets[0]), client_address, version_,
+ server_connection_id);
+
+ EXPECT_EQ(dispatcher_->session_map().size(), 0u)
+ << "No session should be created before the rest of the CHLO arrives.";
+
+ // Processing the second packet should create the new session.
+ EXPECT_CALL(*dispatcher_,
+ CreateQuicSession(server_connection_id, client_address,
+ Eq(ExpectedAlpn()), _))
+ .WillOnce(Return(ByMove(CreateSession(
+ dispatcher_.get(), config_, server_connection_id, client_address,
+ &mock_helper_, &mock_alarm_factory_, &crypto_config_,
+ QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_))));
+ EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
+ ProcessUdpPacket(_, _, _))
+ .Times(2);
+
+ ProcessReceivedPacket(std::move(packets[1]), client_address, version_,
+ server_connection_id);
+ EXPECT_EQ(dispatcher_->session_map().size(), 1u);
+}
+
+TEST_P(QuicDispatcherTestAllVersions, TlsMultiPacketClientHello) {
+ TestTlsMultiPacketClientHello(/*add_reordering=*/false);
+}
+
+TEST_P(QuicDispatcherTestAllVersions, TlsMultiPacketClientHelloWithReordering) {
+ TestTlsMultiPacketClientHello(/*add_reordering=*/true);
}
TEST_P(QuicDispatcherTestAllVersions, ProcessPackets) {
@@ -475,7 +598,7 @@ TEST_P(QuicDispatcherTestAllVersions, ProcessPackets) {
EXPECT_CALL(*dispatcher_,
ShouldCreateOrBufferPacketForConnection(
ReceivedPacketInfoConnectionIdEquals(TestConnectionId(1))));
- ProcessPacket(client_address, TestConnectionId(1), true, SerializeCHLO());
+ ProcessFirstFlight(client_address, TestConnectionId(1));
EXPECT_CALL(*dispatcher_,
CreateQuicSession(TestConnectionId(2), client_address,
@@ -492,7 +615,7 @@ TEST_P(QuicDispatcherTestAllVersions, ProcessPackets) {
EXPECT_CALL(*dispatcher_,
ShouldCreateOrBufferPacketForConnection(
ReceivedPacketInfoConnectionIdEquals(TestConnectionId(2))));
- ProcessPacket(client_address, TestConnectionId(2), true, SerializeCHLO());
+ ProcessFirstFlight(client_address, TestConnectionId(2));
EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
ProcessUdpPacket(_, _, _))
@@ -525,9 +648,7 @@ TEST_P(QuicDispatcherTestAllVersions, DispatcherDoesNotRejectPacketNumberZero) {
EXPECT_CALL(*dispatcher_,
ShouldCreateOrBufferPacketForConnection(
ReceivedPacketInfoConnectionIdEquals(TestConnectionId(1))));
- ProcessPacket(client_address, TestConnectionId(1), true, version_,
- SerializeCHLO(), true, CONNECTION_ID_PRESENT,
- PACKET_4BYTE_PACKET_NUMBER, 1);
+ ProcessFirstFlight(client_address, TestConnectionId(1));
// Packet number 256 with packet number length 1 would be considered as 0 in
// dispatcher.
ProcessPacket(client_address, TestConnectionId(1), false, version_, "", true,
@@ -543,13 +664,8 @@ TEST_P(QuicDispatcherTestOneVersion, StatelessVersionNegotiation) {
*time_wait_list_manager_,
SendVersionNegotiationPacket(TestConnectionId(1), _, _, _, _, _, _, _))
.Times(1);
- // Pad the CHLO message with enough data to make the packet large enough
- // to trigger version negotiation.
- std::string chlo = SerializeCHLO() + std::string(1200, 'a');
- DCHECK_LE(1200u, chlo.length());
- ProcessPacket(client_address, TestConnectionId(1), true,
- QuicVersionReservedForNegotiation(), chlo, true,
- CONNECTION_ID_PRESENT, PACKET_4BYTE_PACKET_NUMBER, 1);
+ ProcessFirstFlight(QuicVersionReservedForNegotiation(), client_address,
+ TestConnectionId(1));
}
TEST_P(QuicDispatcherTestOneVersion,
@@ -562,13 +678,8 @@ TEST_P(QuicDispatcherTestOneVersion,
EXPECT_CALL(*time_wait_list_manager_,
SendVersionNegotiationPacket(connection_id, _, _, _, _, _, _, _))
.Times(1);
- // Pad the CHLO message with enough data to make the packet large enough
- // to trigger version negotiation.
- std::string chlo = SerializeCHLO() + std::string(1200, 'a');
- DCHECK_LE(1200u, chlo.length());
- ProcessPacket(client_address, connection_id, true,
- QuicVersionReservedForNegotiation(), chlo, true,
- CONNECTION_ID_PRESENT, PACKET_4BYTE_PACKET_NUMBER, 1);
+ ProcessFirstFlight(QuicVersionReservedForNegotiation(), client_address,
+ connection_id);
}
TEST_P(QuicDispatcherTestOneVersion,
@@ -581,14 +692,8 @@ TEST_P(QuicDispatcherTestOneVersion,
SendVersionNegotiationPacket(
TestConnectionId(1), TestConnectionId(2), _, _, _, _, _, _))
.Times(1);
- // Pad the CHLO message with enough data to make the packet large enough
- // to trigger version negotiation.
- std::string chlo = SerializeCHLO() + std::string(1200, 'a');
- DCHECK_LE(1200u, chlo.length());
- ProcessPacket(client_address, TestConnectionId(1), TestConnectionId(2), true,
- QuicVersionReservedForNegotiation(), chlo, true,
- CONNECTION_ID_PRESENT, CONNECTION_ID_PRESENT,
- PACKET_4BYTE_PACKET_NUMBER, 1);
+ ProcessFirstFlight(QuicVersionReservedForNegotiation(), client_address,
+ TestConnectionId(1), TestConnectionId(2));
}
TEST_P(QuicDispatcherTestOneVersion, NoVersionNegotiationWithSmallPacket) {
@@ -652,7 +757,7 @@ TEST_P(QuicDispatcherTestAllVersions, Shutdown) {
EXPECT_CALL(*dispatcher_,
ShouldCreateOrBufferPacketForConnection(
ReceivedPacketInfoConnectionIdEquals(TestConnectionId(1))));
- ProcessPacket(client_address, TestConnectionId(1), true, SerializeCHLO());
+ ProcessFirstFlight(client_address, TestConnectionId(1));
EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
CloseConnection(QUIC_PEER_GOING_AWAY, _, _));
@@ -681,7 +786,7 @@ TEST_P(QuicDispatcherTestAllVersions, TimeWaitListManager) {
EXPECT_CALL(*dispatcher_,
ShouldCreateOrBufferPacketForConnection(
ReceivedPacketInfoConnectionIdEquals(TestConnectionId(1))));
- ProcessPacket(client_address, connection_id, true, SerializeCHLO());
+ ProcessFirstFlight(client_address, connection_id);
// Now close the connection, which should add it to the time wait list.
session1_->connection()->CloseConnection(
@@ -717,7 +822,8 @@ TEST_P(QuicDispatcherTestAllVersions, NoVersionPacketToTimeWaitListManager) {
.Times(0);
EXPECT_CALL(*time_wait_list_manager_, SendPublicReset(_, _, _, _, _))
.Times(1);
- ProcessPacket(client_address, connection_id, false, SerializeCHLO());
+ ProcessPacket(client_address, connection_id, /*has_version_flag=*/false,
+ "data");
}
TEST_P(QuicDispatcherTestAllVersions,
@@ -772,7 +878,7 @@ TEST_P(QuicDispatcherTestAllVersions, LongConnectionIdLengthReplaced) {
EXPECT_CALL(*dispatcher_,
ShouldCreateOrBufferPacketForConnection(
ReceivedPacketInfoConnectionIdEquals(bad_connection_id)));
- ProcessPacket(client_address, bad_connection_id, true, SerializeCHLO());
+ ProcessFirstFlight(client_address, bad_connection_id);
}
// Makes sure zero-byte connection IDs are replaced by 8-byte ones.
@@ -809,7 +915,7 @@ TEST_P(QuicDispatcherTestAllVersions, InvalidShortConnectionIdLengthReplaced) {
EXPECT_CALL(*dispatcher_,
ShouldCreateOrBufferPacketForConnection(
ReceivedPacketInfoConnectionIdEquals(bad_connection_id)));
- ProcessPacket(client_address, bad_connection_id, true, SerializeCHLO());
+ ProcessFirstFlight(client_address, bad_connection_id);
}
// Makes sure TestConnectionId(1) creates a new connection and
@@ -839,7 +945,7 @@ TEST_P(QuicDispatcherTestAllVersions, MixGoodAndBadConnectionIdLengthPackets) {
EXPECT_CALL(*dispatcher_,
ShouldCreateOrBufferPacketForConnection(
ReceivedPacketInfoConnectionIdEquals(TestConnectionId(1))));
- ProcessPacket(client_address, TestConnectionId(1), true, SerializeCHLO());
+ ProcessFirstFlight(client_address, TestConnectionId(1));
EXPECT_CALL(*dispatcher_,
CreateQuicSession(fixed_connection_id, client_address,
@@ -857,7 +963,7 @@ TEST_P(QuicDispatcherTestAllVersions, MixGoodAndBadConnectionIdLengthPackets) {
EXPECT_CALL(*dispatcher_,
ShouldCreateOrBufferPacketForConnection(
ReceivedPacketInfoConnectionIdEquals(bad_connection_id)));
- ProcessPacket(client_address, bad_connection_id, true, SerializeCHLO());
+ ProcessFirstFlight(client_address, bad_connection_id);
EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
ProcessUdpPacket(_, _, _))
@@ -881,7 +987,8 @@ TEST_P(QuicDispatcherTestAllVersions, ProcessPacketWithZeroPort) {
EXPECT_CALL(*time_wait_list_manager_,
AddConnectionIdToTimeWait(_, _, _, _, _))
.Times(0);
- ProcessPacket(client_address, TestConnectionId(1), true, SerializeCHLO());
+ ProcessPacket(client_address, TestConnectionId(1), /*has_version_flag=*/true,
+ "data");
}
TEST_P(QuicDispatcherTestAllVersions,
@@ -900,10 +1007,14 @@ TEST_P(QuicDispatcherTestAllVersions,
EXPECT_CALL(*time_wait_list_manager_,
AddConnectionIdToTimeWait(_, _, _, _, _))
.Times(0);
- ProcessPacket(client_address, EmptyQuicConnectionId(), true, SerializeCHLO());
+ ProcessFirstFlight(client_address, EmptyQuicConnectionId());
}
TEST_P(QuicDispatcherTestAllVersions, OKSeqNoPacketProcessed) {
+ if (version_.UsesTls()) {
+ // QUIC+TLS allows clients to start with any packet number.
+ return;
+ }
QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
QuicConnectionId connection_id = TestConnectionId(1);
@@ -1165,7 +1276,10 @@ TEST_P(QuicDispatcherTestOneVersion, VersionNegotiationProbeEndToEnd) {
}
TEST_P(QuicDispatcherTestOneVersion, AndroidConformanceTestOld) {
- // TODO(b/139691956) Remove this test once the workaround is removed.
+ if (GetQuicReloadableFlag(quic_remove_android_conformance_test_workaround)) {
+ // TODO(b/139691956) Remove this test once the flag is deprecated.
+ return;
+ }
SavingWriter* saving_writer = new SavingWriter();
// dispatcher_ takes ownership of saving_writer.
QuicDispatcherPeer::UseWriter(dispatcher_.get(), saving_writer);
@@ -1339,7 +1453,7 @@ TEST_P(QuicDispatcherTestAllVersions, StopAcceptingNewConnections) {
.WillOnce(WithArg<2>(Invoke([this](const QuicEncryptedPacket& packet) {
ValidatePacket(TestConnectionId(1), packet);
})));
- ProcessPacket(client_address, TestConnectionId(1), true, SerializeCHLO());
+ ProcessFirstFlight(client_address, TestConnectionId(1));
dispatcher_->StopAcceptingNewConnections();
EXPECT_FALSE(dispatcher_->accept_new_connections());
@@ -1349,7 +1463,7 @@ TEST_P(QuicDispatcherTestAllVersions, StopAcceptingNewConnections) {
CreateQuicSession(TestConnectionId(2), client_address,
Eq(ExpectedAlpn()), _))
.Times(0u);
- ProcessPacket(client_address, TestConnectionId(2), true, SerializeCHLO());
+ ProcessFirstFlight(client_address, TestConnectionId(2));
// Existing connections should be able to continue.
EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
@@ -1370,7 +1484,7 @@ TEST_P(QuicDispatcherTestAllVersions, StartAcceptingNewConnections) {
CreateQuicSession(TestConnectionId(2), client_address,
Eq(ExpectedAlpn()), _))
.Times(0u);
- ProcessPacket(client_address, TestConnectionId(2), true, SerializeCHLO());
+ ProcessFirstFlight(client_address, TestConnectionId(2));
dispatcher_->StartAcceptingNewConnections();
EXPECT_TRUE(dispatcher_->accept_new_connections());
@@ -1387,7 +1501,18 @@ TEST_P(QuicDispatcherTestAllVersions, StartAcceptingNewConnections) {
.WillOnce(WithArg<2>(Invoke([this](const QuicEncryptedPacket& packet) {
ValidatePacket(TestConnectionId(1), packet);
})));
- ProcessPacket(client_address, TestConnectionId(1), true, SerializeCHLO());
+ ProcessFirstFlight(client_address, TestConnectionId(1));
+}
+
+TEST_P(QuicDispatcherTestOneVersion, SelectAlpn) {
+ EXPECT_EQ(QuicDispatcherPeer::SelectAlpn(dispatcher_.get(), {}), "");
+ EXPECT_EQ(QuicDispatcherPeer::SelectAlpn(dispatcher_.get(), {""}), "");
+ EXPECT_EQ(QuicDispatcherPeer::SelectAlpn(dispatcher_.get(), {"hq"}), "hq");
+ // Q033 is no longer supported but Q050 is.
+ QuicEnableVersion(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50));
+ EXPECT_EQ(
+ QuicDispatcherPeer::SelectAlpn(dispatcher_.get(), {"h3-Q033", "h3-Q050"}),
+ "h3-Q050");
}
// Verify the stopgap test: Packets with truncated connection IDs should be
@@ -1462,7 +1587,7 @@ class QuicDispatcherWriteBlockedListTest : public QuicDispatcherTestBase {
EXPECT_CALL(*dispatcher_,
ShouldCreateOrBufferPacketForConnection(
ReceivedPacketInfoConnectionIdEquals(TestConnectionId(1))));
- ProcessPacket(client_address, TestConnectionId(1), true, SerializeCHLO());
+ ProcessFirstFlight(client_address, TestConnectionId(1));
EXPECT_CALL(*dispatcher_,
CreateQuicSession(_, client_address, Eq(ExpectedAlpn()), _))
@@ -1478,7 +1603,7 @@ class QuicDispatcherWriteBlockedListTest : public QuicDispatcherTestBase {
EXPECT_CALL(*dispatcher_,
ShouldCreateOrBufferPacketForConnection(
ReceivedPacketInfoConnectionIdEquals(TestConnectionId(2))));
- ProcessPacket(client_address, TestConnectionId(2), true, SerializeCHLO());
+ ProcessFirstFlight(client_address, TestConnectionId(2));
blocked_list_ = QuicDispatcherPeer::GetWriteBlockedList(dispatcher_.get());
}
@@ -1724,69 +1849,100 @@ class BufferedPacketStoreTest : public QuicDispatcherTestBase {
public:
BufferedPacketStoreTest()
: QuicDispatcherTestBase(),
- server_addr_(QuicSocketAddress(QuicIpAddress::Any4(), 5)),
- client_addr_(QuicIpAddress::Loopback4(), 1234),
- signed_config_(new QuicSignedServerConfig) {}
+ client_addr_(QuicIpAddress::Loopback4(), 1234) {}
- void SetUp() override {
- QuicDispatcherTestBase::SetUp();
- clock_ = QuicDispatcherPeer::GetHelper(dispatcher_.get())->GetClock();
+ void ProcessFirstFlight(const ParsedQuicVersion& version,
+ const QuicSocketAddress& peer_address,
+ const QuicConnectionId& server_connection_id) {
+ QuicDispatcherTestBase::ProcessFirstFlight(version, peer_address,
+ server_connection_id);
+ }
- ASSERT_EQ(PROTOCOL_QUIC_CRYPTO, version_.handshake_protocol);
- ASSERT_NE(QUIC_VERSION_UNSUPPORTED, version_.transport_version);
+ void ProcessFirstFlight(const QuicSocketAddress& peer_address,
+ const QuicConnectionId& server_connection_id) {
+ ProcessFirstFlight(version_, peer_address, server_connection_id);
+ }
- CryptoHandshakeMessage chlo =
- crypto_test_utils::GenerateDefaultInchoateCHLO(
- clock_, version_.transport_version, &crypto_config_);
- // Pass an inchoate CHLO.
- crypto_test_utils::GenerateFullCHLO(
- chlo, &crypto_config_, server_addr_, client_addr_,
- version_.transport_version, clock_, signed_config_,
- QuicDispatcherPeer::GetCache(dispatcher_.get()), &full_chlo_);
+ void ProcessFirstFlight(const QuicConnectionId& server_connection_id) {
+ ProcessFirstFlight(client_addr_, server_connection_id);
}
- std::string SerializeFullCHLO() {
- return std::string(full_chlo_.GetSerialized().AsStringPiece());
+ void ProcessFirstFlight(const ParsedQuicVersion& version,
+ const QuicConnectionId& server_connection_id) {
+ ProcessFirstFlight(version, client_addr_, server_connection_id);
+ }
+
+ void ProcessUndecryptableEarlyPacket(
+ const ParsedQuicVersion& version,
+ const QuicSocketAddress& peer_address,
+ const QuicConnectionId& server_connection_id) {
+ QuicDispatcherTestBase::ProcessUndecryptableEarlyPacket(
+ version, peer_address, server_connection_id);
+ }
+
+ void ProcessUndecryptableEarlyPacket(
+ const QuicSocketAddress& peer_address,
+ const QuicConnectionId& server_connection_id) {
+ ProcessUndecryptableEarlyPacket(version_, peer_address,
+ server_connection_id);
+ }
+
+ void ProcessUndecryptableEarlyPacket(
+ const QuicConnectionId& server_connection_id) {
+ ProcessUndecryptableEarlyPacket(version_, client_addr_,
+ server_connection_id);
}
protected:
- QuicSocketAddress server_addr_;
QuicSocketAddress client_addr_;
- QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config_;
- const QuicClock* clock_;
- CryptoHandshakeMessage full_chlo_;
};
-ParsedQuicVersionVector BufferedPacketStoreTestParams() {
- ParsedQuicVersionVector versions;
- for (const ParsedQuicVersion& version : CurrentSupportedVersions()) {
- if (version.handshake_protocol != PROTOCOL_QUIC_CRYPTO) {
- // TODO(b/149597791) Remove this once we can parse ALPN with TLS.
- break;
- }
- versions.push_back(version);
- }
- return versions;
-}
-
INSTANTIATE_TEST_SUITE_P(BufferedPacketStoreTests,
BufferedPacketStoreTest,
- ::testing::ValuesIn(BufferedPacketStoreTestParams()),
+ ::testing::ValuesIn(CurrentSupportedVersions()),
::testing::PrintToStringParamName());
+TEST_P(BufferedPacketStoreTest, ProcessNonChloPacketBeforeChlo) {
+ InSequence s;
+ QuicConnectionId conn_id = TestConnectionId(1);
+ // Non-CHLO should be buffered upon arrival, and should trigger
+ // ShouldCreateOrBufferPacketForConnection().
+ EXPECT_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection(
+ ReceivedPacketInfoConnectionIdEquals(conn_id)));
+ // Process non-CHLO packet.
+ ProcessUndecryptableEarlyPacket(conn_id);
+ EXPECT_EQ(0u, dispatcher_->session_map().size())
+ << "No session should be created before CHLO arrives.";
+
+ // When CHLO arrives, a new session should be created, and all packets
+ // buffered should be delivered to the session.
+ EXPECT_CALL(*dispatcher_,
+ CreateQuicSession(conn_id, client_addr_, Eq(ExpectedAlpn()), _))
+ .WillOnce(Return(ByMove(CreateSession(
+ dispatcher_.get(), config_, conn_id, client_addr_, &mock_helper_,
+ &mock_alarm_factory_, &crypto_config_,
+ QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_))));
+ EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
+ ProcessUdpPacket(_, _, _))
+ .Times(2) // non-CHLO + CHLO.
+ .WillRepeatedly(
+ WithArg<2>(Invoke([this, conn_id](const QuicEncryptedPacket& packet) {
+ if (version_.UsesQuicCrypto()) {
+ ValidatePacket(conn_id, packet);
+ }
+ })));
+ ProcessFirstFlight(conn_id);
+}
+
TEST_P(BufferedPacketStoreTest, ProcessNonChloPacketsUptoLimitAndProcessChlo) {
InSequence s;
- QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
QuicConnectionId conn_id = TestConnectionId(1);
// A bunch of non-CHLO should be buffered upon arrival, and the first one
// should trigger ShouldCreateOrBufferPacketForConnection().
EXPECT_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection(
ReceivedPacketInfoConnectionIdEquals(conn_id)));
for (size_t i = 1; i <= kDefaultMaxUndecryptablePackets + 1; ++i) {
- ProcessPacket(client_address, conn_id, true,
- quiche::QuicheStrCat("data packet ", i + 1),
- CONNECTION_ID_PRESENT, PACKET_4BYTE_PACKET_NUMBER,
- /*packet_number=*/i + 1);
+ ProcessUndecryptableEarlyPacket(conn_id);
}
EXPECT_EQ(0u, dispatcher_->session_map().size())
<< "No session should be created before CHLO arrives.";
@@ -1795,10 +1951,10 @@ TEST_P(BufferedPacketStoreTest, ProcessNonChloPacketsUptoLimitAndProcessChlo) {
data_connection_map_[conn_id].pop_back();
// When CHLO arrives, a new session should be created, and all packets
// buffered should be delivered to the session.
- EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_address,
- quiche::QuicheStringPiece(), _))
+ EXPECT_CALL(*dispatcher_,
+ CreateQuicSession(conn_id, client_addr_, Eq(ExpectedAlpn()), _))
.WillOnce(Return(ByMove(CreateSession(
- dispatcher_.get(), config_, conn_id, client_address, &mock_helper_,
+ dispatcher_.get(), config_, conn_id, client_addr_, &mock_helper_,
&mock_alarm_factory_, &crypto_config_,
QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_))));
@@ -1809,9 +1965,11 @@ TEST_P(BufferedPacketStoreTest, ProcessNonChloPacketsUptoLimitAndProcessChlo) {
.Times(kDefaultMaxUndecryptablePackets + 1) // + 1 for CHLO.
.WillRepeatedly(
WithArg<2>(Invoke([this, conn_id](const QuicEncryptedPacket& packet) {
- ValidatePacket(conn_id, packet);
+ if (version_.UsesQuicCrypto()) {
+ ValidatePacket(conn_id, packet);
+ }
})));
- ProcessPacket(client_address, conn_id, true, SerializeFullCHLO());
+ ProcessFirstFlight(conn_id);
}
TEST_P(BufferedPacketStoreTest,
@@ -1825,10 +1983,7 @@ TEST_P(BufferedPacketStoreTest,
EXPECT_CALL(*dispatcher_,
ShouldCreateOrBufferPacketForConnection(
ReceivedPacketInfoConnectionIdEquals(conn_id)));
- ProcessPacket(client_address, conn_id, true,
- quiche::QuicheStrCat("data packet on connection ", i),
- CONNECTION_ID_PRESENT, PACKET_4BYTE_PACKET_NUMBER,
- /*packet_number=*/2);
+ ProcessUndecryptableEarlyPacket(client_address, conn_id);
}
// Pop out the packet on last connection as it shouldn't be enqueued in store
@@ -1849,7 +2004,7 @@ TEST_P(BufferedPacketStoreTest,
ReceivedPacketInfoConnectionIdEquals(conn_id)));
}
EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_address,
- quiche::QuicheStringPiece(), _))
+ Eq(ExpectedAlpn()), _))
.WillOnce(Return(ByMove(CreateSession(
dispatcher_.get(), config_, conn_id, client_address, &mock_helper_,
&mock_alarm_factory_, &crypto_config_,
@@ -1862,48 +2017,45 @@ TEST_P(BufferedPacketStoreTest,
.Times(num_packet_to_process)
.WillRepeatedly(WithArg<2>(
Invoke([this, conn_id](const QuicEncryptedPacket& packet) {
- ValidatePacket(conn_id, packet);
+ if (version_.UsesQuicCrypto()) {
+ ValidatePacket(conn_id, packet);
+ }
})));
- ProcessPacket(client_address, conn_id, true, SerializeFullCHLO());
+ ProcessFirstFlight(client_address, conn_id);
}
}
// Tests that store delivers empty packet list if CHLO arrives firstly.
TEST_P(BufferedPacketStoreTest, DeliverEmptyPackets) {
QuicConnectionId conn_id = TestConnectionId(1);
- QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
EXPECT_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection(
ReceivedPacketInfoConnectionIdEquals(conn_id)));
- EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_address,
- quiche::QuicheStringPiece(), _))
+ EXPECT_CALL(*dispatcher_,
+ CreateQuicSession(conn_id, client_addr_, Eq(ExpectedAlpn()), _))
.WillOnce(Return(ByMove(CreateSession(
- dispatcher_.get(), config_, conn_id, client_address, &mock_helper_,
+ dispatcher_.get(), config_, conn_id, client_addr_, &mock_helper_,
&mock_alarm_factory_, &crypto_config_,
QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_))));
EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
- ProcessUdpPacket(_, client_address, _));
- ProcessPacket(client_address, conn_id, true, SerializeFullCHLO());
+ ProcessUdpPacket(_, client_addr_, _));
+ ProcessFirstFlight(conn_id);
}
// Tests that a retransmitted CHLO arrives after a connection for the
// CHLO has been created.
TEST_P(BufferedPacketStoreTest, ReceiveRetransmittedCHLO) {
InSequence s;
- QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
QuicConnectionId conn_id = TestConnectionId(1);
- ProcessPacket(client_address, conn_id, true,
- quiche::QuicheStrCat("data packet ", 2), CONNECTION_ID_PRESENT,
- PACKET_4BYTE_PACKET_NUMBER,
- /*packet_number=*/2);
+ ProcessUndecryptableEarlyPacket(conn_id);
// When CHLO arrives, a new session should be created, and all packets
// buffered should be delivered to the session.
- EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_address,
- quiche::QuicheStringPiece(), _))
+ EXPECT_CALL(*dispatcher_,
+ CreateQuicSession(conn_id, client_addr_, Eq(ExpectedAlpn()), _))
.Times(1) // Only triggered by 1st CHLO.
.WillOnce(Return(ByMove(CreateSession(
- dispatcher_.get(), config_, conn_id, client_address, &mock_helper_,
+ dispatcher_.get(), config_, conn_id, client_addr_, &mock_helper_,
&mock_alarm_factory_, &crypto_config_,
QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_))));
EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
@@ -1911,11 +2063,18 @@ TEST_P(BufferedPacketStoreTest, ReceiveRetransmittedCHLO) {
.Times(3) // Triggered by 1 data packet and 2 CHLOs.
.WillRepeatedly(
WithArg<2>(Invoke([this, conn_id](const QuicEncryptedPacket& packet) {
- ValidatePacket(conn_id, packet);
+ if (version_.UsesQuicCrypto()) {
+ ValidatePacket(conn_id, packet);
+ }
})));
- ProcessPacket(client_address, conn_id, true, SerializeFullCHLO());
- ProcessPacket(client_address, conn_id, true, SerializeFullCHLO());
+ std::vector<std::unique_ptr<QuicReceivedPacket>> packets =
+ GetFirstFlightOfPackets(version_, conn_id);
+ ASSERT_EQ(packets.size(), 1u);
+ // Receive the CHLO once.
+ ProcessReceivedPacket(packets[0]->Clone(), client_addr_, version_, conn_id);
+ // Receive the CHLO a second time to simulate retransmission.
+ ProcessReceivedPacket(std::move(packets[0]), client_addr_, version_, conn_id);
}
// Tests that expiration of a connection add connection id to time wait list.
@@ -1926,9 +2085,8 @@ TEST_P(BufferedPacketStoreTest, ReceiveCHLOAfterExpiration) {
QuicDispatcherPeer::GetBufferedPackets(dispatcher_.get());
QuicBufferedPacketStorePeer::set_clock(store, mock_helper_.GetClock());
- QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
QuicConnectionId conn_id = TestConnectionId(1);
- ProcessPacket(client_address, conn_id, true,
+ ProcessPacket(client_addr_, conn_id, true,
quiche::QuicheStrCat("data packet ", 2), CONNECTION_ID_PRESENT,
PACKET_4BYTE_PACKET_NUMBER,
/*packet_number=*/2);
@@ -1943,7 +2101,7 @@ TEST_P(BufferedPacketStoreTest, ReceiveCHLOAfterExpiration) {
// list.
ASSERT_TRUE(time_wait_list_manager_->IsConnectionIdInTimeWait(conn_id));
EXPECT_CALL(*time_wait_list_manager_, ProcessPacket(_, _, conn_id, _, _));
- ProcessPacket(client_address, conn_id, true, SerializeFullCHLO());
+ ProcessFirstFlight(conn_id);
}
TEST_P(BufferedPacketStoreTest, ProcessCHLOsUptoLimitAndBufferTheRest) {
@@ -1964,7 +2122,7 @@ TEST_P(BufferedPacketStoreTest, ProcessCHLOsUptoLimitAndBufferTheRest) {
if (conn_id <= kMaxNumSessionsToCreate) {
EXPECT_CALL(*dispatcher_,
CreateQuicSession(TestConnectionId(conn_id), client_addr_,
- quiche::QuicheStringPiece(), _))
+ Eq(ExpectedAlpn()), _))
.WillOnce(Return(ByMove(CreateSession(
dispatcher_.get(), config_, TestConnectionId(conn_id),
client_addr_, &mock_helper_, &mock_alarm_factory_,
@@ -1975,11 +2133,12 @@ TEST_P(BufferedPacketStoreTest, ProcessCHLOsUptoLimitAndBufferTheRest) {
ProcessUdpPacket(_, _, _))
.WillOnce(WithArg<2>(
Invoke([this, conn_id](const QuicEncryptedPacket& packet) {
- ValidatePacket(TestConnectionId(conn_id), packet);
+ if (version_.UsesQuicCrypto()) {
+ ValidatePacket(TestConnectionId(conn_id), packet);
+ }
})));
}
- ProcessPacket(client_addr_, TestConnectionId(conn_id), true,
- SerializeFullCHLO());
+ ProcessFirstFlight(TestConnectionId(conn_id));
if (conn_id <= kMaxNumSessionsToCreate + kDefaultMaxConnectionsInStore &&
conn_id > kMaxNumSessionsToCreate) {
EXPECT_TRUE(store->HasChloForConnection(TestConnectionId(conn_id)));
@@ -1998,7 +2157,7 @@ TEST_P(BufferedPacketStoreTest, ProcessCHLOsUptoLimitAndBufferTheRest) {
++conn_id) {
EXPECT_CALL(*dispatcher_,
CreateQuicSession(TestConnectionId(conn_id), client_addr_,
- quiche::QuicheStringPiece(), _))
+ Eq(ExpectedAlpn()), _))
.WillOnce(Return(ByMove(CreateSession(
dispatcher_.get(), config_, TestConnectionId(conn_id), client_addr_,
&mock_helper_, &mock_alarm_factory_, &crypto_config_,
@@ -2007,12 +2166,14 @@ TEST_P(BufferedPacketStoreTest, ProcessCHLOsUptoLimitAndBufferTheRest) {
ProcessUdpPacket(_, _, _))
.WillOnce(WithArg<2>(
Invoke([this, conn_id](const QuicEncryptedPacket& packet) {
- ValidatePacket(TestConnectionId(conn_id), packet);
+ if (version_.UsesQuicCrypto()) {
+ ValidatePacket(TestConnectionId(conn_id), packet);
+ }
})));
}
EXPECT_CALL(*dispatcher_,
CreateQuicSession(TestConnectionId(kNumCHLOs), client_addr_,
- quiche::QuicheStringPiece(), _))
+ Eq(ExpectedAlpn()), _))
.Times(0);
while (store->HasChlosBuffered()) {
@@ -2032,7 +2193,7 @@ TEST_P(BufferedPacketStoreTest, BufferDuplicatedCHLO) {
if (conn_id <= kMaxNumSessionsToCreate) {
EXPECT_CALL(*dispatcher_,
CreateQuicSession(TestConnectionId(conn_id), client_addr_,
- quiche::QuicheStringPiece(), _))
+ Eq(ExpectedAlpn()), _))
.WillOnce(Return(ByMove(CreateSession(
dispatcher_.get(), config_, TestConnectionId(conn_id),
client_addr_, &mock_helper_, &mock_alarm_factory_,
@@ -2043,22 +2204,23 @@ TEST_P(BufferedPacketStoreTest, BufferDuplicatedCHLO) {
ProcessUdpPacket(_, _, _))
.WillOnce(WithArg<2>(
Invoke([this, conn_id](const QuicEncryptedPacket& packet) {
- ValidatePacket(TestConnectionId(conn_id), packet);
+ if (version_.UsesQuicCrypto()) {
+ ValidatePacket(TestConnectionId(conn_id), packet);
+ }
})));
}
- ProcessPacket(client_addr_, TestConnectionId(conn_id), true,
- SerializeFullCHLO());
+ ProcessFirstFlight(TestConnectionId(conn_id));
}
// Retransmit CHLO on last connection should be dropped.
QuicConnectionId last_connection =
TestConnectionId(kMaxNumSessionsToCreate + 1);
- ProcessPacket(client_addr_, last_connection, true, SerializeFullCHLO());
+ ProcessFirstFlight(last_connection);
size_t packets_buffered = 2;
// Reset counter and process buffered CHLO.
EXPECT_CALL(*dispatcher_, CreateQuicSession(last_connection, client_addr_,
- quiche::QuicheStringPiece(), _))
+ Eq(ExpectedAlpn()), _))
.WillOnce(Return(ByMove(CreateSession(
dispatcher_.get(), config_, last_connection, client_addr_,
&mock_helper_, &mock_alarm_factory_, &crypto_config_,
@@ -2069,7 +2231,9 @@ TEST_P(BufferedPacketStoreTest, BufferDuplicatedCHLO) {
.Times(packets_buffered)
.WillRepeatedly(WithArg<2>(
Invoke([this, last_connection](const QuicEncryptedPacket& packet) {
- ValidatePacket(last_connection, packet);
+ if (version_.UsesQuicCrypto()) {
+ ValidatePacket(last_connection, packet);
+ }
})));
dispatcher_->ProcessBufferedChlos(kMaxNumSessionsToCreate);
}
@@ -2082,7 +2246,7 @@ TEST_P(BufferedPacketStoreTest, BufferNonChloPacketsUptoLimitWithChloBuffered) {
if (conn_id <= kMaxNumSessionsToCreate) {
EXPECT_CALL(*dispatcher_,
CreateQuicSession(TestConnectionId(conn_id), client_addr_,
- quiche::QuicheStringPiece(), _))
+ Eq(ExpectedAlpn()), _))
.WillOnce(Return(ByMove(CreateSession(
dispatcher_.get(), config_, TestConnectionId(conn_id),
client_addr_, &mock_helper_, &mock_alarm_factory_,
@@ -2093,11 +2257,12 @@ TEST_P(BufferedPacketStoreTest, BufferNonChloPacketsUptoLimitWithChloBuffered) {
ProcessUdpPacket(_, _, _))
.WillRepeatedly(WithArg<2>(
Invoke([this, conn_id](const QuicEncryptedPacket& packet) {
- ValidatePacket(TestConnectionId(conn_id), packet);
+ if (version_.UsesQuicCrypto()) {
+ ValidatePacket(TestConnectionId(conn_id), packet);
+ }
})));
}
- ProcessPacket(client_addr_, TestConnectionId(conn_id), true,
- SerializeFullCHLO());
+ ProcessFirstFlight(TestConnectionId(conn_id));
}
// Process another |kDefaultMaxUndecryptablePackets| + 1 data packets. The
@@ -2109,7 +2274,7 @@ TEST_P(BufferedPacketStoreTest, BufferNonChloPacketsUptoLimitWithChloBuffered) {
// Reset counter and process buffered CHLO.
EXPECT_CALL(*dispatcher_, CreateQuicSession(last_connection_id, client_addr_,
- quiche::QuicheStringPiece(), _))
+ Eq(ExpectedAlpn()), _))
.WillOnce(Return(ByMove(CreateSession(
dispatcher_.get(), config_, last_connection_id, client_addr_,
&mock_helper_, &mock_alarm_factory_, &crypto_config_,
@@ -2121,7 +2286,9 @@ TEST_P(BufferedPacketStoreTest, BufferNonChloPacketsUptoLimitWithChloBuffered) {
.Times(kDefaultMaxUndecryptablePackets + 1)
.WillRepeatedly(WithArg<2>(
Invoke([this, last_connection_id](const QuicEncryptedPacket& packet) {
- ValidatePacket(last_connection_id, packet);
+ if (version_.UsesQuicCrypto()) {
+ ValidatePacket(last_connection_id, packet);
+ }
})));
dispatcher_->ProcessBufferedChlos(kMaxNumSessionsToCreate);
}
@@ -2133,9 +2300,7 @@ TEST_P(BufferedPacketStoreTest, ReceiveCHLOForBufferedConnection) {
QuicDispatcherPeer::GetBufferedPackets(dispatcher_.get());
uint64_t conn_id = 1;
- ProcessPacket(client_addr_, TestConnectionId(conn_id), true, "data packet",
- CONNECTION_ID_PRESENT, PACKET_4BYTE_PACKET_NUMBER,
- /*packet_number=*/1);
+ ProcessUndecryptableEarlyPacket(TestConnectionId(conn_id));
// Fill packet buffer to full with CHLOs on other connections. Need to feed
// extra CHLOs because the first |kMaxNumSessionsToCreate| are going to create
// session directly.
@@ -2145,7 +2310,7 @@ TEST_P(BufferedPacketStoreTest, ReceiveCHLOForBufferedConnection) {
if (conn_id <= kMaxNumSessionsToCreate + 1) {
EXPECT_CALL(*dispatcher_,
CreateQuicSession(TestConnectionId(conn_id), client_addr_,
- quiche::QuicheStringPiece(), _))
+ Eq(ExpectedAlpn()), _))
.WillOnce(Return(ByMove(CreateSession(
dispatcher_.get(), config_, TestConnectionId(conn_id),
client_addr_, &mock_helper_, &mock_alarm_factory_,
@@ -2156,18 +2321,18 @@ TEST_P(BufferedPacketStoreTest, ReceiveCHLOForBufferedConnection) {
ProcessUdpPacket(_, _, _))
.WillOnce(WithArg<2>(
Invoke([this, conn_id](const QuicEncryptedPacket& packet) {
- ValidatePacket(TestConnectionId(conn_id), packet);
+ if (version_.UsesQuicCrypto()) {
+ ValidatePacket(TestConnectionId(conn_id), packet);
+ }
})));
}
- ProcessPacket(client_addr_, TestConnectionId(conn_id), true,
- SerializeFullCHLO());
+ ProcessFirstFlight(TestConnectionId(conn_id));
}
EXPECT_FALSE(store->HasChloForConnection(
/*connection_id=*/TestConnectionId(1)));
// CHLO on connection 1 should still be buffered.
- ProcessPacket(client_addr_, /*server_connection_id=*/TestConnectionId(1),
- true, SerializeFullCHLO());
+ ProcessFirstFlight(TestConnectionId(1));
EXPECT_TRUE(store->HasChloForConnection(
/*connection_id=*/TestConnectionId(1)));
}
@@ -2183,9 +2348,10 @@ TEST_P(BufferedPacketStoreTest, ProcessBufferedChloWithDifferentVersion) {
ParsedQuicVersion version =
supported_versions[(conn_id - 1) % supported_versions.size()];
if (conn_id <= kMaxNumSessionsToCreate) {
- EXPECT_CALL(*dispatcher_,
- CreateQuicSession(TestConnectionId(conn_id), client_addr_,
- quiche::QuicheStringPiece(), version))
+ EXPECT_CALL(
+ *dispatcher_,
+ CreateQuicSession(TestConnectionId(conn_id), client_addr_,
+ Eq(ExpectedAlpnForVersion(version)), version))
.WillOnce(Return(ByMove(CreateSession(
dispatcher_.get(), config_, TestConnectionId(conn_id),
client_addr_, &mock_helper_, &mock_alarm_factory_,
@@ -2196,12 +2362,12 @@ TEST_P(BufferedPacketStoreTest, ProcessBufferedChloWithDifferentVersion) {
ProcessUdpPacket(_, _, _))
.WillRepeatedly(WithArg<2>(
Invoke([this, conn_id](const QuicEncryptedPacket& packet) {
- ValidatePacket(TestConnectionId(conn_id), packet);
+ if (version_.UsesQuicCrypto()) {
+ ValidatePacket(TestConnectionId(conn_id), packet);
+ }
})));
}
- ProcessPacket(client_addr_, TestConnectionId(conn_id), true, version,
- SerializeFullCHLO(), true, CONNECTION_ID_PRESENT,
- PACKET_4BYTE_PACKET_NUMBER, 1);
+ ProcessFirstFlight(version, TestConnectionId(conn_id));
}
// Process buffered CHLOs. Verify the version is correct.
@@ -2211,7 +2377,7 @@ TEST_P(BufferedPacketStoreTest, ProcessBufferedChloWithDifferentVersion) {
supported_versions[(conn_id - 1) % supported_versions.size()];
EXPECT_CALL(*dispatcher_,
CreateQuicSession(TestConnectionId(conn_id), client_addr_,
- quiche::QuicheStringPiece(), version))
+ Eq(ExpectedAlpnForVersion(version)), version))
.WillOnce(Return(ByMove(CreateSession(
dispatcher_.get(), config_, TestConnectionId(conn_id), client_addr_,
&mock_helper_, &mock_alarm_factory_, &crypto_config_,
@@ -2220,7 +2386,9 @@ TEST_P(BufferedPacketStoreTest, ProcessBufferedChloWithDifferentVersion) {
ProcessUdpPacket(_, _, _))
.WillRepeatedly(WithArg<2>(
Invoke([this, conn_id](const QuicEncryptedPacket& packet) {
- ValidatePacket(TestConnectionId(conn_id), packet);
+ if (version_.UsesQuicCrypto()) {
+ ValidatePacket(TestConnectionId(conn_id), packet);
+ }
})));
}
dispatcher_->ProcessBufferedChlos(kMaxNumSessionsToCreate);
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 db97d32572d..6afccfece10 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
@@ -2,7 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <cstdint>
+#include <cstring>
+
+#include "third_party/boringssl/src/include/openssl/ssl.h"
#include "net/third_party/quiche/src/quic/core/quic_error_codes.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
+#include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h"
namespace quic {
@@ -13,15 +19,14 @@ namespace quic {
const char* QuicRstStreamErrorCodeToString(QuicRstStreamErrorCode error) {
switch (error) {
RETURN_STRING_LITERAL(QUIC_STREAM_NO_ERROR);
- RETURN_STRING_LITERAL(QUIC_STREAM_CONNECTION_ERROR);
RETURN_STRING_LITERAL(QUIC_ERROR_PROCESSING_STREAM);
RETURN_STRING_LITERAL(QUIC_MULTIPLE_TERMINATION_OFFSETS);
RETURN_STRING_LITERAL(QUIC_BAD_APPLICATION_PAYLOAD);
+ RETURN_STRING_LITERAL(QUIC_STREAM_CONNECTION_ERROR);
RETURN_STRING_LITERAL(QUIC_STREAM_PEER_GOING_AWAY);
RETURN_STRING_LITERAL(QUIC_STREAM_CANCELLED);
RETURN_STRING_LITERAL(QUIC_RST_ACKNOWLEDGEMENT);
RETURN_STRING_LITERAL(QUIC_REFUSED_STREAM);
- RETURN_STRING_LITERAL(QUIC_STREAM_LAST_ERROR);
RETURN_STRING_LITERAL(QUIC_INVALID_PROMISE_URL);
RETURN_STRING_LITERAL(QUIC_UNAUTHORIZED_PROMISE_URL);
RETURN_STRING_LITERAL(QUIC_DUPLICATE_PROMISE_URL);
@@ -29,8 +34,27 @@ const char* QuicRstStreamErrorCodeToString(QuicRstStreamErrorCode error) {
RETURN_STRING_LITERAL(QUIC_INVALID_PROMISE_METHOD);
RETURN_STRING_LITERAL(QUIC_PUSH_STREAM_TIMED_OUT);
RETURN_STRING_LITERAL(QUIC_HEADERS_TOO_LARGE);
- RETURN_STRING_LITERAL(QUIC_DATA_AFTER_CLOSE_OFFSET);
RETURN_STRING_LITERAL(QUIC_STREAM_TTL_EXPIRED);
+ RETURN_STRING_LITERAL(QUIC_DATA_AFTER_CLOSE_OFFSET);
+ RETURN_STRING_LITERAL(QUIC_STREAM_GENERAL_PROTOCOL_ERROR);
+ RETURN_STRING_LITERAL(QUIC_STREAM_INTERNAL_ERROR);
+ RETURN_STRING_LITERAL(QUIC_STREAM_STREAM_CREATION_ERROR);
+ RETURN_STRING_LITERAL(QUIC_STREAM_CLOSED_CRITICAL_STREAM);
+ RETURN_STRING_LITERAL(QUIC_STREAM_FRAME_UNEXPECTED);
+ RETURN_STRING_LITERAL(QUIC_STREAM_FRAME_ERROR);
+ RETURN_STRING_LITERAL(QUIC_STREAM_EXCESSIVE_LOAD);
+ RETURN_STRING_LITERAL(QUIC_STREAM_ID_ERROR);
+ RETURN_STRING_LITERAL(QUIC_STREAM_SETTINGS_ERROR);
+ RETURN_STRING_LITERAL(QUIC_STREAM_MISSING_SETTINGS);
+ RETURN_STRING_LITERAL(QUIC_STREAM_REQUEST_REJECTED);
+ RETURN_STRING_LITERAL(QUIC_STREAM_REQUEST_INCOMPLETE);
+ RETURN_STRING_LITERAL(QUIC_STREAM_CONNECT_ERROR);
+ RETURN_STRING_LITERAL(QUIC_STREAM_VERSION_FALLBACK);
+ RETURN_STRING_LITERAL(QUIC_STREAM_DECOMPRESSION_FAILED);
+ RETURN_STRING_LITERAL(QUIC_STREAM_ENCODER_STREAM_ERROR);
+ RETURN_STRING_LITERAL(QUIC_STREAM_DECODER_STREAM_ERROR);
+ RETURN_STRING_LITERAL(QUIC_STREAM_UNKNOWN_APPLICATION_ERROR_CODE);
+ RETURN_STRING_LITERAL(QUIC_STREAM_LAST_ERROR);
}
// Return a default value so that we return this when |error| doesn't match
// any of the QuicRstStreamErrorCodes. This can happen when the RstStream
@@ -177,6 +201,8 @@ const char* QuicErrorCodeToString(QuicErrorCode error) {
RETURN_STRING_LITERAL(QUIC_HTTP_CLOSED_CRITICAL_STREAM);
RETURN_STRING_LITERAL(QUIC_HTTP_MISSING_SETTINGS_FRAME);
RETURN_STRING_LITERAL(QUIC_HTTP_DUPLICATE_SETTING_IDENTIFIER);
+ RETURN_STRING_LITERAL(QUIC_HTTP_INVALID_MAX_PUSH_ID);
+ RETURN_STRING_LITERAL(QUIC_HTTP_STREAM_LIMIT_TOO_LOW);
RETURN_STRING_LITERAL(QUIC_HPACK_INDEX_VARINT_ERROR);
RETURN_STRING_LITERAL(QUIC_HPACK_NAME_LENGTH_VARINT_ERROR);
RETURN_STRING_LITERAL(QUIC_HPACK_VALUE_LENGTH_VARINT_ERROR);
@@ -206,5 +232,513 @@ const char* QuicErrorCodeToString(QuicErrorCode error) {
return "INVALID_ERROR_CODE";
}
+std::string QuicIetfTransportErrorCodeString(QuicIetfTransportErrorCodes c) {
+ if (static_cast<uint64_t>(c) >= 0xff00u) {
+ return quiche::QuicheStrCat("Private(", static_cast<uint64_t>(c), ")");
+ }
+ if (c >= CRYPTO_ERROR_FIRST && c <= CRYPTO_ERROR_LAST) {
+ const int tls_error = static_cast<int>(c - CRYPTO_ERROR_FIRST);
+ const char* tls_error_description = SSL_alert_desc_string_long(tls_error);
+ if (strcmp("unknown", tls_error_description) != 0) {
+ return quiche::QuicheStrCat("CRYPTO_ERROR(", tls_error_description, ")");
+ }
+ return quiche::QuicheStrCat("CRYPTO_ERROR(unknown(", tls_error, "))");
+ }
+
+ switch (c) {
+ RETURN_STRING_LITERAL(NO_IETF_QUIC_ERROR);
+ RETURN_STRING_LITERAL(INTERNAL_ERROR);
+ RETURN_STRING_LITERAL(SERVER_BUSY_ERROR);
+ RETURN_STRING_LITERAL(FLOW_CONTROL_ERROR);
+ RETURN_STRING_LITERAL(STREAM_LIMIT_ERROR);
+ RETURN_STRING_LITERAL(STREAM_STATE_ERROR);
+ RETURN_STRING_LITERAL(FINAL_SIZE_ERROR);
+ RETURN_STRING_LITERAL(FRAME_ENCODING_ERROR);
+ RETURN_STRING_LITERAL(TRANSPORT_PARAMETER_ERROR);
+ RETURN_STRING_LITERAL(CONNECTION_ID_LIMIT_ERROR);
+ RETURN_STRING_LITERAL(PROTOCOL_VIOLATION);
+ RETURN_STRING_LITERAL(INVALID_TOKEN);
+ RETURN_STRING_LITERAL(CRYPTO_BUFFER_EXCEEDED);
+ // CRYPTO_ERROR is handled in the if before this switch, these cases do not
+ // change behavior and are only here to make the compiler happy.
+ case CRYPTO_ERROR_FIRST:
+ case CRYPTO_ERROR_LAST:
+ DCHECK(false) << "Unexpected error " << static_cast<uint64_t>(c);
+ break;
+ }
+
+ return quiche::QuicheStrCat("Unknown(", static_cast<uint64_t>(c), ")");
+}
+
+std::ostream& operator<<(std::ostream& os,
+ const QuicIetfTransportErrorCodes& c) {
+ os << QuicIetfTransportErrorCodeString(c);
+ return os;
+}
+
+QuicErrorCodeToIetfMapping QuicErrorCodeToTransportErrorCode(
+ QuicErrorCode error) {
+ switch (error) {
+ case QUIC_NO_ERROR:
+ return {true, static_cast<uint64_t>(NO_IETF_QUIC_ERROR)};
+ case QUIC_INTERNAL_ERROR:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_STREAM_DATA_AFTER_TERMINATION:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_INVALID_PACKET_HEADER:
+ return {true, static_cast<uint64_t>(FRAME_ENCODING_ERROR)};
+ case QUIC_INVALID_FRAME_DATA:
+ return {true, static_cast<uint64_t>(FRAME_ENCODING_ERROR)};
+ case QUIC_MISSING_PAYLOAD:
+ return {true, static_cast<uint64_t>(FRAME_ENCODING_ERROR)};
+ case QUIC_INVALID_FEC_DATA:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_INVALID_STREAM_DATA:
+ return {true, static_cast<uint64_t>(FRAME_ENCODING_ERROR)};
+ case QUIC_OVERLAPPING_STREAM_DATA:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_UNENCRYPTED_STREAM_DATA:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_ATTEMPT_TO_SEND_UNENCRYPTED_STREAM_DATA:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_MAYBE_CORRUPTED_MEMORY:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_UNENCRYPTED_FEC_DATA:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_INVALID_RST_STREAM_DATA:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_INVALID_CONNECTION_CLOSE_DATA:
+ return {true, static_cast<uint64_t>(FRAME_ENCODING_ERROR)};
+ case QUIC_INVALID_GOAWAY_DATA:
+ return {true, static_cast<uint64_t>(FRAME_ENCODING_ERROR)};
+ case QUIC_INVALID_WINDOW_UPDATE_DATA:
+ return {true, static_cast<uint64_t>(FRAME_ENCODING_ERROR)};
+ case QUIC_INVALID_BLOCKED_DATA:
+ return {true, static_cast<uint64_t>(FRAME_ENCODING_ERROR)};
+ case QUIC_INVALID_STOP_WAITING_DATA:
+ return {true, static_cast<uint64_t>(FRAME_ENCODING_ERROR)};
+ case QUIC_INVALID_PATH_CLOSE_DATA:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_INVALID_ACK_DATA:
+ return {true, static_cast<uint64_t>(FRAME_ENCODING_ERROR)};
+ case QUIC_INVALID_MESSAGE_DATA:
+ return {true, static_cast<uint64_t>(FRAME_ENCODING_ERROR)};
+ case QUIC_INVALID_VERSION_NEGOTIATION_PACKET:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_INVALID_PUBLIC_RST_PACKET:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_DECRYPTION_FAILURE:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_ENCRYPTION_FAILURE:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_PACKET_TOO_LARGE:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_PEER_GOING_AWAY:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_INVALID_STREAM_ID:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_INVALID_PRIORITY:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_TOO_MANY_OPEN_STREAMS:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_TOO_MANY_AVAILABLE_STREAMS:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_PUBLIC_RESET:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_INVALID_VERSION:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_INVALID_HEADER_ID:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_INVALID_NEGOTIATED_VALUE:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_DECOMPRESSION_FAILURE:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_NETWORK_IDLE_TIMEOUT:
+ return {true, static_cast<uint64_t>(NO_IETF_QUIC_ERROR)};
+ case QUIC_HANDSHAKE_TIMEOUT:
+ return {true, static_cast<uint64_t>(NO_IETF_QUIC_ERROR)};
+ case QUIC_ERROR_MIGRATING_ADDRESS:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_ERROR_MIGRATING_PORT:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_PACKET_WRITE_ERROR:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_PACKET_READ_ERROR:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_EMPTY_STREAM_FRAME_NO_FIN:
+ return {true, static_cast<uint64_t>(FRAME_ENCODING_ERROR)};
+ case QUIC_INVALID_HEADERS_STREAM_DATA:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_HEADERS_STREAM_DATA_DECOMPRESS_FAILURE:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA:
+ return {true, static_cast<uint64_t>(FLOW_CONTROL_ERROR)};
+ case QUIC_FLOW_CONTROL_SENT_TOO_MUCH_DATA:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_FLOW_CONTROL_INVALID_WINDOW:
+ return {true, static_cast<uint64_t>(FLOW_CONTROL_ERROR)};
+ case QUIC_CONNECTION_IP_POOLED:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_TOO_MANY_OUTSTANDING_SENT_PACKETS:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_TOO_MANY_OUTSTANDING_RECEIVED_PACKETS:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_CONNECTION_CANCELLED:
+ return {true, static_cast<uint64_t>(NO_IETF_QUIC_ERROR)};
+ case QUIC_BAD_PACKET_LOSS_RATE:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_PUBLIC_RESETS_POST_HANDSHAKE:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_FAILED_TO_SERIALIZE_PACKET:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_TOO_MANY_RTOS:
+ return {true, static_cast<uint64_t>(NO_IETF_QUIC_ERROR)};
+ case QUIC_HANDSHAKE_FAILED:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_CRYPTO_TAGS_OUT_OF_ORDER:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_CRYPTO_TOO_MANY_ENTRIES:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_CRYPTO_INVALID_VALUE_LENGTH:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_INVALID_CRYPTO_MESSAGE_TYPE:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_INVALID_CHANNEL_ID_SIGNATURE:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_CRYPTO_MESSAGE_PARAMETER_NO_OVERLAP:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_CRYPTO_MESSAGE_INDEX_NOT_FOUND:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_UNSUPPORTED_PROOF_DEMAND:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_CRYPTO_INTERNAL_ERROR:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_CRYPTO_VERSION_NOT_SUPPORTED:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_CRYPTO_NO_SUPPORT:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_CRYPTO_TOO_MANY_REJECTS:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_PROOF_INVALID:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_CRYPTO_DUPLICATE_TAG:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_CRYPTO_SERVER_CONFIG_EXPIRED:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_CRYPTO_MESSAGE_WHILE_VALIDATING_CLIENT_HELLO:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_CRYPTO_UPDATE_BEFORE_HANDSHAKE_COMPLETE:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_CRYPTO_CHLO_TOO_LARGE:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_VERSION_NEGOTIATION_MISMATCH:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_BAD_MULTIPATH_FLAG:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_MULTIPATH_PATH_DOES_NOT_EXIST:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_MULTIPATH_PATH_NOT_ACTIVE:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_IP_ADDRESS_CHANGED:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_CONNECTION_MIGRATION_NO_MIGRATABLE_STREAMS:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_CONNECTION_MIGRATION_TOO_MANY_CHANGES:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_CONNECTION_MIGRATION_NO_NEW_NETWORK:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_CONNECTION_MIGRATION_NON_MIGRATABLE_STREAM:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_CONNECTION_MIGRATION_DISABLED_BY_CONFIG:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_CONNECTION_MIGRATION_INTERNAL_ERROR:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_CONNECTION_MIGRATION_HANDSHAKE_UNCONFIRMED:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_TOO_MANY_STREAM_DATA_INTERVALS:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_STREAM_SEQUENCER_INVALID_STATE:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_TOO_MANY_SESSIONS_ON_SERVER:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_STREAM_LENGTH_OVERFLOW:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_INVALID_MAX_DATA_FRAME_DATA:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_INVALID_MAX_STREAM_DATA_FRAME_DATA:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_MAX_STREAMS_DATA:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_STREAMS_BLOCKED_DATA:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_INVALID_STREAM_BLOCKED_DATA:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_INVALID_NEW_CONNECTION_ID_DATA:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_INVALID_STOP_SENDING_FRAME_DATA:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_INVALID_PATH_CHALLENGE_DATA:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_INVALID_PATH_RESPONSE_DATA:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case IETF_QUIC_PROTOCOL_VIOLATION:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_INVALID_NEW_TOKEN:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_DATA_RECEIVED_ON_WRITE_UNIDIRECTIONAL_STREAM:
+ return {true, static_cast<uint64_t>(STREAM_STATE_ERROR)};
+ case QUIC_TRY_TO_WRITE_DATA_ON_READ_UNIDIRECTIONAL_STREAM:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_INVALID_RETIRE_CONNECTION_ID_DATA:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_STREAMS_BLOCKED_ERROR:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_MAX_STREAMS_ERROR:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_HTTP_DECODER_ERROR:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_STALE_CONNECTION_CANCELLED:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_IETF_GQUIC_ERROR_MISSING:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_WINDOW_UPDATE_RECEIVED_ON_READ_UNIDIRECTIONAL_STREAM:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_TOO_MANY_BUFFERED_CONTROL_FRAMES:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_TRANSPORT_INVALID_CLIENT_INDICATION:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_QPACK_DECOMPRESSION_FAILED:
+ return {false, static_cast<uint64_t>(
+ QuicHttpQpackErrorCode::DECOMPRESSION_FAILED)};
+ case QUIC_QPACK_ENCODER_STREAM_ERROR:
+ return {false, static_cast<uint64_t>(
+ QuicHttpQpackErrorCode::ENCODER_STREAM_ERROR)};
+ case QUIC_QPACK_DECODER_STREAM_ERROR:
+ return {false, static_cast<uint64_t>(
+ QuicHttpQpackErrorCode::DECODER_STREAM_ERROR)};
+ case QUIC_STREAM_DATA_BEYOND_CLOSE_OFFSET:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_STREAM_MULTIPLE_OFFSET:
+ return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)};
+ case QUIC_HTTP_FRAME_TOO_LARGE:
+ return {false, static_cast<uint64_t>(QuicHttp3ErrorCode::EXCESSIVE_LOAD)};
+ case QUIC_HTTP_FRAME_ERROR:
+ return {false, static_cast<uint64_t>(QuicHttp3ErrorCode::FRAME_ERROR)};
+ case QUIC_HTTP_FRAME_UNEXPECTED_ON_SPDY_STREAM:
+ return {false,
+ static_cast<uint64_t>(QuicHttp3ErrorCode::FRAME_UNEXPECTED)};
+ case QUIC_HTTP_FRAME_UNEXPECTED_ON_CONTROL_STREAM:
+ return {false,
+ static_cast<uint64_t>(QuicHttp3ErrorCode::FRAME_UNEXPECTED)};
+ case QUIC_HTTP_INVALID_FRAME_SEQUENCE_ON_SPDY_STREAM:
+ return {false,
+ static_cast<uint64_t>(QuicHttp3ErrorCode::FRAME_UNEXPECTED)};
+ case QUIC_HTTP_INVALID_FRAME_SEQUENCE_ON_CONTROL_STREAM:
+ return {false,
+ static_cast<uint64_t>(QuicHttp3ErrorCode::FRAME_UNEXPECTED)};
+ case QUIC_HTTP_DUPLICATE_UNIDIRECTIONAL_STREAM:
+ return {false,
+ static_cast<uint64_t>(QuicHttp3ErrorCode::STREAM_CREATION_ERROR)};
+ case QUIC_HTTP_SERVER_INITIATED_BIDIRECTIONAL_STREAM:
+ return {false,
+ static_cast<uint64_t>(QuicHttp3ErrorCode::STREAM_CREATION_ERROR)};
+ case QUIC_HTTP_STREAM_WRONG_DIRECTION:
+ return {true, static_cast<uint64_t>(STREAM_STATE_ERROR)};
+ case QUIC_HTTP_CLOSED_CRITICAL_STREAM:
+ return {false, static_cast<uint64_t>(
+ QuicHttp3ErrorCode::CLOSED_CRITICAL_STREAM)};
+ case QUIC_HTTP_MISSING_SETTINGS_FRAME:
+ return {false,
+ static_cast<uint64_t>(QuicHttp3ErrorCode::MISSING_SETTINGS)};
+ case QUIC_HTTP_DUPLICATE_SETTING_IDENTIFIER:
+ return {false, static_cast<uint64_t>(QuicHttp3ErrorCode::SETTINGS_ERROR)};
+ case QUIC_HTTP_INVALID_MAX_PUSH_ID:
+ return {false, static_cast<uint64_t>(QuicHttp3ErrorCode::ID_ERROR)};
+ case QUIC_HTTP_STREAM_LIMIT_TOO_LOW:
+ return {false, static_cast<uint64_t>(
+ QuicHttp3ErrorCode::GENERAL_PROTOCOL_ERROR)};
+ case QUIC_HPACK_INDEX_VARINT_ERROR:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_HPACK_NAME_LENGTH_VARINT_ERROR:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_HPACK_VALUE_LENGTH_VARINT_ERROR:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_HPACK_NAME_TOO_LONG:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_HPACK_VALUE_TOO_LONG:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_HPACK_NAME_HUFFMAN_ERROR:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_HPACK_VALUE_HUFFMAN_ERROR:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_HPACK_MISSING_DYNAMIC_TABLE_SIZE_UPDATE:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_HPACK_INVALID_INDEX:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_HPACK_INVALID_NAME_INDEX:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_HPACK_DYNAMIC_TABLE_SIZE_UPDATE_NOT_ALLOWED:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_HPACK_INITIAL_TABLE_SIZE_UPDATE_IS_ABOVE_LOW_WATER_MARK:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_HPACK_TABLE_SIZE_UPDATE_IS_ABOVE_ACKNOWLEDGED_SETTING:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_HPACK_TRUNCATED_BLOCK:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_HPACK_FRAGMENT_TOO_LONG:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_HPACK_COMPRESSED_HEADER_SIZE_EXCEEDS_LIMIT:
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_LAST_ERROR:
+ return {false, static_cast<uint64_t>(QUIC_LAST_ERROR)};
+ }
+ // This function should not be called with unknown error code.
+ return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+}
+
+// Convert a QuicRstStreamErrorCode to an application error code to be used in
+// an IETF QUIC RESET_STREAM frame
+uint64_t RstStreamErrorCodeToIetfResetStreamErrorCode(
+ QuicRstStreamErrorCode rst_stream_error_code) {
+ switch (rst_stream_error_code) {
+ case QUIC_STREAM_NO_ERROR:
+ return static_cast<uint64_t>(QuicHttp3ErrorCode::HTTP3_NO_ERROR);
+ case QUIC_ERROR_PROCESSING_STREAM:
+ return static_cast<uint64_t>(QuicHttp3ErrorCode::GENERAL_PROTOCOL_ERROR);
+ case QUIC_MULTIPLE_TERMINATION_OFFSETS:
+ return static_cast<uint64_t>(QuicHttp3ErrorCode::GENERAL_PROTOCOL_ERROR);
+ case QUIC_BAD_APPLICATION_PAYLOAD:
+ return static_cast<uint64_t>(QuicHttp3ErrorCode::GENERAL_PROTOCOL_ERROR);
+ case QUIC_STREAM_CONNECTION_ERROR:
+ return static_cast<uint64_t>(QuicHttp3ErrorCode::INTERNAL_ERROR);
+ case QUIC_STREAM_PEER_GOING_AWAY:
+ return static_cast<uint64_t>(QuicHttp3ErrorCode::GENERAL_PROTOCOL_ERROR);
+ case QUIC_STREAM_CANCELLED:
+ return static_cast<uint64_t>(QuicHttp3ErrorCode::REQUEST_CANCELLED);
+ case QUIC_RST_ACKNOWLEDGEMENT:
+ return static_cast<uint64_t>(QuicHttp3ErrorCode::HTTP3_NO_ERROR);
+ case QUIC_REFUSED_STREAM:
+ return static_cast<uint64_t>(QuicHttp3ErrorCode::ID_ERROR);
+ case QUIC_INVALID_PROMISE_URL:
+ return static_cast<uint64_t>(QuicHttp3ErrorCode::STREAM_CREATION_ERROR);
+ case QUIC_UNAUTHORIZED_PROMISE_URL:
+ return static_cast<uint64_t>(QuicHttp3ErrorCode::STREAM_CREATION_ERROR);
+ case QUIC_DUPLICATE_PROMISE_URL:
+ return static_cast<uint64_t>(QuicHttp3ErrorCode::STREAM_CREATION_ERROR);
+ case QUIC_PROMISE_VARY_MISMATCH:
+ return static_cast<uint64_t>(QuicHttp3ErrorCode::REQUEST_CANCELLED);
+ case QUIC_INVALID_PROMISE_METHOD:
+ return static_cast<uint64_t>(QuicHttp3ErrorCode::STREAM_CREATION_ERROR);
+ case QUIC_PUSH_STREAM_TIMED_OUT:
+ return static_cast<uint64_t>(QuicHttp3ErrorCode::REQUEST_CANCELLED);
+ case QUIC_HEADERS_TOO_LARGE:
+ return static_cast<uint64_t>(QuicHttp3ErrorCode::EXCESSIVE_LOAD);
+ case QUIC_STREAM_TTL_EXPIRED:
+ return static_cast<uint64_t>(QuicHttp3ErrorCode::REQUEST_CANCELLED);
+ case QUIC_DATA_AFTER_CLOSE_OFFSET:
+ return static_cast<uint64_t>(QuicHttp3ErrorCode::GENERAL_PROTOCOL_ERROR);
+ case QUIC_STREAM_GENERAL_PROTOCOL_ERROR:
+ return static_cast<uint64_t>(QuicHttp3ErrorCode::GENERAL_PROTOCOL_ERROR);
+ case QUIC_STREAM_INTERNAL_ERROR:
+ return static_cast<uint64_t>(QuicHttp3ErrorCode::INTERNAL_ERROR);
+ case QUIC_STREAM_STREAM_CREATION_ERROR:
+ return static_cast<uint64_t>(QuicHttp3ErrorCode::STREAM_CREATION_ERROR);
+ case QUIC_STREAM_CLOSED_CRITICAL_STREAM:
+ return static_cast<uint64_t>(QuicHttp3ErrorCode::CLOSED_CRITICAL_STREAM);
+ case QUIC_STREAM_FRAME_UNEXPECTED:
+ return static_cast<uint64_t>(QuicHttp3ErrorCode::FRAME_UNEXPECTED);
+ case QUIC_STREAM_FRAME_ERROR:
+ return static_cast<uint64_t>(QuicHttp3ErrorCode::FRAME_ERROR);
+ case QUIC_STREAM_EXCESSIVE_LOAD:
+ return static_cast<uint64_t>(QuicHttp3ErrorCode::EXCESSIVE_LOAD);
+ case QUIC_STREAM_ID_ERROR:
+ return static_cast<uint64_t>(QuicHttp3ErrorCode::ID_ERROR);
+ case QUIC_STREAM_SETTINGS_ERROR:
+ return static_cast<uint64_t>(QuicHttp3ErrorCode::SETTINGS_ERROR);
+ case QUIC_STREAM_MISSING_SETTINGS:
+ return static_cast<uint64_t>(QuicHttp3ErrorCode::MISSING_SETTINGS);
+ case QUIC_STREAM_REQUEST_REJECTED:
+ return static_cast<uint64_t>(QuicHttp3ErrorCode::REQUEST_REJECTED);
+ case QUIC_STREAM_REQUEST_INCOMPLETE:
+ return static_cast<uint64_t>(QuicHttp3ErrorCode::REQUEST_INCOMPLETE);
+ case QUIC_STREAM_CONNECT_ERROR:
+ return static_cast<uint64_t>(QuicHttp3ErrorCode::CONNECT_ERROR);
+ case QUIC_STREAM_VERSION_FALLBACK:
+ return static_cast<uint64_t>(QuicHttp3ErrorCode::VERSION_FALLBACK);
+ case QUIC_STREAM_DECOMPRESSION_FAILED:
+ return static_cast<uint64_t>(
+ QuicHttpQpackErrorCode::DECOMPRESSION_FAILED);
+ case QUIC_STREAM_ENCODER_STREAM_ERROR:
+ return static_cast<uint64_t>(
+ QuicHttpQpackErrorCode::ENCODER_STREAM_ERROR);
+ case QUIC_STREAM_DECODER_STREAM_ERROR:
+ return static_cast<uint64_t>(
+ QuicHttpQpackErrorCode::DECODER_STREAM_ERROR);
+ case QUIC_STREAM_UNKNOWN_APPLICATION_ERROR_CODE:
+ return static_cast<uint64_t>(QuicHttp3ErrorCode::INTERNAL_ERROR);
+ case QUIC_STREAM_LAST_ERROR:
+ return static_cast<uint64_t>(QuicHttp3ErrorCode::INTERNAL_ERROR);
+ }
+ return static_cast<uint64_t>(QuicHttp3ErrorCode::INTERNAL_ERROR);
+}
+
+// Convert the application error code of an IETF QUIC RESET_STREAM frame
+// to QuicRstStreamErrorCode.
+QuicRstStreamErrorCode IetfResetStreamErrorCodeToRstStreamErrorCode(
+ uint64_t ietf_error_code) {
+ switch (ietf_error_code) {
+ case static_cast<uint64_t>(QuicHttp3ErrorCode::HTTP3_NO_ERROR):
+ return QUIC_STREAM_NO_ERROR;
+ case static_cast<uint64_t>(QuicHttp3ErrorCode::GENERAL_PROTOCOL_ERROR):
+ return QUIC_STREAM_GENERAL_PROTOCOL_ERROR;
+ case static_cast<uint64_t>(QuicHttp3ErrorCode::INTERNAL_ERROR):
+ return QUIC_STREAM_INTERNAL_ERROR;
+ case static_cast<uint64_t>(QuicHttp3ErrorCode::STREAM_CREATION_ERROR):
+ return QUIC_STREAM_STREAM_CREATION_ERROR;
+ case static_cast<uint64_t>(QuicHttp3ErrorCode::CLOSED_CRITICAL_STREAM):
+ return QUIC_STREAM_CLOSED_CRITICAL_STREAM;
+ case static_cast<uint64_t>(QuicHttp3ErrorCode::FRAME_UNEXPECTED):
+ return QUIC_STREAM_FRAME_UNEXPECTED;
+ case static_cast<uint64_t>(QuicHttp3ErrorCode::FRAME_ERROR):
+ return QUIC_STREAM_FRAME_ERROR;
+ case static_cast<uint64_t>(QuicHttp3ErrorCode::EXCESSIVE_LOAD):
+ return QUIC_STREAM_EXCESSIVE_LOAD;
+ case static_cast<uint64_t>(QuicHttp3ErrorCode::ID_ERROR):
+ return QUIC_STREAM_ID_ERROR;
+ case static_cast<uint64_t>(QuicHttp3ErrorCode::SETTINGS_ERROR):
+ return QUIC_STREAM_SETTINGS_ERROR;
+ case static_cast<uint64_t>(QuicHttp3ErrorCode::MISSING_SETTINGS):
+ return QUIC_STREAM_MISSING_SETTINGS;
+ case static_cast<uint64_t>(QuicHttp3ErrorCode::REQUEST_REJECTED):
+ return QUIC_STREAM_REQUEST_REJECTED;
+ case static_cast<uint64_t>(QuicHttp3ErrorCode::REQUEST_CANCELLED):
+ return QUIC_STREAM_CANCELLED;
+ case static_cast<uint64_t>(QuicHttp3ErrorCode::REQUEST_INCOMPLETE):
+ return QUIC_STREAM_REQUEST_INCOMPLETE;
+ case static_cast<uint64_t>(QuicHttp3ErrorCode::CONNECT_ERROR):
+ return QUIC_STREAM_CONNECT_ERROR;
+ case static_cast<uint64_t>(QuicHttp3ErrorCode::VERSION_FALLBACK):
+ return QUIC_STREAM_VERSION_FALLBACK;
+ case static_cast<uint64_t>(QuicHttpQpackErrorCode::DECOMPRESSION_FAILED):
+ return QUIC_STREAM_DECOMPRESSION_FAILED;
+ case static_cast<uint64_t>(QuicHttpQpackErrorCode::ENCODER_STREAM_ERROR):
+ return QUIC_STREAM_ENCODER_STREAM_ERROR;
+ case static_cast<uint64_t>(QuicHttpQpackErrorCode::DECODER_STREAM_ERROR):
+ return QUIC_STREAM_DECODER_STREAM_ERROR;
+ }
+ return QUIC_STREAM_UNKNOWN_APPLICATION_ERROR_CODE;
+}
+
#undef RETURN_STRING_LITERAL // undef for jumbo builds
+
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.h b/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.h
index 0548e9b0fe0..f057fea1028 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
@@ -56,6 +56,53 @@ enum QuicRstStreamErrorCode {
QUIC_STREAM_TTL_EXPIRED,
// The stream received data that goes beyond its close offset.
QUIC_DATA_AFTER_CLOSE_OFFSET,
+ // Peer violated protocol requirements in a way which does not match a more
+ // specific error code, or endpoint declines to use the more specific error
+ // code.
+ QUIC_STREAM_GENERAL_PROTOCOL_ERROR,
+ // An internal error has occurred.
+ QUIC_STREAM_INTERNAL_ERROR,
+ // Peer created a stream that will not be accepted.
+ QUIC_STREAM_STREAM_CREATION_ERROR,
+ // A stream required by the connection was closed or reset.
+ QUIC_STREAM_CLOSED_CRITICAL_STREAM,
+ // A frame was received which was not permitted in the current state or on the
+ // current stream.
+ QUIC_STREAM_FRAME_UNEXPECTED,
+ // A frame that fails to satisfy layout requirements or with an invalid size
+ // was received.
+ QUIC_STREAM_FRAME_ERROR,
+ // Peer exhibits a behavior that might be generating excessive load.
+ QUIC_STREAM_EXCESSIVE_LOAD,
+ // A Stream ID or Push ID was used incorrectly, such as exceeding a limit,
+ // reducing a limit, or being reused.
+ QUIC_STREAM_ID_ERROR,
+ // Error in the payload of a SETTINGS frame.
+ QUIC_STREAM_SETTINGS_ERROR,
+ // No SETTINGS frame was received at the beginning of the control stream.
+ QUIC_STREAM_MISSING_SETTINGS,
+ // A server rejected a request without performing any application processing.
+ QUIC_STREAM_REQUEST_REJECTED,
+ // The client's stream terminated without containing a fully-formed request.
+ QUIC_STREAM_REQUEST_INCOMPLETE,
+ // The connection established in response to a CONNECT request was reset or
+ // abnormally closed.
+ QUIC_STREAM_CONNECT_ERROR,
+ // The requested operation cannot be served over HTTP/3.
+ // The peer should retry over HTTP/1.1.
+ QUIC_STREAM_VERSION_FALLBACK,
+ // The QPACK decoder failed to interpret a header block and is not able to
+ // continue decoding that header block.
+ QUIC_STREAM_DECOMPRESSION_FAILED,
+ // The QPACK decoder failed to interpret an encoder instruction received on
+ // the encoder stream.
+ QUIC_STREAM_ENCODER_STREAM_ERROR,
+ // The QPACK encoder failed to interpret a decoder instruction received on the
+ // decoder stream.
+ QUIC_STREAM_DECODER_STREAM_ERROR,
+ // IETF RESET_FRAME application error code not matching any HTTP/3 or QPACK
+ // error codes.
+ QUIC_STREAM_UNKNOWN_APPLICATION_ERROR_CODE,
// No error. Used as bound while iterating.
QUIC_STREAM_LAST_ERROR,
};
@@ -379,6 +426,11 @@ enum QuicErrorCode {
QUIC_HTTP_MISSING_SETTINGS_FRAME = 157,
// The received SETTINGS frame contains duplicate setting identifiers.
QUIC_HTTP_DUPLICATE_SETTING_IDENTIFIER = 158,
+ // MAX_PUSH_ID frame received with push ID value smaller than a previously
+ // received value.
+ QUIC_HTTP_INVALID_MAX_PUSH_ID = 159,
+ // Received unidirectional stream limit is lower than required by HTTP/3.
+ QUIC_HTTP_STREAM_LIMIT_TOO_LOW = 160,
// HPACK header block decoding errors.
// Index varint beyond implementation limit.
@@ -415,7 +467,7 @@ enum QuicErrorCode {
QUIC_HPACK_COMPRESSED_HEADER_SIZE_EXCEEDS_LIMIT = 150,
// No error. Used as bound while iterating.
- QUIC_LAST_ERROR = 159,
+ QUIC_LAST_ERROR = 161,
};
// 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
@@ -431,35 +483,85 @@ QUIC_EXPORT_PRIVATE const char* QuicRstStreamErrorCodeToString(
// Returns the name of the QuicErrorCode as a char*
QUIC_EXPORT_PRIVATE const char* QuicErrorCodeToString(QuicErrorCode error);
+// Wire values for QUIC transport errors.
+// https://quicwg.org/base-drafts/draft-ietf-quic-transport.html#name-transport-error-codes
+enum QuicIetfTransportErrorCodes : uint64_t {
+ NO_IETF_QUIC_ERROR = 0x0,
+ INTERNAL_ERROR = 0x1,
+ SERVER_BUSY_ERROR = 0x2,
+ FLOW_CONTROL_ERROR = 0x3,
+ STREAM_LIMIT_ERROR = 0x4,
+ STREAM_STATE_ERROR = 0x5,
+ FINAL_SIZE_ERROR = 0x6,
+ FRAME_ENCODING_ERROR = 0x7,
+ TRANSPORT_PARAMETER_ERROR = 0x8,
+ CONNECTION_ID_LIMIT_ERROR = 0x9,
+ PROTOCOL_VIOLATION = 0xA,
+ INVALID_TOKEN = 0xB,
+ CRYPTO_BUFFER_EXCEEDED = 0xD,
+ CRYPTO_ERROR_FIRST = 0x100,
+ CRYPTO_ERROR_LAST = 0x1FF,
+};
+
+QUIC_EXPORT_PRIVATE std::string QuicIetfTransportErrorCodeString(
+ QuicIetfTransportErrorCodes c);
+
+QUIC_EXPORT_PRIVATE std::ostream& operator<<(
+ std::ostream& os,
+ const QuicIetfTransportErrorCodes& c);
+
+// A transport error code (if is_transport_close is true) or application error
+// code (if is_transport_close is false) to be used in CONNECTION_CLOSE frames.
+struct QUIC_EXPORT_PRIVATE QuicErrorCodeToIetfMapping {
+ bool is_transport_close;
+ uint64_t error_code;
+};
+
+// Convert QuicErrorCode to transport or application IETF error code
+// to be used in CONNECTION_CLOSE frames.
+QUIC_EXPORT_PRIVATE QuicErrorCodeToIetfMapping
+QuicErrorCodeToTransportErrorCode(QuicErrorCode error);
+
// Wire values for HTTP/3 errors.
// https://quicwg.org/base-drafts/draft-ietf-quic-http.html#http-error-codes
enum class QuicHttp3ErrorCode {
- IETF_QUIC_HTTP3_NO_ERROR = 0x100,
- IETF_QUIC_HTTP3_GENERAL_PROTOCOL_ERROR = 0x101,
- IETF_QUIC_HTTP3_INTERNAL_ERROR = 0x102,
- IETF_QUIC_HTTP3_STREAM_CREATION_ERROR = 0x103,
- IETF_QUIC_HTTP3_CLOSED_CRITICAL_STREAM = 0x104,
- IETF_QUIC_HTTP3_FRAME_UNEXPECTED = 0x105,
- IETF_QUIC_HTTP3_FRAME_ERROR = 0x106,
- IETF_QUIC_HTTP3_EXCESSIVE_LOAD = 0x107,
- IETF_QUIC_HTTP3_ID_ERROR = 0x108,
- IETF_QUIC_HTTP3_SETTINGS_ERROR = 0x109,
- IETF_QUIC_HTTP3_MISSING_SETTINGS = 0x10A,
- IETF_QUIC_HTTP3_REQUEST_REJECTED = 0x10B,
- IETF_QUIC_HTTP3_REQUEST_CANCELLED = 0x10C,
- IETF_QUIC_HTTP3_REQUEST_INCOMPLETE = 0x10D,
- IETF_QUIC_HTTP3_CONNECT_ERROR = 0x10F,
- IETF_QUIC_HTTP3_VERSION_FALLBACK = 0x110,
+ // NO_ERROR is defined as a C preprocessor macro on Windows.
+ HTTP3_NO_ERROR = 0x100,
+ GENERAL_PROTOCOL_ERROR = 0x101,
+ INTERNAL_ERROR = 0x102,
+ STREAM_CREATION_ERROR = 0x103,
+ CLOSED_CRITICAL_STREAM = 0x104,
+ FRAME_UNEXPECTED = 0x105,
+ FRAME_ERROR = 0x106,
+ EXCESSIVE_LOAD = 0x107,
+ ID_ERROR = 0x108,
+ SETTINGS_ERROR = 0x109,
+ MISSING_SETTINGS = 0x10A,
+ REQUEST_REJECTED = 0x10B,
+ REQUEST_CANCELLED = 0x10C,
+ REQUEST_INCOMPLETE = 0x10D,
+ CONNECT_ERROR = 0x10F,
+ VERSION_FALLBACK = 0x110,
};
// 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
+enum class QuicHttpQpackErrorCode {
+ DECOMPRESSION_FAILED = 0x200,
+ ENCODER_STREAM_ERROR = 0x201,
+ DECODER_STREAM_ERROR = 0x202
};
+// Convert a QuicRstStreamErrorCode to an application error code to be used in
+// an IETF QUIC RESET_STREAM frame
+uint64_t RstStreamErrorCodeToIetfResetStreamErrorCode(
+ QuicRstStreamErrorCode rst_stream_error_code);
+
+// Convert the application error code of an IETF QUIC RESET_STREAM frame
+// to QuicRstStreamErrorCode.
+QuicRstStreamErrorCode IetfResetStreamErrorCodeToRstStreamErrorCode(
+ uint64_t ietf_error_code);
+
QUIC_EXPORT_PRIVATE inline std::string HistogramEnumString(
QuicErrorCode enum_value) {
return QuicErrorCodeToString(enum_value);
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_error_codes_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_error_codes_test.cc
index f9928bd2b39..e57a3e57cd0 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_error_codes_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_error_codes_test.cc
@@ -4,6 +4,9 @@
#include "net/third_party/quiche/src/quic/core/quic_error_codes.h"
+#include <cstdint>
+
+#include "third_party/boringssl/src/include/openssl/ssl.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
namespace quic {
@@ -21,6 +24,76 @@ TEST_F(QuicErrorCodesTest, QuicErrorCodeToString) {
EXPECT_STREQ("QUIC_NO_ERROR", QuicErrorCodeToString(QUIC_NO_ERROR));
}
+TEST_F(QuicErrorCodesTest, QuicIetfTransportErrorCodeString) {
+ EXPECT_EQ("Private(65280)",
+ QuicIetfTransportErrorCodeString(
+ static_cast<quic::QuicIetfTransportErrorCodes>(0xff00u)));
+
+ EXPECT_EQ("CRYPTO_ERROR(missing extension)",
+ QuicIetfTransportErrorCodeString(
+ static_cast<quic::QuicIetfTransportErrorCodes>(
+ CRYPTO_ERROR_FIRST + SSL_AD_MISSING_EXTENSION)));
+
+ EXPECT_EQ("NO_IETF_QUIC_ERROR",
+ QuicIetfTransportErrorCodeString(NO_IETF_QUIC_ERROR));
+ EXPECT_EQ("INTERNAL_ERROR", QuicIetfTransportErrorCodeString(INTERNAL_ERROR));
+ EXPECT_EQ("SERVER_BUSY_ERROR",
+ QuicIetfTransportErrorCodeString(SERVER_BUSY_ERROR));
+ EXPECT_EQ("FLOW_CONTROL_ERROR",
+ QuicIetfTransportErrorCodeString(FLOW_CONTROL_ERROR));
+ EXPECT_EQ("STREAM_LIMIT_ERROR",
+ QuicIetfTransportErrorCodeString(STREAM_LIMIT_ERROR));
+ EXPECT_EQ("STREAM_STATE_ERROR",
+ QuicIetfTransportErrorCodeString(STREAM_STATE_ERROR));
+ EXPECT_EQ("FINAL_SIZE_ERROR",
+ QuicIetfTransportErrorCodeString(FINAL_SIZE_ERROR));
+ EXPECT_EQ("FRAME_ENCODING_ERROR",
+ QuicIetfTransportErrorCodeString(FRAME_ENCODING_ERROR));
+ EXPECT_EQ("TRANSPORT_PARAMETER_ERROR",
+ QuicIetfTransportErrorCodeString(TRANSPORT_PARAMETER_ERROR));
+ EXPECT_EQ("CONNECTION_ID_LIMIT_ERROR",
+ QuicIetfTransportErrorCodeString(CONNECTION_ID_LIMIT_ERROR));
+ EXPECT_EQ("PROTOCOL_VIOLATION",
+ QuicIetfTransportErrorCodeString(PROTOCOL_VIOLATION));
+ EXPECT_EQ("INVALID_TOKEN", QuicIetfTransportErrorCodeString(INVALID_TOKEN));
+ EXPECT_EQ("CRYPTO_BUFFER_EXCEEDED",
+ QuicIetfTransportErrorCodeString(CRYPTO_BUFFER_EXCEEDED));
+
+ EXPECT_EQ("Unknown(1024)",
+ QuicIetfTransportErrorCodeString(
+ static_cast<quic::QuicIetfTransportErrorCodes>(0x400)));
+}
+
+TEST_F(QuicErrorCodesTest, QuicErrorCodeToTransportErrorCode) {
+ for (int internal_error_code = 0; internal_error_code < QUIC_LAST_ERROR;
+ ++internal_error_code) {
+ std::string internal_error_code_string =
+ QuicErrorCodeToString(static_cast<QuicErrorCode>(internal_error_code));
+ if (internal_error_code_string == "INVALID_ERROR_CODE") {
+ // Not a valid QuicErrorCode.
+ continue;
+ }
+ QuicErrorCodeToIetfMapping ietf_error_code =
+ QuicErrorCodeToTransportErrorCode(
+ static_cast<QuicErrorCode>(internal_error_code));
+ if (ietf_error_code.is_transport_close) {
+ QuicIetfTransportErrorCodes transport_error_code =
+ static_cast<QuicIetfTransportErrorCodes>(ietf_error_code.error_code);
+ bool is_valid_transport_error_code = transport_error_code <= 0x0d;
+ EXPECT_TRUE(is_valid_transport_error_code) << internal_error_code_string;
+ } else {
+ // Non-transport errors are application errors, either HTTP/3 or QPACK.
+ uint64_t application_error_code = ietf_error_code.error_code;
+ bool is_valid_http3_error_code =
+ application_error_code >= 0x100 && application_error_code <= 0x110;
+ bool is_valid_qpack_error_code =
+ application_error_code >= 0x200 && application_error_code <= 0x202;
+ EXPECT_TRUE(is_valid_http3_error_code || is_valid_qpack_error_code)
+ << internal_error_code_string;
+ }
+ }
+}
+
} // namespace
} // namespace test
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_flow_controller.h b/chromium/net/third_party/quiche/src/quic/core/quic_flow_controller.h
index e627c8c4d31..29c3c02d1a3 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_flow_controller.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_flow_controller.h
@@ -91,6 +91,8 @@ class QUIC_EXPORT_PRIVATE QuicFlowController
QuicByteCount bytes_consumed() const { return bytes_consumed_; }
+ QuicStreamOffset send_window_offset() const { return send_window_offset_; }
+
QuicStreamOffset highest_received_byte_offset() const {
return highest_received_byte_offset_;
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_flow_controller_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_flow_controller_test.cc
index 8f4cdf7849e..29a9ba37649 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_flow_controller_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_flow_controller_test.cc
@@ -31,7 +31,7 @@ class MockFlowController : public QuicFlowControllerInterface {
MockFlowController& operator=(const MockFlowController&) = delete;
~MockFlowController() override {}
- MOCK_METHOD1(EnsureWindowAtLeast, void(QuicByteCount));
+ MOCK_METHOD(void, EnsureWindowAtLeast, (QuicByteCount), (override));
};
class QuicFlowControllerTest : public QuicTest {
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 f90019176aa..b05b4576d8e 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
@@ -466,11 +466,9 @@ size_t QuicFramer::GetMessageFrameSize(QuicTransportVersion version,
}
// static
-size_t QuicFramer::GetMinAckFrameSize(
- QuicTransportVersion version,
- const QuicAckFrame& ack_frame,
- uint32_t local_ack_delay_exponent,
- QuicPacketNumberLength largest_observed_length) {
+size_t QuicFramer::GetMinAckFrameSize(QuicTransportVersion version,
+ const QuicAckFrame& ack_frame,
+ uint32_t local_ack_delay_exponent) {
if (VersionHasIetfQuicFrames(version)) {
// The minimal ack frame consists of the following fields: Largest
// Acknowledged, ACK Delay, 0 ACK Block Count, First ACK Block and ECN
@@ -498,13 +496,9 @@ size_t QuicFramer::GetMinAckFrameSize(
}
return min_size;
}
- if (GetQuicReloadableFlag(quic_use_ack_frame_to_get_min_size)) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_use_ack_frame_to_get_min_size);
- largest_observed_length = GetMinPacketNumberLength(LargestAcked(ack_frame));
- }
- size_t min_size = kQuicFrameTypeSize + largest_observed_length +
- kQuicDeltaTimeLargestObservedSize;
- return min_size + kQuicNumTimestampsSize;
+ return kQuicFrameTypeSize +
+ GetMinPacketNumberLength(LargestAcked(ack_frame)) +
+ kQuicDeltaTimeLargestObservedSize + kQuicNumTimestampsSize;
}
// static
@@ -541,16 +535,13 @@ size_t QuicFramer::GetConnectionCloseFrameSize(
// Prepend the extra error information to the string and get the result's
// length.
const size_t truncated_error_string_size = TruncatedErrorStringSize(
- GenerateErrorString(frame.error_details, frame.extracted_error_code));
+ GenerateErrorString(frame.error_details, frame.quic_error_code));
const size_t frame_size =
truncated_error_string_size +
QuicDataWriter::GetVarInt62Len(truncated_error_string_size) +
kQuicFrameTypeSize +
- QuicDataWriter::GetVarInt62Len(
- (frame.close_type == IETF_QUIC_TRANSPORT_CONNECTION_CLOSE)
- ? frame.transport_error_code
- : frame.application_error_code);
+ QuicDataWriter::GetVarInt62Len(frame.wire_error_code);
if (frame.close_type == IETF_QUIC_APPLICATION_CONNECTION_CLOSE) {
return frame_size;
}
@@ -819,9 +810,9 @@ size_t QuicFramer::GetSerializedFrameLength(
}
bool can_truncate =
frame.type == ACK_FRAME &&
- free_bytes >= GetMinAckFrameSize(
- version_.transport_version, *frame.ack_frame,
- local_ack_delay_exponent_, PACKET_6BYTE_PACKET_NUMBER);
+ free_bytes >= GetMinAckFrameSize(version_.transport_version,
+ *frame.ack_frame,
+ local_ack_delay_exponent_);
if (can_truncate) {
// Truncate the frame so the packet will not exceed kMaxOutgoingPacketSize.
// Note that we may not use every byte of the writer in this case.
@@ -1621,26 +1612,14 @@ void QuicFramer::MaybeProcessCoalescedPacket(
return;
}
- if (GetQuicReloadableFlag(quic_minimum_validation_of_coalesced_packets)) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_minimum_validation_of_coalesced_packets);
- if (coalesced_header.destination_connection_id !=
- header.destination_connection_id) {
- // Drop coalesced packets with mismatched connection IDs.
- QUIC_DLOG(INFO) << ENDPOINT << "Received mismatched coalesced header "
- << coalesced_header << " previous header was " << header;
- QUIC_CODE_COUNT(
- quic_received_coalesced_packets_with_mismatched_connection_id);
- return;
- }
- } else {
- if (coalesced_header.destination_connection_id !=
- header.destination_connection_id ||
- (coalesced_header.form != IETF_QUIC_SHORT_HEADER_PACKET &&
- coalesced_header.version != header.version)) {
- QUIC_PEER_BUG << ENDPOINT << "Received mismatched coalesced header "
+ if (coalesced_header.destination_connection_id !=
+ header.destination_connection_id) {
+ // Drop coalesced packets with mismatched connection IDs.
+ QUIC_DLOG(INFO) << ENDPOINT << "Received mismatched coalesced header "
<< coalesced_header << " previous header was " << header;
- return;
- }
+ QUIC_CODE_COUNT(
+ quic_received_coalesced_packets_with_mismatched_connection_id);
+ return;
}
QuicEncryptedPacket coalesced_packet(coalesced_data, coalesced_data_length,
@@ -1758,6 +1737,7 @@ bool QuicFramer::ProcessIetfDataPacket(QuicDataReader* encrypted_reader,
visitor_->OnUndecryptablePacket(
QuicEncryptedPacket(encrypted_reader->FullPayload()),
decryption_level, has_decryption_key);
+ RecordDroppedPacketReason(DroppedPacketReason::DECRYPTION_FAILURE);
set_detailed_error(quiche::QuicheStrCat(
"Unable to decrypt ", EncryptionLevelToString(decryption_level),
" header protection", has_decryption_key ? "" : " (missing key)",
@@ -3469,12 +3449,12 @@ bool QuicFramer::ProcessIetfStreamFrame(QuicDataReader* reader,
// If we have a data length, read it. If not, set to 0.
if (frame_type & IETF_STREAM_FRAME_LEN_BIT) {
- QuicIetfStreamDataLength length;
+ uint64_t length;
if (!reader->ReadVarInt62(&length)) {
set_detailed_error("Unable to read stream data length.");
return false;
}
- if (length > 0xffff) {
+ if (length > std::numeric_limits<decltype(frame->data_length)>::max()) {
set_detailed_error("Stream data length is too large.");
return false;
}
@@ -3498,7 +3478,7 @@ bool QuicFramer::ProcessIetfStreamFrame(QuicDataReader* reader,
return false;
}
frame->data_buffer = data.data();
- frame->data_length = static_cast<QuicIetfStreamDataLength>(data.length());
+ DCHECK_EQ(frame->data_length, data.length());
return true;
}
@@ -3975,13 +3955,11 @@ bool QuicFramer::ProcessConnectionCloseFrame(QuicDataReader* reader,
error_code = QUIC_LAST_ERROR;
}
+ // For Google QUIC connection closes, |wire_error_code| and |quic_error_code|
+ // must have the same value.
+ frame->wire_error_code = error_code;
frame->quic_error_code = static_cast<QuicErrorCode>(error_code);
- // For Google QUIC connection closes, copy the Google QUIC error code to
- // the extracted error code field so that the Google QUIC error code is always
- // available in extracted_error_code.
- frame->extracted_error_code = frame->quic_error_code;
-
quiche::QuicheStringPiece error_details;
if (!reader->ReadStringPiece16(&error_details)) {
set_detailed_error("Unable to read connection close error details.");
@@ -4680,14 +4658,11 @@ size_t QuicFramer::GetAckFrameSize(
return GetIetfAckFrameSize(ack);
}
AckFrameInfo ack_info = GetAckFrameInfo(ack);
- QuicPacketNumberLength largest_acked_length =
- GetMinPacketNumberLength(LargestAcked(ack));
QuicPacketNumberLength ack_block_length =
GetMinPacketNumberLength(QuicPacketNumber(ack_info.max_block_length));
- ack_size =
- GetMinAckFrameSize(version_.transport_version, ack,
- local_ack_delay_exponent_, largest_acked_length);
+ ack_size = GetMinAckFrameSize(version_.transport_version, ack,
+ local_ack_delay_exponent_);
// First ack block length.
ack_size += ack_block_length;
if (ack_info.num_ack_blocks != 0) {
@@ -5153,7 +5128,7 @@ bool QuicFramer::AppendAckFrameAndTypeByte(const QuicAckFrame& frame,
int32_t available_timestamp_and_ack_block_bytes =
writer->capacity() - writer->length() - ack_block_length -
GetMinAckFrameSize(version_.transport_version, frame,
- local_ack_delay_exponent_, largest_acked_length) -
+ local_ack_delay_exponent_) -
(new_ack_info.num_ack_blocks != 0 ? kNumberOfAckBlocksSize : 0);
DCHECK_LE(0, available_timestamp_and_ack_block_bytes);
@@ -5441,7 +5416,7 @@ bool QuicFramer::AppendIetfAckFrameAndTypeByte(const QuicAckFrame& frame,
const uint64_t ack_range = iter->Length() - 1;
if (writer->remaining() < ecn_size ||
- writer->remaining() - ecn_size <
+ static_cast<size_t>(writer->remaining() - ecn_size) <
QuicDataWriter::GetVarInt62Len(gap) +
QuicDataWriter::GetVarInt62Len(ack_range)) {
// ACK range does not fit, truncate it.
@@ -5517,7 +5492,7 @@ bool QuicFramer::AppendConnectionCloseFrame(
if (VersionHasIetfQuicFrames(version_.transport_version)) {
return AppendIetfConnectionCloseFrame(frame, writer);
}
- uint32_t error_code = static_cast<uint32_t>(frame.quic_error_code);
+ uint32_t error_code = static_cast<uint32_t>(frame.wire_error_code);
if (!writer->WriteUInt32(error_code)) {
return false;
}
@@ -5642,10 +5617,7 @@ bool QuicFramer::AppendIetfConnectionCloseFrame(
return false;
}
- if (!writer->WriteVarInt62(
- (frame.close_type == IETF_QUIC_TRANSPORT_CONNECTION_CLOSE)
- ? frame.transport_error_code
- : frame.application_error_code)) {
+ if (!writer->WriteVarInt62(frame.wire_error_code)) {
set_detailed_error("Can not write connection close frame error code");
return false;
}
@@ -5663,7 +5635,7 @@ bool QuicFramer::AppendIetfConnectionCloseFrame(
// code. Encode the error information in the reason phrase and serialize the
// result.
std::string final_error_string =
- GenerateErrorString(frame.error_details, frame.extracted_error_code);
+ GenerateErrorString(frame.error_details, frame.quic_error_code);
if (!writer->WriteStringPieceVarInt62(
TruncateErrorString(final_error_string))) {
set_detailed_error("Can not write connection close phrase");
@@ -5684,12 +5656,7 @@ bool QuicFramer::ProcessIetfConnectionCloseFrame(
return false;
}
- if (frame->close_type == IETF_QUIC_TRANSPORT_CONNECTION_CLOSE) {
- frame->transport_error_code =
- static_cast<QuicIetfTransportErrorCodes>(error_code);
- } else if (frame->close_type == IETF_QUIC_APPLICATION_CONNECTION_CLOSE) {
- frame->application_error_code = error_code;
- }
+ frame->wire_error_code = error_code;
if (type == IETF_QUIC_TRANSPORT_CONNECTION_CLOSE) {
// The frame-type of the frame causing the error is present only
@@ -5790,18 +5757,13 @@ bool QuicFramer::ProcessIetfResetStreamFrame(QuicDataReader* reader,
return false;
}
- uint64_t error_code;
- if (!reader->ReadVarInt62(&error_code)) {
+ if (!reader->ReadVarInt62(&frame->ietf_error_code)) {
set_detailed_error("Unable to read rst stream error code.");
return false;
}
- if (error_code > 0xffff) {
- frame->ietf_error_code = 0xffff;
- QUIC_DLOG(ERROR) << "Reset stream error code (" << error_code
- << ") > 0xffff";
- } else {
- frame->ietf_error_code = static_cast<uint16_t>(error_code);
- }
+
+ frame->error_code =
+ IetfResetStreamErrorCodeToRstStreamErrorCode(frame->ietf_error_code);
if (!reader->ReadVarInt62(&frame->byte_offset)) {
set_detailed_error("Unable to read rst stream sent byte offset.");
@@ -6626,10 +6588,10 @@ void MaybeExtractQuicErrorCode(QuicConnectionCloseFrame* frame) {
if (ed.size() < 2 || !quiche::QuicheTextUtils::IsAllDigits(ed[0]) ||
!quiche::QuicheTextUtils::StringToUint64(ed[0], &extracted_error_code)) {
if (frame->close_type == IETF_QUIC_TRANSPORT_CONNECTION_CLOSE &&
- frame->transport_error_code == NO_IETF_QUIC_ERROR) {
- frame->extracted_error_code = QUIC_NO_ERROR;
+ frame->wire_error_code == NO_IETF_QUIC_ERROR) {
+ frame->quic_error_code = QUIC_NO_ERROR;
} else {
- frame->extracted_error_code = QUIC_IETF_GQUIC_ERROR_MISSING;
+ frame->quic_error_code = QUIC_IETF_GQUIC_ERROR_MISSING;
}
return;
}
@@ -6641,8 +6603,7 @@ void MaybeExtractQuicErrorCode(QuicConnectionCloseFrame* frame) {
quiche::QuicheStringPiece x = quiche::QuicheStringPiece(frame->error_details);
x.remove_prefix(ed[0].length() + 1);
frame->error_details = std::string(x);
- frame->extracted_error_code =
- static_cast<QuicErrorCode>(extracted_error_code);
+ frame->quic_error_code = static_cast<QuicErrorCode>(extracted_error_code);
}
#undef ENDPOINT // undef for jumbo builds
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 746e6a1dacc..8ace715d285 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
@@ -312,13 +312,9 @@ class QUIC_EXPORT_PRIVATE QuicFramer {
QuicByteCount length);
// Size in bytes of all ack frame fields without the missing packets or ack
// blocks.
- // TODO(fayang): Remove |largest_observed_length| when deprecating
- // quic_use_ack_frame_to_get_min_size.
- static size_t GetMinAckFrameSize(
- QuicTransportVersion version,
- const QuicAckFrame& ack_frame,
- uint32_t local_ack_delay_exponent,
- QuicPacketNumberLength largest_observed_length);
+ static size_t GetMinAckFrameSize(QuicTransportVersion version,
+ const QuicAckFrame& ack_frame,
+ uint32_t local_ack_delay_exponent);
// Size in bytes of a stop waiting frame.
static size_t GetStopWaitingFrameSize(
QuicPacketNumberLength packet_number_length);
@@ -1097,9 +1093,10 @@ class QUIC_EXPORT_PRIVATE QuicFramer {
// This text, inserted by the peer if it's using Google's QUIC implementation,
// contains additional error information that narrows down the exact error. The
// extracted error code and (possibly updated) error_details string are returned
-// in |*frame|. If an error code is not found in the error details then the
-// extracted_error_code is set to QuicErrorCode::QUIC_IETF_GQUIC_ERROR_MISSING.
-// If there is an error code in the string then it is removed from the string.
+// in |*frame|. If an error code is not found in the error details, then
+// frame->quic_error_code is set to
+// QuicErrorCode::QUIC_IETF_GQUIC_ERROR_MISSING. If there is an error code in
+// the string then it is removed from the string.
QUIC_EXPORT_PRIVATE void MaybeExtractQuicErrorCode(
QuicConnectionCloseFrame* frame);
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 813d4f6c270..fb9c2eb87bc 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
@@ -4259,9 +4259,9 @@ TEST_P(QuicFramerTest, RstStreamFrame) {
{"Unable to read rst stream sent byte offset.",
{0x3A, 0x98, 0xFE, 0xDC,
0x32, 0x10, 0x76, 0x54}},
- // error code
+ // error code QUIC_STREAM_CANCELLED
{"Unable to read rst stream error code.",
- {0x00, 0x00, 0x00, 0x01}}
+ {0x00, 0x00, 0x00, 0x06}}
};
PacketFragments packet46 = {
@@ -4284,9 +4284,9 @@ TEST_P(QuicFramerTest, RstStreamFrame) {
{"Unable to read rst stream sent byte offset.",
{0x3A, 0x98, 0xFE, 0xDC,
0x32, 0x10, 0x76, 0x54}},
- // error code
+ // error code QUIC_STREAM_CANCELLED
{"Unable to read rst stream error code.",
- {0x00, 0x00, 0x00, 0x01}}
+ {0x00, 0x00, 0x00, 0x06}}
};
PacketFragments packet99 = {
@@ -4305,9 +4305,10 @@ TEST_P(QuicFramerTest, RstStreamFrame) {
// stream id
{"Unable to read IETF_RST_STREAM frame stream id/count.",
{kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04}},
- // application error code
+ // application error code H3_REQUEST_CANCELLED gets translated to
+ // QuicRstStreamErrorCode::QUIC_STREAM_CANCELLED.
{"Unable to read rst stream error code.",
- {kVarInt62OneByte + 0x01}},
+ {kVarInt62TwoBytes + 0x01, 0x0c}},
// Final Offset
{"Unable to read rst stream sent byte offset.",
{kVarInt62EightBytes + 0x3a, 0x98, 0xFE, 0xDC, 0x32, 0x10, 0x76, 0x54}}
@@ -4330,7 +4331,7 @@ TEST_P(QuicFramerTest, RstStreamFrame) {
PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID));
EXPECT_EQ(kStreamId, visitor_.rst_stream_frame_.stream_id);
- EXPECT_EQ(0x01, visitor_.rst_stream_frame_.error_code);
+ EXPECT_EQ(QUIC_STREAM_CANCELLED, visitor_.rst_stream_frame_.error_code);
EXPECT_EQ(kStreamOffset, visitor_.rst_stream_frame_.byte_offset);
CheckFramingBoundaries(fragments, QUIC_INVALID_RST_STREAM_DATA);
}
@@ -4442,19 +4443,18 @@ TEST_P(QuicFramerTest, ConnectionCloseFrame) {
EXPECT_EQ(0u, visitor_.stream_frames_.size());
EXPECT_EQ(0x11u, static_cast<unsigned>(
- visitor_.connection_close_frame_.quic_error_code));
+ visitor_.connection_close_frame_.wire_error_code));
EXPECT_EQ("because I can", visitor_.connection_close_frame_.error_details);
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
EXPECT_EQ(0x1234u,
visitor_.connection_close_frame_.transport_close_frame_type);
- EXPECT_THAT(visitor_.connection_close_frame_.extracted_error_code,
+ EXPECT_THAT(visitor_.connection_close_frame_.quic_error_code,
IsError(QUIC_IETF_GQUIC_ERROR_MISSING));
} else {
- // For Google QUIC closes, the error code is copied into
- // extracted_error_code.
- EXPECT_EQ(0x11u,
- static_cast<unsigned>(
- visitor_.connection_close_frame_.extracted_error_code));
+ // For Google QUIC frame, |quic_error_code| and |wire_error_code| has the
+ // same value.
+ EXPECT_EQ(0x11u, static_cast<unsigned>(
+ visitor_.connection_close_frame_.quic_error_code));
}
ASSERT_EQ(0u, visitor_.ack_frames_.size());
@@ -4576,15 +4576,15 @@ TEST_P(QuicFramerTest, ConnectionCloseFrameWithExtractedInfoIgnoreGCuic) {
EXPECT_EQ(0u, visitor_.stream_frames_.size());
EXPECT_EQ(0x11u, static_cast<unsigned>(
- visitor_.connection_close_frame_.quic_error_code));
+ visitor_.connection_close_frame_.wire_error_code));
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
EXPECT_EQ(0x1234u,
visitor_.connection_close_frame_.transport_close_frame_type);
- EXPECT_EQ(17767u, visitor_.connection_close_frame_.extracted_error_code);
+ EXPECT_EQ(17767u, visitor_.connection_close_frame_.quic_error_code);
EXPECT_EQ("because I can", visitor_.connection_close_frame_.error_details);
} else {
- EXPECT_EQ(0x11u, visitor_.connection_close_frame_.extracted_error_code);
+ EXPECT_EQ(0x11u, visitor_.connection_close_frame_.quic_error_code);
// Error code is not prepended in GQUIC, so it is not removed and should
// remain in the reason phrase.
EXPECT_EQ("17767:because I can",
@@ -4648,8 +4648,8 @@ TEST_P(QuicFramerTest, ApplicationCloseFrame) {
EXPECT_EQ(IETF_QUIC_APPLICATION_CONNECTION_CLOSE,
visitor_.connection_close_frame_.close_type);
- EXPECT_EQ(122u, visitor_.connection_close_frame_.extracted_error_code);
- EXPECT_EQ(0x11u, visitor_.connection_close_frame_.quic_error_code);
+ EXPECT_EQ(122u, visitor_.connection_close_frame_.quic_error_code);
+ EXPECT_EQ(0x11u, visitor_.connection_close_frame_.wire_error_code);
EXPECT_EQ("because I can", visitor_.connection_close_frame_.error_details);
ASSERT_EQ(0u, visitor_.ack_frames_.size());
@@ -4710,8 +4710,8 @@ TEST_P(QuicFramerTest, ApplicationCloseFrameExtract) {
EXPECT_EQ(IETF_QUIC_APPLICATION_CONNECTION_CLOSE,
visitor_.connection_close_frame_.close_type);
- EXPECT_EQ(17767u, visitor_.connection_close_frame_.extracted_error_code);
- EXPECT_EQ(0x11u, visitor_.connection_close_frame_.quic_error_code);
+ EXPECT_EQ(17767u, visitor_.connection_close_frame_.quic_error_code);
+ EXPECT_EQ(0x11u, visitor_.connection_close_frame_.wire_error_code);
EXPECT_EQ("because I can", visitor_.connection_close_frame_.error_details);
ASSERT_EQ(0u, visitor_.ack_frames_.size());
@@ -7528,12 +7528,7 @@ TEST_P(QuicFramerTest, BuildCloseFramePacket) {
header.packet_number = kPacketNumber;
QuicConnectionCloseFrame close_frame(
- framer_.transport_version(),
- static_cast<QuicErrorCode>(
- VersionHasIetfQuicFrames(framer_.transport_version()) ? 0x11
- : 0x05060708),
- "because I can", 0x05);
- close_frame.extracted_error_code = QUIC_IETF_GQUIC_ERROR_MISSING;
+ framer_.transport_version(), QUIC_INTERNAL_ERROR, "because I can", 0x05);
QuicFrames frames = {QuicFrame(&close_frame)};
// clang-format off
@@ -7548,7 +7543,7 @@ TEST_P(QuicFramerTest, BuildCloseFramePacket) {
// frame type (connection close frame)
0x02,
// error code
- 0x05, 0x06, 0x07, 0x08,
+ 0x00, 0x00, 0x00, 0x01,
// error details length
0x00, 0x0d,
// error details
@@ -7569,7 +7564,7 @@ TEST_P(QuicFramerTest, BuildCloseFramePacket) {
// frame type (connection close frame)
0x02,
// error code
- 0x05, 0x06, 0x07, 0x08,
+ 0x00, 0x00, 0x00, 0x01,
// error details length
0x00, 0x0d,
// error details
@@ -7590,16 +7585,16 @@ TEST_P(QuicFramerTest, BuildCloseFramePacket) {
// frame type (IETF_CONNECTION_CLOSE frame)
0x1c,
// error code
- kVarInt62OneByte + 0x11,
+ kVarInt62OneByte + 0x01,
// Frame type within the CONNECTION_CLOSE frame
kVarInt62OneByte + 0x05,
// error details length
- kVarInt62OneByte + 0x0d,
+ kVarInt62OneByte + 0x0f,
// error details
- 'b', 'e', 'c', 'a',
- 'u', 's', 'e', ' ',
- 'I', ' ', 'c', 'a',
- 'n',
+ '1', ':', 'b', 'e',
+ 'c', 'a', 'u', 's',
+ 'e', ' ', 'I', ' ',
+ 'c', 'a', 'n',
};
// clang-format on
@@ -7631,12 +7626,12 @@ TEST_P(QuicFramerTest, BuildCloseFramePacketExtendedInfo) {
QuicConnectionCloseFrame close_frame(
framer_.transport_version(),
static_cast<QuicErrorCode>(
- VersionHasIetfQuicFrames(framer_.transport_version()) ? 0x11
+ VersionHasIetfQuicFrames(framer_.transport_version()) ? 0x01
: 0x05060708),
"because I can", 0x05);
// Set this so that it is "there" for both Google QUIC and IETF QUIC
// framing. It better not show up for Google QUIC!
- close_frame.extracted_error_code = static_cast<QuicErrorCode>(0x4567);
+ close_frame.quic_error_code = static_cast<QuicErrorCode>(0x4567);
QuicFrames frames = {QuicFrame(&close_frame)};
@@ -7693,8 +7688,9 @@ TEST_P(QuicFramerTest, BuildCloseFramePacketExtendedInfo) {
// frame type (IETF_CONNECTION_CLOSE frame)
0x1c,
- // error code
- kVarInt62OneByte + 0x11,
+ // IETF error code INTERNAL_ERROR = 0x01 corresponding to
+ // QuicErrorCode::QUIC_INTERNAL_ERROR = 0x01.
+ kVarInt62OneByte + 0x01,
// Frame type within the CONNECTION_CLOSE frame
kVarInt62OneByte + 0x05,
// error details length
@@ -7733,13 +7729,9 @@ TEST_P(QuicFramerTest, BuildTruncatedCloseFramePacket) {
header.version_flag = false;
header.packet_number = kPacketNumber;
- QuicConnectionCloseFrame close_frame(
- framer_.transport_version(),
- static_cast<QuicErrorCode>(
- VersionHasIetfQuicFrames(framer_.transport_version()) ? 0xa
- : 0x05060708),
- std::string(2048, 'A'), 0x05);
- close_frame.extracted_error_code = QUIC_IETF_GQUIC_ERROR_MISSING;
+ QuicConnectionCloseFrame close_frame(framer_.transport_version(),
+ QUIC_INTERNAL_ERROR,
+ std::string(2048, 'A'), 0x05);
QuicFrames frames = {QuicFrame(&close_frame)};
// clang-format off
@@ -7754,7 +7746,7 @@ TEST_P(QuicFramerTest, BuildTruncatedCloseFramePacket) {
// frame type (connection close frame)
0x02,
// error code
- 0x05, 0x06, 0x07, 0x08,
+ 0x00, 0x00, 0x00, 0x01,
// error details length
0x01, 0x00,
// error details (truncated to 256 bytes)
@@ -7803,7 +7795,7 @@ TEST_P(QuicFramerTest, BuildTruncatedCloseFramePacket) {
// frame type (connection close frame)
0x02,
// error code
- 0x05, 0x06, 0x07, 0x08,
+ 0x00, 0x00, 0x00, 0x01,
// error details length
0x01, 0x00,
// error details (truncated to 256 bytes)
@@ -7852,13 +7844,13 @@ TEST_P(QuicFramerTest, BuildTruncatedCloseFramePacket) {
// frame type (IETF_CONNECTION_CLOSE frame)
0x1c,
// error code
- kVarInt62OneByte + 0x0a,
+ kVarInt62OneByte + 0x01,
// Frame type within the CONNECTION_CLOSE frame
kVarInt62OneByte + 0x05,
// error details length
kVarInt62TwoBytes + 0x01, 0x00,
// error details (truncated to 256 bytes)
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
+ '1', ':', 'A', 'A', 'A', 'A', 'A', 'A',
'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
@@ -7923,8 +7915,7 @@ TEST_P(QuicFramerTest, BuildApplicationCloseFramePacket) {
header.packet_number = kPacketNumber;
QuicConnectionCloseFrame app_close_frame;
- app_close_frame.application_error_code =
- static_cast<uint64_t>(QUIC_INVALID_STREAM_ID);
+ app_close_frame.wire_error_code = 0x11;
app_close_frame.error_details = "because I can";
app_close_frame.close_type = IETF_QUIC_APPLICATION_CONNECTION_CLOSE;
@@ -7975,13 +7966,12 @@ TEST_P(QuicFramerTest, BuildTruncatedApplicationCloseFramePacket) {
header.packet_number = kPacketNumber;
QuicConnectionCloseFrame app_close_frame;
- app_close_frame.application_error_code =
- static_cast<uint64_t>(QUIC_INVALID_STREAM_ID);
+ app_close_frame.wire_error_code = 0x11;
app_close_frame.error_details = std::string(2048, 'A');
app_close_frame.close_type = IETF_QUIC_APPLICATION_CONNECTION_CLOSE;
// Setting to missing ensures that if it is missing, the extended
// code is not added to the text message.
- app_close_frame.extracted_error_code = QUIC_IETF_GQUIC_ERROR_MISSING;
+ app_close_frame.quic_error_code = QUIC_IETF_GQUIC_ERROR_MISSING;
QuicFrames frames = {QuicFrame(&app_close_frame)};
@@ -12451,7 +12441,6 @@ TEST_P(QuicFramerTest, CoalescedPacketWithDifferentVersion) {
if (!QuicVersionHasLongHeaderLengths(framer_.transport_version())) {
return;
}
- SetQuicReloadableFlag(quic_minimum_validation_of_coalesced_packets, true);
SetDecrypterLevel(ENCRYPTION_ZERO_RTT);
// clang-format off
unsigned char packet[] = {
@@ -13123,12 +13112,7 @@ TEST_P(QuicFramerTest, MismatchedCoalescedPacket) {
QuicEncryptedPacket encrypted(AsChars(p), p_length, false);
- if (GetQuicReloadableFlag(quic_minimum_validation_of_coalesced_packets)) {
- EXPECT_TRUE(framer_.ProcessPacket(encrypted));
- } else {
- EXPECT_QUIC_PEER_BUG(EXPECT_TRUE(framer_.ProcessPacket(encrypted)),
- "Server: Received mismatched coalesced header.*");
- }
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
EXPECT_THAT(framer_.error(), IsQuicNoError());
ASSERT_TRUE(visitor_.header_.get());
@@ -14254,84 +14238,77 @@ TEST_P(QuicFramerTest, TestExtendedErrorCodeParser) {
frame.error_details = "this has no error code info in it";
MaybeExtractQuicErrorCode(&frame);
- EXPECT_THAT(frame.extracted_error_code,
- IsError(QUIC_IETF_GQUIC_ERROR_MISSING));
+ EXPECT_THAT(frame.quic_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_THAT(frame.extracted_error_code,
- IsError(QUIC_IETF_GQUIC_ERROR_MISSING));
+ EXPECT_THAT(frame.quic_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_THAT(frame.extracted_error_code,
- IsError(QUIC_IETF_GQUIC_ERROR_MISSING));
+ EXPECT_THAT(frame.quic_error_code, IsError(QUIC_IETF_GQUIC_ERROR_MISSING));
EXPECT_EQ("1a234:this has a colon, but a malformed error number",
frame.error_details);
frame.error_details = "1234:this is good";
MaybeExtractQuicErrorCode(&frame);
- EXPECT_EQ(1234u, frame.extracted_error_code);
+ EXPECT_EQ(1234u, frame.quic_error_code);
EXPECT_EQ("this is good", frame.error_details);
frame.error_details =
"1234 :this is not good, space between last digit and colon";
MaybeExtractQuicErrorCode(&frame);
- EXPECT_THAT(frame.extracted_error_code,
- IsError(QUIC_IETF_GQUIC_ERROR_MISSING));
+ EXPECT_THAT(frame.quic_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_THAT(
- frame.extracted_error_code,
+ frame.quic_error_code,
IsError(QUIC_IETF_GQUIC_ERROR_MISSING)); // Not good, all numbers, no :
EXPECT_EQ("123456789", frame.error_details);
frame.error_details = "1234:";
MaybeExtractQuicErrorCode(&frame);
EXPECT_EQ(1234u,
- frame.extracted_error_code); // corner case.
+ frame.quic_error_code); // corner case.
EXPECT_EQ("", frame.error_details);
frame.error_details = "1234:5678";
MaybeExtractQuicErrorCode(&frame);
EXPECT_EQ(1234u,
- frame.extracted_error_code); // another corner case.
+ frame.quic_error_code); // another corner case.
EXPECT_EQ("5678", frame.error_details);
frame.error_details = "12345 6789:";
MaybeExtractQuicErrorCode(&frame);
- EXPECT_THAT(frame.extracted_error_code,
+ EXPECT_THAT(frame.quic_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_THAT(frame.extracted_error_code,
- IsError(QUIC_IETF_GQUIC_ERROR_MISSING));
+ EXPECT_THAT(frame.quic_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_THAT(frame.extracted_error_code,
- IsError(QUIC_IETF_GQUIC_ERROR_MISSING));
+ EXPECT_THAT(frame.quic_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_THAT(frame.extracted_error_code,
- IsError(QUIC_IETF_GQUIC_ERROR_MISSING));
+ EXPECT_THAT(frame.quic_error_code, IsError(QUIC_IETF_GQUIC_ERROR_MISSING));
EXPECT_EQ(" 1234:this is not good, space before first digit",
frame.error_details);
frame.error_details = "1234:";
MaybeExtractQuicErrorCode(&frame);
EXPECT_EQ(1234u,
- frame.extracted_error_code); // this is good
+ frame.quic_error_code); // this is good
EXPECT_EQ("", frame.error_details);
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_idle_network_detector_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_idle_network_detector_test.cc
index 16941ef7a82..0d40d640417 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_idle_network_detector_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_idle_network_detector_test.cc
@@ -22,8 +22,8 @@ namespace {
class MockDelegate : public QuicIdleNetworkDetector::Delegate {
public:
- MOCK_METHOD0(OnHandshakeTimeout, void());
- MOCK_METHOD0(OnIdleNetworkDetected, void());
+ MOCK_METHOD(void, OnHandshakeTimeout, (), (override));
+ MOCK_METHOD(void, OnIdleNetworkDetected, (), (override));
};
class QuicIdleNetworkDetectorTest : public QuicTest {
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_network_blackhole_detector_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_network_blackhole_detector_test.cc
index eca50e3c1f3..0178887c2f8 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_network_blackhole_detector_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_network_blackhole_detector_test.cc
@@ -21,8 +21,8 @@ class QuicNetworkBlackholeDetectorPeer {
namespace {
class MockDelegate : public QuicNetworkBlackholeDetector::Delegate {
public:
- MOCK_METHOD0(OnPathDegradingDetected, void());
- MOCK_METHOD0(OnBlackholeDetected, void());
+ MOCK_METHOD(void, OnPathDegradingDetected, (), (override));
+ MOCK_METHOD(void, OnBlackholeDetected, (), (override));
};
const size_t kPathDegradingDelayInSeconds = 5;
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 d6b7ee99b55..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
@@ -75,10 +75,7 @@ QuicArenaScopedPtr<T> QuicOneBlockArena<ArenaSize>::New(Args&&... args) {
// QuicConnections currently use around 1KB of polymorphic types which would
// ordinarily be on the heap. Instead, store them inline in an arena.
-// TODO(fayang): Switch this and 1200 used in quic_arena_scoped_ptr_test and
-// quic_one_block_arena_test back to 1024 when deprecating
-// quic_use_blackhole_detector or quic_use_idle_network_detector.
-using QuicConnectionArena = QuicOneBlockArena<1200>;
+using QuicConnectionArena = QuicOneBlockArena<1024>;
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_one_block_arena_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_one_block_arena_test.cc
index 11b12de410a..3175ac54abf 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_one_block_arena_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_one_block_arena_test.cc
@@ -23,14 +23,14 @@ struct TestObject {
class QuicOneBlockArenaTest : public QuicTest {};
TEST_F(QuicOneBlockArenaTest, AllocateSuccess) {
- QuicOneBlockArena<1200> arena;
+ QuicOneBlockArena<1024> arena;
QuicArenaScopedPtr<TestObject> ptr = arena.New<TestObject>();
EXPECT_TRUE(ptr.is_from_arena());
}
TEST_F(QuicOneBlockArenaTest, Exhaust) {
- QuicOneBlockArena<1200> arena;
- for (size_t i = 0; i < 1200 / kMaxAlign; ++i) {
+ QuicOneBlockArena<1024> arena;
+ for (size_t i = 0; i < 1024 / kMaxAlign; ++i) {
QuicArenaScopedPtr<TestObject> ptr = arena.New<TestObject>();
EXPECT_TRUE(ptr.is_from_arena());
}
@@ -41,10 +41,10 @@ TEST_F(QuicOneBlockArenaTest, Exhaust) {
}
TEST_F(QuicOneBlockArenaTest, NoOverlaps) {
- QuicOneBlockArena<1200> arena;
+ QuicOneBlockArena<1024> arena;
std::vector<QuicArenaScopedPtr<TestObject>> objects;
QuicIntervalSet<uintptr_t> used;
- for (size_t i = 0; i < 1200 / kMaxAlign; ++i) {
+ for (size_t i = 0; i < 1024 / kMaxAlign; ++i) {
QuicArenaScopedPtr<TestObject> ptr = arena.New<TestObject>();
EXPECT_TRUE(ptr.is_from_arena());
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 cea1a1be9cf..0ae78d22fa6 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
@@ -7,6 +7,7 @@
#include <algorithm>
#include <cstddef>
#include <cstdint>
+#include <limits>
#include <string>
#include <utility>
@@ -130,8 +131,15 @@ QuicPacketCreator::QuicPacketCreator(QuicConnectionId server_connection_id,
next_transmission_type_(NOT_RETRANSMISSION),
flusher_attached_(false),
fully_pad_crypto_handshake_packets_(true),
- latched_hard_max_packet_length_(0) {
+ latched_hard_max_packet_length_(0),
+ max_datagram_frame_size_(0) {
SetMaxPacketLength(kDefaultMaxPacketSize);
+ if (!framer_->version().UsesTls()) {
+ // QUIC+TLS negotiates the maximum datagram frame size via the
+ // IETF QUIC max_datagram_frame_size transport parameter.
+ // QUIC_CRYPTO however does not negotiate this so we set its value here.
+ SetMaxDatagramFrameSize(kMaxAcceptedDatagramFrameSize);
+ }
}
QuicPacketCreator::~QuicPacketCreator() {
@@ -165,6 +173,21 @@ void QuicPacketCreator::SetMaxPacketLength(QuicByteCount length) {
<< "Attempted to set max packet length too small";
}
+void QuicPacketCreator::SetMaxDatagramFrameSize(
+ QuicByteCount max_datagram_frame_size) {
+ constexpr QuicByteCount upper_bound =
+ std::min<QuicByteCount>(std::numeric_limits<QuicPacketLength>::max(),
+ std::numeric_limits<size_t>::max());
+ if (max_datagram_frame_size > upper_bound) {
+ // A value of |max_datagram_frame_size| that is equal or greater than
+ // 2^16-1 is effectively infinite because QUIC packets cannot be that large.
+ // We therefore clamp the value here to allow us to safely cast
+ // |max_datagram_frame_size_| to QuicPacketLength or size_t.
+ max_datagram_frame_size = upper_bound;
+ }
+ max_datagram_frame_size_ = max_datagram_frame_size;
+}
+
void QuicPacketCreator::SetSoftMaxPacketLength(QuicByteCount length) {
DCHECK(CanSetMaxPacketLength());
if (length > max_packet_length_) {
@@ -326,6 +349,10 @@ bool QuicPacketCreator::HasRoomForStreamFrame(QuicStreamId id,
bool QuicPacketCreator::HasRoomForMessageFrame(QuicByteCount length) {
const size_t message_frame_size = QuicFramer::GetMessageFrameSize(
framer_->transport_version(), /*last_frame_in_packet=*/true, length);
+ if (static_cast<QuicByteCount>(message_frame_size) >
+ max_datagram_frame_size_) {
+ return false;
+ }
if (BytesFree() >= message_frame_size) {
return true;
}
@@ -433,7 +460,7 @@ void QuicPacketCreator::OnSerializedPacket() {
SerializedPacket packet(std::move(packet_));
ClearPacket();
RemoveSoftMaxPacketLength();
- delegate_->OnSerializedPacket(&packet);
+ delegate_->OnSerializedPacket(std::move(packet));
}
void QuicPacketCreator::ClearPacket() {
@@ -741,7 +768,7 @@ QuicPacketCreator::SerializeVersionNegotiationPacket(
return encrypted;
}
-OwningSerializedPacketPointer
+std::unique_ptr<SerializedPacket>
QuicPacketCreator::SerializeConnectivityProbingPacket() {
QUIC_BUG_IF(VersionHasIetfQuicFrames(framer_->transport_version()))
<< "Must not be version 99 to serialize padded ping connectivity probe";
@@ -764,17 +791,20 @@ QuicPacketCreator::SerializeConnectivityProbingPacket() {
kMaxOutgoingPacketSize, buffer.get());
DCHECK(encrypted_length);
- OwningSerializedPacketPointer serialize_packet(new SerializedPacket(
+ std::unique_ptr<SerializedPacket> serialize_packet(new SerializedPacket(
header.packet_number, header.packet_number_length, buffer.release(),
encrypted_length, /*has_ack=*/false, /*has_stop_waiting=*/false));
+ serialize_packet->release_encrypted_buffer = [](const char* p) {
+ delete[] p;
+ };
serialize_packet->encryption_level = packet_.encryption_level;
serialize_packet->transmission_type = NOT_RETRANSMISSION;
return serialize_packet;
}
-OwningSerializedPacketPointer
+std::unique_ptr<SerializedPacket>
QuicPacketCreator::SerializePathChallengeConnectivityProbingPacket(
QuicPathFrameBuffer* payload) {
QUIC_BUG_IF(!VersionHasIetfQuicFrames(framer_->transport_version()))
@@ -800,17 +830,21 @@ QuicPacketCreator::SerializePathChallengeConnectivityProbingPacket(
kMaxOutgoingPacketSize, buffer.get());
DCHECK(encrypted_length);
- OwningSerializedPacketPointer serialize_packet(new SerializedPacket(
- header.packet_number, header.packet_number_length, buffer.release(),
- encrypted_length, /*has_ack=*/false, /*has_stop_waiting=*/false));
+ std::unique_ptr<SerializedPacket> serialize_packet(
+ new SerializedPacket(header.packet_number, header.packet_number_length,
+ buffer.release(), encrypted_length,
+ /*has_ack=*/false, /*has_stop_waiting=*/false));
+ serialize_packet->release_encrypted_buffer = [](const char* p) {
+ delete[] p;
+ };
serialize_packet->encryption_level = packet_.encryption_level;
serialize_packet->transmission_type = NOT_RETRANSMISSION;
return serialize_packet;
}
-OwningSerializedPacketPointer
+std::unique_ptr<SerializedPacket>
QuicPacketCreator::SerializePathResponseConnectivityProbingPacket(
const QuicCircularDeque<QuicPathFrameBuffer>& payloads,
const bool is_padded) {
@@ -837,10 +871,14 @@ QuicPacketCreator::SerializePathResponseConnectivityProbingPacket(
kMaxOutgoingPacketSize, buffer.get());
DCHECK(encrypted_length);
- OwningSerializedPacketPointer serialize_packet(new SerializedPacket(
- header.packet_number, header.packet_number_length, buffer.release(),
- encrypted_length, /*has_ack=*/false, /*has_stop_waiting=*/false));
+ std::unique_ptr<SerializedPacket> serialize_packet(
+ new SerializedPacket(header.packet_number, header.packet_number_length,
+ buffer.release(), encrypted_length,
+ /*has_ack=*/false, /*has_stop_waiting=*/false));
+ serialize_packet->release_encrypted_buffer = [](const char* p) {
+ delete[] p;
+ };
serialize_packet->encryption_level = packet_.encryption_level;
serialize_packet->transmission_type = NOT_RETRANSMISSION;
@@ -1705,8 +1743,12 @@ QuicPacketLength QuicPacketCreator::GetCurrentLargestMessagePayload() const {
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);
+ size_t largest_frame =
+ max_plaintext_size - std::min(max_plaintext_size, packet_header_size);
+ if (static_cast<QuicByteCount>(largest_frame) > max_datagram_frame_size_) {
+ largest_frame = static_cast<size_t>(max_datagram_frame_size_);
+ }
+ return largest_frame - std::min(largest_frame, kQuicFrameTypeSize);
}
QuicPacketLength QuicPacketCreator::GetGuaranteedLargestMessagePayload() const {
@@ -1739,9 +1781,13 @@ QuicPacketLength QuicPacketCreator::GetGuaranteedLargestMessagePayload() const {
latched_hard_max_packet_length_ == 0
? max_plaintext_size_
: framer_->GetMaxPlaintextSize(latched_hard_max_packet_length_);
+ size_t largest_frame =
+ max_plaintext_size - std::min(max_plaintext_size, packet_header_size);
+ if (static_cast<QuicByteCount>(largest_frame) > max_datagram_frame_size_) {
+ largest_frame = static_cast<size_t>(max_datagram_frame_size_);
+ }
const QuicPacketLength largest_payload =
- max_plaintext_size -
- std::min(max_plaintext_size, packet_header_size + kQuicFrameTypeSize);
+ largest_frame - std::min(largest_frame, kQuicFrameTypeSize);
// This must always be less than or equal to GetCurrentLargestMessagePayload.
DCHECK_LE(largest_payload, GetCurrentLargestMessagePayload());
return largest_payload;
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 508cd56256f..7695587f9f5 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
@@ -44,10 +44,9 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator {
// packet. If return nullptr, QuicPacketCreator will serialize on a stack
// buffer.
virtual char* GetPacketBuffer() = 0;
- // Called when a packet is serialized. Delegate does not take the ownership
- // of |serialized_packet|, but takes ownership of any frames it removes
- // from |packet.retransmittable_frames|.
- virtual void OnSerializedPacket(SerializedPacket* serialized_packet) = 0;
+ // Called when a packet is serialized. Delegate take the ownership of
+ // |serialized_packet|.
+ virtual void OnSerializedPacket(SerializedPacket serialized_packet) = 0;
// Called when an unrecoverable error is encountered.
virtual void OnUnrecoverableError(QuicErrorCode error,
@@ -210,19 +209,20 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator {
const ParsedQuicVersionVector& supported_versions);
// Creates a connectivity probing packet for versions prior to version 99.
- OwningSerializedPacketPointer SerializeConnectivityProbingPacket();
+ std::unique_ptr<SerializedPacket> SerializeConnectivityProbingPacket();
// Create connectivity probing request and response packets using PATH
// CHALLENGE and PATH RESPONSE frames, respectively, for version 99/IETF QUIC.
// SerializePathChallengeConnectivityProbingPacket will pad the packet to be
// MTU bytes long.
- OwningSerializedPacketPointer SerializePathChallengeConnectivityProbingPacket(
- QuicPathFrameBuffer* payload);
+ std::unique_ptr<SerializedPacket>
+ 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(
+ std::unique_ptr<SerializedPacket>
+ SerializePathResponseConnectivityProbingPacket(
const QuicCircularDeque<QuicPathFrameBuffer>& payloads,
const bool is_padded);
@@ -278,6 +278,9 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator {
// Sets the maximum packet length.
void SetMaxPacketLength(QuicByteCount length);
+ // Sets the maximum DATAGRAM/MESSAGE frame size we can send.
+ void SetMaxDatagramFrameSize(QuicByteCount max_datagram_frame_size);
+
// 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.
@@ -455,8 +458,8 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator {
// Serializes all frames which have been added and adds any which should be
// retransmitted to packet_.retransmittable_frames. All frames must fit into
// a single packet.
- // Fails if |buffer_len| isn't long enough for the encrypted packet.
- void SerializePacket(char* encrypted_buffer, size_t buffer_len);
+ // Fails if |encrypted_buffer_len| isn't long enough for the encrypted packet.
+ void SerializePacket(char* encrypted_buffer, size_t encrypted_buffer_len);
// Called after a new SerialiedPacket is created to call the delegate's
// OnSerializedPacket and reset state.
@@ -589,6 +592,11 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator {
// SetSoftMaxPacketLength is called and max_packet_length_ gets
// set to a soft value.
QuicByteCount latched_hard_max_packet_length_;
+
+ // The maximum length of a MESSAGE/DATAGRAM frame that our peer is willing to
+ // accept. There is no limit for QUIC_CRYPTO connections, but QUIC+TLS
+ // negotiates this during the handshake.
+ QuicByteCount max_datagram_frame_size_;
};
} // 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 1507ae5f34d..d1beea7c01d 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
@@ -86,9 +86,12 @@ class MockDebugDelegate : public QuicPacketCreator::DebugDelegate {
public:
~MockDebugDelegate() override = default;
- MOCK_METHOD1(OnFrameAddedToPacket, void(const QuicFrame& frame));
+ MOCK_METHOD(void, OnFrameAddedToPacket, (const QuicFrame& frame), (override));
- MOCK_METHOD1(OnStreamFrameCoalesced, void(const QuicStreamFrame& frame));
+ MOCK_METHOD(void,
+ OnStreamFrameCoalesced,
+ (const QuicStreamFrame& frame),
+ (override));
};
class TestPacketCreator : public QuicPacketCreator {
@@ -135,28 +138,16 @@ class TestPacketCreator : public QuicPacketCreator {
class QuicPacketCreatorTest : public QuicTestWithParam<TestParams> {
public:
- void ClearSerializedPacketForTests(SerializedPacket* serialized_packet) {
- if (serialized_packet == nullptr) {
- return;
- }
- ClearSerializedPacket(serialized_packet);
+ void ClearSerializedPacketForTests(SerializedPacket /*serialized_packet*/) {
+ // serialized packet self-clears on destruction.
}
- void SaveSerializedPacket(SerializedPacket* serialized_packet) {
- if (serialized_packet == nullptr) {
- return;
- }
- delete[] serialized_packet_.encrypted_buffer;
- serialized_packet_ = *serialized_packet;
- serialized_packet_.encrypted_buffer = CopyBuffer(*serialized_packet);
- serialized_packet->retransmittable_frames.clear();
+ void SaveSerializedPacket(SerializedPacket serialized_packet) {
+ serialized_packet_.reset(CopySerializedPacket(
+ serialized_packet, &allocator_, /*copy_buffer=*/true));
}
- void DeleteSerializedPacket() {
- delete[] serialized_packet_.encrypted_buffer;
- serialized_packet_.encrypted_buffer = nullptr;
- ClearSerializedPacket(&serialized_packet_);
- }
+ void DeleteSerializedPacket() { serialized_packet_ = nullptr; }
protected:
QuicPacketCreatorTest()
@@ -170,8 +161,7 @@ class QuicPacketCreatorTest : public QuicTestWithParam<TestParams> {
Perspective::IS_CLIENT,
connection_id_.length()),
data_("foo"),
- creator_(connection_id_, &client_framer_, &delegate_, &producer_),
- serialized_packet_(creator_.NoPacket()) {
+ creator_(connection_id_, &client_framer_, &delegate_, &producer_) {
EXPECT_CALL(delegate_, GetPacketBuffer()).WillRepeatedly(Return(nullptr));
creator_.SetEncrypter(ENCRYPTION_INITIAL, std::make_unique<NullEncrypter>(
Perspective::IS_CLIENT));
@@ -205,10 +195,7 @@ class QuicPacketCreatorTest : public QuicTestWithParam<TestParams> {
}
}
- ~QuicPacketCreatorTest() override {
- delete[] serialized_packet_.encrypted_buffer;
- ClearSerializedPacket(&serialized_packet_);
- }
+ ~QuicPacketCreatorTest() override {}
SerializedPacket SerializeAllFrames(const QuicFrames& frames) {
SerializedPacket packet = QuicPacketCreatorPeer::SerializeAllFrames(
@@ -282,7 +269,7 @@ class QuicPacketCreatorTest : public QuicTestWithParam<TestParams> {
n * 2;
}
- static const QuicStreamOffset kOffset = 0u;
+ static constexpr QuicStreamOffset kOffset = 0u;
char buffer_[kMaxOutgoingPacketSize];
QuicConnectionId connection_id_;
@@ -294,7 +281,7 @@ class QuicPacketCreatorTest : public QuicTestWithParam<TestParams> {
std::string data_;
struct iovec iov_;
TestPacketCreator creator_;
- SerializedPacket serialized_packet_;
+ std::unique_ptr<SerializedPacket> serialized_packet_;
SimpleDataProducer producer_;
SimpleBufferAllocator allocator_;
};
@@ -351,12 +338,12 @@ TEST_P(QuicPacketCreatorTest, SerializeFrames) {
}
TEST_P(QuicPacketCreatorTest, SerializeConnectionClose) {
- QuicConnectionCloseFrame frame(creator_.transport_version(), QUIC_NO_ERROR,
- "error",
- /*transport_close_frame_type=*/0);
+ QuicConnectionCloseFrame* frame = new QuicConnectionCloseFrame(
+ creator_.transport_version(), QUIC_NO_ERROR, "error",
+ /*transport_close_frame_type=*/0);
QuicFrames frames;
- frames.push_back(QuicFrame(&frame));
+ frames.push_back(QuicFrame(frame));
SerializedPacket serialized = SerializeAllFrames(frames);
EXPECT_EQ(ENCRYPTION_INITIAL, serialized.encryption_level);
ASSERT_EQ(QuicPacketNumber(1u), serialized.packet_number);
@@ -486,7 +473,7 @@ TEST_P(QuicPacketCreatorTest, StreamFrameConsumption) {
EXPECT_CALL(delegate_, OnSerializedPacket(_))
.WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
creator_.FlushCurrentPacket();
- ASSERT_TRUE(serialized_packet_.encrypted_buffer);
+ ASSERT_TRUE(serialized_packet_->encrypted_buffer);
DeleteSerializedPacket();
}
}
@@ -534,7 +521,7 @@ TEST_P(QuicPacketCreatorTest, CryptoStreamFramePacketPadding) {
EXPECT_LT(0u, bytes_consumed);
}
creator_.FlushCurrentPacket();
- ASSERT_TRUE(serialized_packet_.encrypted_buffer);
+ ASSERT_TRUE(serialized_packet_->encrypted_buffer);
// 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.
@@ -543,9 +530,9 @@ TEST_P(QuicPacketCreatorTest, CryptoStreamFramePacketPadding) {
!QuicVersionUsesCryptoFrames(client_framer_.transport_version())) ||
client_framer_.version().CanSendCoalescedPackets()) {
EXPECT_EQ(kDefaultMaxPacketSize - bytes_free,
- serialized_packet_.encrypted_length);
+ serialized_packet_->encrypted_length);
} else {
- EXPECT_EQ(kDefaultMaxPacketSize, serialized_packet_.encrypted_length);
+ EXPECT_EQ(kDefaultMaxPacketSize, serialized_packet_->encrypted_length);
}
DeleteSerializedPacket();
}
@@ -575,12 +562,12 @@ TEST_P(QuicPacketCreatorTest, NonCryptoStreamFramePacketNonPadding) {
size_t bytes_consumed = frame.stream_frame.data_length;
EXPECT_LT(0u, bytes_consumed);
creator_.FlushCurrentPacket();
- ASSERT_TRUE(serialized_packet_.encrypted_buffer);
+ ASSERT_TRUE(serialized_packet_->encrypted_buffer);
if (bytes_free > 0) {
EXPECT_EQ(kDefaultMaxPacketSize - bytes_free,
- serialized_packet_.encrypted_length);
+ serialized_packet_->encrypted_length);
} else {
- EXPECT_EQ(kDefaultMaxPacketSize, serialized_packet_.encrypted_length);
+ EXPECT_EQ(kDefaultMaxPacketSize, serialized_packet_->encrypted_length);
}
DeleteSerializedPacket();
}
@@ -948,7 +935,7 @@ TEST_P(QuicPacketCreatorTest, SerializeConnectivityProbingPacket) {
creator_.set_encryption_level(level);
- OwningSerializedPacketPointer encrypted;
+ std::unique_ptr<SerializedPacket> encrypted;
if (VersionHasIetfQuicFrames(creator_.transport_version())) {
QuicPathFrameBuffer payload = {
{0xde, 0xad, 0xbe, 0xef, 0xba, 0xdc, 0x0f, 0xfe}};
@@ -991,7 +978,7 @@ TEST_P(QuicPacketCreatorTest, SerializePathChallengeProbePacket) {
creator_.set_encryption_level(level);
- OwningSerializedPacketPointer encrypted(
+ std::unique_ptr<SerializedPacket> encrypted(
creator_.SerializePathChallengeConnectivityProbingPacket(&payload));
{
InSequence s;
@@ -1024,7 +1011,7 @@ TEST_P(QuicPacketCreatorTest, SerializePathResponseProbePacket1PayloadPadded) {
QuicCircularDeque<QuicPathFrameBuffer> payloads;
payloads.push_back(payload0);
- OwningSerializedPacketPointer encrypted(
+ std::unique_ptr<SerializedPacket> encrypted(
creator_.SerializePathResponseConnectivityProbingPacket(payloads,
true));
{
@@ -1058,7 +1045,7 @@ TEST_P(QuicPacketCreatorTest,
QuicCircularDeque<QuicPathFrameBuffer> payloads;
payloads.push_back(payload0);
- OwningSerializedPacketPointer encrypted(
+ std::unique_ptr<SerializedPacket> encrypted(
creator_.SerializePathResponseConnectivityProbingPacket(payloads,
false));
{
@@ -1093,7 +1080,7 @@ TEST_P(QuicPacketCreatorTest, SerializePathResponseProbePacket2PayloadsPadded) {
payloads.push_back(payload0);
payloads.push_back(payload1);
- OwningSerializedPacketPointer encrypted(
+ std::unique_ptr<SerializedPacket> encrypted(
creator_.SerializePathResponseConnectivityProbingPacket(payloads,
true));
{
@@ -1130,7 +1117,7 @@ TEST_P(QuicPacketCreatorTest,
payloads.push_back(payload0);
payloads.push_back(payload1);
- OwningSerializedPacketPointer encrypted(
+ std::unique_ptr<SerializedPacket> encrypted(
creator_.SerializePathResponseConnectivityProbingPacket(payloads,
false));
{
@@ -1168,7 +1155,7 @@ TEST_P(QuicPacketCreatorTest, SerializePathResponseProbePacket3PayloadsPadded) {
payloads.push_back(payload1);
payloads.push_back(payload2);
- OwningSerializedPacketPointer encrypted(
+ std::unique_ptr<SerializedPacket> encrypted(
creator_.SerializePathResponseConnectivityProbingPacket(payloads,
true));
{
@@ -1208,7 +1195,7 @@ TEST_P(QuicPacketCreatorTest,
payloads.push_back(payload1);
payloads.push_back(payload2);
- OwningSerializedPacketPointer encrypted(
+ std::unique_ptr<SerializedPacket> encrypted(
creator_.SerializePathResponseConnectivityProbingPacket(payloads,
false));
InSequence s;
@@ -1361,7 +1348,6 @@ TEST_P(QuicPacketCreatorTest, SerializeFrame) {
}
ProcessPacket(serialized);
EXPECT_EQ(GetParam().version_serialization, header.version_flag);
- DeleteFrames(&frames_);
}
TEST_P(QuicPacketCreatorTest, SerializeFrameShortData) {
@@ -1402,7 +1388,6 @@ TEST_P(QuicPacketCreatorTest, SerializeFrameShortData) {
}
ProcessPacket(serialized);
EXPECT_EQ(GetParam().version_serialization, header.version_flag);
- DeleteFrames(&frames_);
}
TEST_P(QuicPacketCreatorTest, ConsumeDataLargerThanOneStreamFrame) {
@@ -1488,13 +1473,14 @@ TEST_P(QuicPacketCreatorTest, AddFrameAndFlush) {
EXPECT_FALSE(creator_.AddFrame(QuicFrame(&ack_frame), NOT_RETRANSMISSION));
// Ensure the packet is successfully created.
- ASSERT_TRUE(serialized_packet_.encrypted_buffer);
- ASSERT_FALSE(serialized_packet_.retransmittable_frames.empty());
- const QuicFrames& retransmittable = serialized_packet_.retransmittable_frames;
+ ASSERT_TRUE(serialized_packet_->encrypted_buffer);
+ ASSERT_FALSE(serialized_packet_->retransmittable_frames.empty());
+ const QuicFrames& retransmittable =
+ serialized_packet_->retransmittable_frames;
ASSERT_EQ(1u, retransmittable.size());
EXPECT_EQ(STREAM_FRAME, retransmittable[0].type);
- EXPECT_TRUE(serialized_packet_.has_ack);
- EXPECT_EQ(QuicPacketNumber(10u), serialized_packet_.largest_acked);
+ EXPECT_TRUE(serialized_packet_->has_ack);
+ EXPECT_EQ(QuicPacketNumber(10u), serialized_packet_->largest_acked);
DeleteSerializedPacket();
EXPECT_FALSE(creator_.HasPendingFrames());
@@ -1533,9 +1519,10 @@ TEST_P(QuicPacketCreatorTest, SerializeAndSendStreamFrame) {
EXPECT_EQ(4u, num_bytes_consumed);
// Ensure the packet is successfully created.
- ASSERT_TRUE(serialized_packet_.encrypted_buffer);
- ASSERT_FALSE(serialized_packet_.retransmittable_frames.empty());
- const QuicFrames& retransmittable = serialized_packet_.retransmittable_frames;
+ ASSERT_TRUE(serialized_packet_->encrypted_buffer);
+ ASSERT_FALSE(serialized_packet_->retransmittable_frames.empty());
+ const QuicFrames& retransmittable =
+ serialized_packet_->retransmittable_frames;
ASSERT_EQ(1u, retransmittable.size());
EXPECT_EQ(STREAM_FRAME, retransmittable[0].type);
DeleteSerializedPacket();
@@ -1565,8 +1552,8 @@ TEST_P(QuicPacketCreatorTest, SerializeStreamFrameWithPadding) {
EXPECT_EQ(1u, num_bytes_consumed);
// Check that a packet is created.
- ASSERT_TRUE(serialized_packet_.encrypted_buffer);
- ASSERT_FALSE(serialized_packet_.retransmittable_frames.empty());
+ ASSERT_TRUE(serialized_packet_->encrypted_buffer);
+ ASSERT_FALSE(serialized_packet_->retransmittable_frames.empty());
{
InSequence s;
EXPECT_CALL(framer_visitor_, OnPacket());
@@ -1580,7 +1567,7 @@ TEST_P(QuicPacketCreatorTest, SerializeStreamFrameWithPadding) {
}
EXPECT_CALL(framer_visitor_, OnPacketComplete());
}
- ProcessPacket(serialized_packet_);
+ ProcessPacket(*serialized_packet_);
}
TEST_P(QuicPacketCreatorTest, AddUnencryptedStreamDataClosesConnection) {
@@ -1669,7 +1656,7 @@ TEST_P(QuicPacketCreatorTest, PendingPadding) {
EXPECT_CALL(framer_visitor_, OnPacketComplete());
}
// Packet only contains padding.
- ProcessPacket(serialized_packet_);
+ ProcessPacket(*serialized_packet_);
}
EXPECT_EQ(0u, creator_.pending_padding_bytes());
}
@@ -1751,9 +1738,8 @@ TEST_P(QuicPacketCreatorTest, FlushWithExternalBuffer) {
/*needs_full_padding=*/true, NOT_RETRANSMISSION, &frame));
EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .WillOnce(Invoke([expected_buffer](SerializedPacket* serialized_packet) {
- EXPECT_EQ(expected_buffer, serialized_packet->encrypted_buffer);
- ClearSerializedPacket(serialized_packet);
+ .WillOnce(Invoke([expected_buffer](SerializedPacket serialized_packet) {
+ EXPECT_EQ(expected_buffer, serialized_packet.encrypted_buffer);
}));
creator_.FlushCurrentPacket();
}
@@ -1775,6 +1761,9 @@ TEST_P(QuicPacketCreatorTest, AddMessageFrame) {
if (!VersionSupportsMessageFrames(client_framer_.transport_version())) {
return;
}
+ if (client_framer_.version().UsesTls()) {
+ creator_.SetMaxDatagramFrameSize(kMaxAcceptedDatagramFrameSize);
+ }
creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE);
EXPECT_CALL(delegate_, OnSerializedPacket(_))
.Times(3)
@@ -1827,6 +1816,9 @@ TEST_P(QuicPacketCreatorTest, MessageFrameConsumption) {
if (!VersionSupportsMessageFrames(client_framer_.transport_version())) {
return;
}
+ if (client_framer_.version().UsesTls()) {
+ creator_.SetMaxDatagramFrameSize(kMaxAcceptedDatagramFrameSize);
+ }
std::string message_data(kDefaultMaxPacketSize, 'a');
quiche::QuicheStringPiece message_buffer(message_data);
QuicMemSliceStorage storage(nullptr, 0, nullptr, 0);
@@ -1862,27 +1854,99 @@ TEST_P(QuicPacketCreatorTest, MessageFrameConsumption) {
EXPECT_CALL(delegate_, OnSerializedPacket(_))
.WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
creator_.FlushCurrentPacket();
- ASSERT_TRUE(serialized_packet_.encrypted_buffer);
+ ASSERT_TRUE(serialized_packet_->encrypted_buffer);
DeleteSerializedPacket();
}
}
}
-// Regression test for bugfix of GetPacketHeaderSize.
TEST_P(QuicPacketCreatorTest, GetGuaranteedLargestMessagePayload) {
- QuicTransportVersion version = creator_.transport_version();
- if (!VersionSupportsMessageFrames(version)) {
+ ParsedQuicVersion version = GetParam().version;
+ if (!version.SupportsMessageFrames()) {
return;
}
+ if (version.UsesTls()) {
+ creator_.SetMaxDatagramFrameSize(kMaxAcceptedDatagramFrameSize);
+ }
QuicPacketLength expected_largest_payload = 1319;
- if (QuicVersionHasLongHeaderLengths(version)) {
+ if (version.HasLongHeaderLengths()) {
expected_largest_payload -= 2;
}
- if (GetParam().version.HasLengthPrefixedConnectionIds()) {
+ if (version.HasLengthPrefixedConnectionIds()) {
expected_largest_payload -= 1;
}
EXPECT_EQ(expected_largest_payload,
creator_.GetGuaranteedLargestMessagePayload());
+ EXPECT_TRUE(creator_.HasRoomForMessageFrame(
+ creator_.GetGuaranteedLargestMessagePayload()));
+
+ // Now test whether SetMaxDatagramFrameSize works.
+ creator_.SetMaxDatagramFrameSize(expected_largest_payload + 1 +
+ kQuicFrameTypeSize);
+ EXPECT_EQ(expected_largest_payload,
+ creator_.GetGuaranteedLargestMessagePayload());
+ EXPECT_TRUE(creator_.HasRoomForMessageFrame(
+ creator_.GetGuaranteedLargestMessagePayload()));
+
+ creator_.SetMaxDatagramFrameSize(expected_largest_payload +
+ kQuicFrameTypeSize);
+ EXPECT_EQ(expected_largest_payload,
+ creator_.GetGuaranteedLargestMessagePayload());
+ EXPECT_TRUE(creator_.HasRoomForMessageFrame(
+ creator_.GetGuaranteedLargestMessagePayload()));
+
+ creator_.SetMaxDatagramFrameSize(expected_largest_payload - 1 +
+ kQuicFrameTypeSize);
+ EXPECT_EQ(expected_largest_payload - 1,
+ creator_.GetGuaranteedLargestMessagePayload());
+ EXPECT_TRUE(creator_.HasRoomForMessageFrame(
+ creator_.GetGuaranteedLargestMessagePayload()));
+
+ constexpr QuicPacketLength kFrameSizeLimit = 1000;
+ constexpr QuicPacketLength kPayloadSizeLimit =
+ kFrameSizeLimit - kQuicFrameTypeSize;
+ creator_.SetMaxDatagramFrameSize(kFrameSizeLimit);
+ EXPECT_EQ(creator_.GetGuaranteedLargestMessagePayload(), kPayloadSizeLimit);
+ EXPECT_TRUE(creator_.HasRoomForMessageFrame(kPayloadSizeLimit));
+ EXPECT_FALSE(creator_.HasRoomForMessageFrame(kPayloadSizeLimit + 1));
+}
+
+TEST_P(QuicPacketCreatorTest, GetCurrentLargestMessagePayload) {
+ ParsedQuicVersion version = GetParam().version;
+ if (!version.SupportsMessageFrames()) {
+ return;
+ }
+ if (version.UsesTls()) {
+ creator_.SetMaxDatagramFrameSize(kMaxAcceptedDatagramFrameSize);
+ }
+ QuicPacketLength expected_largest_payload = 1319;
+ if (version.SendsVariableLengthPacketNumberInLongHeader()) {
+ expected_largest_payload += 3;
+ }
+ if (version.HasLongHeaderLengths()) {
+ expected_largest_payload -= 2;
+ }
+ if (version.HasLengthPrefixedConnectionIds()) {
+ expected_largest_payload -= 1;
+ }
+ EXPECT_EQ(expected_largest_payload,
+ creator_.GetCurrentLargestMessagePayload());
+
+ // Now test whether SetMaxDatagramFrameSize works.
+ creator_.SetMaxDatagramFrameSize(expected_largest_payload + 1 +
+ kQuicFrameTypeSize);
+ EXPECT_EQ(expected_largest_payload,
+ creator_.GetCurrentLargestMessagePayload());
+
+ creator_.SetMaxDatagramFrameSize(expected_largest_payload +
+ kQuicFrameTypeSize);
+ EXPECT_EQ(expected_largest_payload,
+ creator_.GetCurrentLargestMessagePayload());
+
+ creator_.SetMaxDatagramFrameSize(expected_largest_payload - 1 +
+ kQuicFrameTypeSize);
+ EXPECT_EQ(expected_largest_payload - 1,
+ creator_.GetCurrentLargestMessagePayload());
}
TEST_P(QuicPacketCreatorTest, PacketTransmissionType) {
@@ -1906,18 +1970,18 @@ TEST_P(QuicPacketCreatorTest, PacketTransmissionType) {
.WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
EXPECT_TRUE(creator_.AddFrame(ack_frame, LOSS_RETRANSMISSION));
- ASSERT_FALSE(serialized_packet_.encrypted_buffer);
+ ASSERT_EQ(serialized_packet_, nullptr);
EXPECT_TRUE(creator_.AddFrame(stream_frame, RTO_RETRANSMISSION));
- ASSERT_FALSE(serialized_packet_.encrypted_buffer);
+ ASSERT_EQ(serialized_packet_, nullptr);
EXPECT_TRUE(creator_.AddFrame(padding_frame, TLP_RETRANSMISSION));
creator_.FlushCurrentPacket();
- ASSERT_TRUE(serialized_packet_.encrypted_buffer);
+ ASSERT_TRUE(serialized_packet_->encrypted_buffer);
// 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);
+ EXPECT_EQ(serialized_packet_->transmission_type, RTO_RETRANSMISSION);
DeleteSerializedPacket();
}
@@ -1972,7 +2036,6 @@ TEST_P(QuicPacketCreatorTest, RetryToken) {
quiche::test::CompareCharArraysWithHexError(
"retry token", header.retry_token.data(), header.retry_token.length(),
retry_token_bytes, sizeof(retry_token_bytes));
- DeleteFrames(&frames_);
}
TEST_P(QuicPacketCreatorTest, GetConnectionId) {
@@ -2068,7 +2131,7 @@ TEST_P(QuicPacketCreatorTest, CoalesceStreamFrames) {
EXPECT_CALL(framer_visitor_, OnStreamFrame(_));
EXPECT_CALL(framer_visitor_, OnStreamFrame(_));
EXPECT_CALL(framer_visitor_, OnPacketComplete());
- ProcessPacket(serialized_packet_);
+ ProcessPacket(*serialized_packet_);
}
TEST_P(QuicPacketCreatorTest, SaveNonRetransmittableFrames) {
@@ -2186,6 +2249,9 @@ TEST_P(QuicPacketCreatorTest, SoftMaxPacketLength) {
// Same for message frame.
if (VersionSupportsMessageFrames(client_framer_.transport_version())) {
creator_.SetSoftMaxPacketLength(overhead);
+ if (client_framer_.version().UsesTls()) {
+ creator_.SetMaxDatagramFrameSize(kMaxAcceptedDatagramFrameSize);
+ }
// Verify GetCurrentLargestMessagePayload is based on the actual
// max_packet_length.
EXPECT_LT(1u, creator_.GetCurrentLargestMessagePayload());
@@ -2237,13 +2303,20 @@ class MockDelegate : public QuicPacketCreator::DelegateInterface {
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&));
+ MOCK_METHOD(bool,
+ ShouldGeneratePacket,
+ (HasRetransmittableData retransmittable, IsHandshake handshake),
+ (override));
+ MOCK_METHOD(const QuicFrames,
+ MaybeBundleAckOpportunistically,
+ (),
+ (override));
+ MOCK_METHOD(char*, GetPacketBuffer, (), (override));
+ MOCK_METHOD(void, OnSerializedPacket, (SerializedPacket), (override));
+ MOCK_METHOD(void,
+ OnUnrecoverableError,
+ (QuicErrorCode, const std::string&),
+ (override));
void SetCanWriteAnything() {
EXPECT_CALL(*this, ShouldGeneratePacket(_, _)).WillRepeatedly(Return(true));
@@ -2407,18 +2480,13 @@ class QuicPacketCreatorMultiplePacketsTest : public QuicTest {
creator_.AttachPacketFlusher();
}
- ~QuicPacketCreatorMultiplePacketsTest() override {
- for (SerializedPacket& packet : packets_) {
- delete[] packet.encrypted_buffer;
- ClearSerializedPacket(&packet);
- }
- }
+ ~QuicPacketCreatorMultiplePacketsTest() override {}
- void SavePacket(SerializedPacket* packet) {
- packet->encrypted_buffer = CopyBuffer(*packet);
- packets_.push_back(*packet);
- packet->encrypted_buffer = nullptr;
- packet->retransmittable_frames.clear();
+ void SavePacket(SerializedPacket packet) {
+ DCHECK(packet.release_encrypted_buffer == nullptr);
+ packet.encrypted_buffer = CopyBuffer(packet);
+ packet.release_encrypted_buffer = [](const char* p) { delete[] p; };
+ packets_.push_back(std::move(packet));
}
protected:
@@ -2903,7 +2971,7 @@ TEST_F(QuicPacketCreatorMultiplePacketsTest, ConsumeDataFastPath) {
contents.num_stream_frames = 1;
CheckPacketContains(contents, 0);
EXPECT_FALSE(packets_.empty());
- SerializedPacket packet = packets_.back();
+ 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);
@@ -2933,7 +3001,7 @@ TEST_F(QuicPacketCreatorMultiplePacketsTest, ConsumeDataLarge) {
contents.num_stream_frames = 1;
CheckPacketContains(contents, 0);
EXPECT_FALSE(packets_.empty());
- SerializedPacket packet = packets_.back();
+ SerializedPacket& packet = packets_.back();
EXPECT_TRUE(!packet.retransmittable_frames.empty());
EXPECT_EQ(STREAM_FRAME, packet.retransmittable_frames.front().type);
const QuicStreamFrame& stream_frame =
@@ -2976,7 +3044,7 @@ TEST_F(QuicPacketCreatorMultiplePacketsTest, ConsumeDataLargeSendAckFalse) {
EXPECT_FALSE(creator_.HasPendingRetransmittableFrames());
EXPECT_FALSE(packets_.empty());
- SerializedPacket packet = packets_.back();
+ SerializedPacket& packet = packets_.back();
EXPECT_TRUE(!packet.retransmittable_frames.empty());
EXPECT_EQ(STREAM_FRAME, packet.retransmittable_frames.front().type);
const QuicStreamFrame& stream_frame =
@@ -3005,7 +3073,7 @@ TEST_F(QuicPacketCreatorMultiplePacketsTest, ConsumeDataLargeSendAckTrue) {
EXPECT_FALSE(creator_.HasPendingRetransmittableFrames());
EXPECT_FALSE(packets_.empty());
- SerializedPacket packet = packets_.back();
+ SerializedPacket& packet = packets_.back();
EXPECT_TRUE(!packet.retransmittable_frames.empty());
EXPECT_EQ(STREAM_FRAME, packet.retransmittable_frames.front().type);
const QuicStreamFrame& stream_frame =
@@ -3352,7 +3420,7 @@ TEST_F(QuicPacketCreatorMultiplePacketsTest,
GenerateConnectivityProbingPacket) {
delegate_.SetCanWriteAnything();
- OwningSerializedPacketPointer probing_packet;
+ std::unique_ptr<SerializedPacket> probing_packet;
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
QuicPathFrameBuffer payload = {
{0xde, 0xad, 0xbe, 0xef, 0xba, 0xdc, 0x0f, 0xfe}};
@@ -3667,6 +3735,9 @@ TEST_F(QuicPacketCreatorMultiplePacketsTest, AddMessageFrame) {
if (!VersionSupportsMessageFrames(framer_.transport_version())) {
return;
}
+ if (framer_.version().UsesTls()) {
+ creator_.SetMaxDatagramFrameSize(kMaxAcceptedDatagramFrameSize);
+ }
quic::QuicMemSliceStorage storage(nullptr, 0, nullptr, 0);
delegate_.SetCanWriteAnything();
EXPECT_CALL(delegate_, OnSerializedPacket(_))
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packet_writer.h b/chromium/net/third_party/quiche/src/quic/core/quic_packet_writer.h
index bd10523e16a..ab29e15aa88 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_packet_writer.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_packet_writer.h
@@ -28,8 +28,10 @@ struct QUIC_EXPORT_PRIVATE PerPacketOptions {
// would not forget to override it.
virtual std::unique_ptr<PerPacketOptions> Clone() const = 0;
- // Specifies release time delay for this packet.
+ // Specifies ideal release time delay for this packet.
QuicTime::Delta release_time_delay = QuicTime::Delta::Zero();
+ // Whether it is allowed to send this packet without |release_time_delay|.
+ bool allow_burst = false;
};
// An interface between writers and the entity managing the
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 4123c27f94c..69575b99935 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
@@ -465,15 +465,8 @@ SerializedPacket::SerializedPacket(QuicPacketNumber packet_number,
transmission_type(NOT_RETRANSMISSION),
has_ack_frame_copy(false) {}
-SerializedPacket::SerializedPacket(const SerializedPacket& other) = default;
-
-SerializedPacket& SerializedPacket::operator=(const SerializedPacket& other) =
- default;
-
SerializedPacket::SerializedPacket(SerializedPacket&& other)
- : encrypted_buffer(other.encrypted_buffer),
- encrypted_length(other.encrypted_length),
- has_crypto_handshake(other.has_crypto_handshake),
+ : has_crypto_handshake(other.has_crypto_handshake),
num_padding_bytes(other.num_padding_bytes),
packet_number(other.packet_number),
packet_number_length(other.packet_number_length),
@@ -483,23 +476,58 @@ SerializedPacket::SerializedPacket(SerializedPacket&& other)
transmission_type(other.transmission_type),
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);
+ if (this != &other) {
+ if (release_encrypted_buffer && encrypted_buffer != nullptr) {
+ release_encrypted_buffer(encrypted_buffer);
+ }
+ encrypted_buffer = other.encrypted_buffer;
+ encrypted_length = other.encrypted_length;
+ release_encrypted_buffer = std::move(other.release_encrypted_buffer);
+ other.release_encrypted_buffer = nullptr;
+
+ retransmittable_frames.swap(other.retransmittable_frames);
+ nonretransmittable_frames.swap(other.nonretransmittable_frames);
+ }
}
-SerializedPacket::~SerializedPacket() {}
+SerializedPacket::~SerializedPacket() {
+ if (release_encrypted_buffer && encrypted_buffer != nullptr) {
+ release_encrypted_buffer(encrypted_buffer);
+ }
+
+ if (!retransmittable_frames.empty()) {
+ DeleteFrames(&retransmittable_frames);
+ }
+ for (auto& frame : nonretransmittable_frames) {
+ if (!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);
+ }
+}
SerializedPacket* CopySerializedPacket(const SerializedPacket& serialized,
QuicBufferAllocator* allocator,
bool copy_buffer) {
- SerializedPacket* copy = new SerializedPacket(serialized);
+ SerializedPacket* copy = new SerializedPacket(
+ serialized.packet_number, serialized.packet_number_length,
+ serialized.encrypted_buffer, serialized.encrypted_length,
+ serialized.has_ack, serialized.has_stop_waiting);
+ copy->has_crypto_handshake = serialized.has_crypto_handshake;
+ copy->num_padding_bytes = serialized.num_padding_bytes;
+ copy->encryption_level = serialized.encryption_level;
+ copy->transmission_type = serialized.transmission_type;
+ copy->largest_acked = serialized.largest_acked;
+
if (copy_buffer) {
copy->encrypted_buffer = CopyBuffer(serialized);
+ copy->release_encrypted_buffer = [](const char* p) { delete[] p; };
}
// Copy underlying frames.
copy->retransmittable_frames =
CopyQuicFrames(allocator, serialized.retransmittable_frames);
- copy->nonretransmittable_frames.clear();
+ DCHECK(copy->nonretransmittable_frames.empty());
for (const auto& frame : serialized.nonretransmittable_frames) {
if (frame.type == ACK_FRAME) {
copy->has_ack_frame_copy = true;
@@ -509,27 +537,8 @@ SerializedPacket* CopySerializedPacket(const SerializedPacket& serialized,
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();
-}
-
char* CopyBuffer(const SerializedPacket& packet) {
- char* dst_buffer = new char[packet.encrypted_length];
- memcpy(dst_buffer, packet.encrypted_buffer, packet.encrypted_length);
- return dst_buffer;
+ return CopyBuffer(packet.encrypted_buffer, packet.encrypted_length);
}
char* CopyBuffer(const char* encrypted_buffer,
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 e8e1931b975..04522e8538b 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
@@ -357,6 +357,13 @@ class QUIC_EXPORT_PRIVATE QuicReceivedPacket : public QuicEncryptedPacket {
bool owns_header_buffer_;
};
+// SerializedPacket contains information of a serialized(encrypted) packet.
+//
+// WARNING:
+//
+// If you add a member field to this class, please make sure it is properly
+// copied in |CopySerializedPacket|.
+//
struct QUIC_EXPORT_PRIVATE SerializedPacket {
SerializedPacket(QuicPacketNumber packet_number,
QuicPacketNumberLength packet_number_length,
@@ -364,14 +371,20 @@ struct QUIC_EXPORT_PRIVATE SerializedPacket {
QuicPacketLength encrypted_length,
bool has_ack,
bool has_stop_waiting);
- SerializedPacket(const SerializedPacket& other);
- SerializedPacket& operator=(const SerializedPacket& other);
+
+ // Copy constructor & assignment are deleted. Use |CopySerializedPacket| to
+ // make a copy.
+ SerializedPacket(const SerializedPacket& other) = delete;
+ SerializedPacket& operator=(const SerializedPacket& other) = delete;
SerializedPacket(SerializedPacket&& other);
~SerializedPacket();
- // Not owned.
+ // Not owned if |release_encrypted_buffer| is nullptr. Otherwise it is
+ // released by |release_encrypted_buffer| on destruction.
const char* encrypted_buffer;
QuicPacketLength encrypted_length;
+ std::function<void(const char*)> release_encrypted_buffer;
+
QuicFrames retransmittable_frames;
QuicFrames nonretransmittable_frames;
IsHandshake has_crypto_handshake;
@@ -401,10 +414,6 @@ QUIC_EXPORT_PRIVATE SerializedPacket* CopySerializedPacket(
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);
-
// Allocates a new char[] of size |packet.encrypted_length| and copies in
// |packet.encrypted_buffer|.
QUIC_EXPORT_PRIVATE char* CopyBuffer(const SerializedPacket& packet);
@@ -413,21 +422,6 @@ QUIC_EXPORT_PRIVATE char* CopyBuffer(const SerializedPacket& packet);
QUIC_EXPORT_PRIVATE char* CopyBuffer(const char* encrypted_buffer,
QuicPacketLength encrypted_length);
-struct QUIC_EXPORT_PRIVATE SerializedPacketDeleter {
- void operator()(SerializedPacket* packet) {
- if (packet->encrypted_buffer != nullptr) {
- delete[] packet->encrypted_buffer;
- }
- delete packet;
- }
-};
-
-// On destruction, OwningSerializedPacketPointer deletes a packet's (on-heap)
-// encrypted_buffer before deleting the (also on-heap) packet itself.
-// TODO(wub): Maybe delete retransmittable_frames too?
-typedef std::unique_ptr<SerializedPacket, SerializedPacketDeleter>
- OwningSerializedPacketPointer;
-
// Context for an incoming packet.
struct QUIC_EXPORT_PRIVATE QuicPerPacketContext {
virtual ~QuicPerPacketContext() {}
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 1ccaabc0a32..b2bccbeeb72 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
@@ -106,10 +106,6 @@ TEST_F(QuicPacketsTest, CopySerializedPacket) {
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
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 0de1dadf17c..92401b0db72 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
@@ -77,7 +77,7 @@ QuicSentPacketManager::QuicSentPacketManager(
debug_delegate_(nullptr),
network_change_visitor_(nullptr),
initial_congestion_window_(kInitialCongestionWindow),
- loss_algorithm_(GetInitialLossAlgorithm()),
+ loss_algorithm_(&uber_loss_algorithm_),
consecutive_rto_count_(0),
consecutive_tlp_count_(0),
consecutive_crypto_retransmission_count_(0),
@@ -98,7 +98,7 @@ QuicSentPacketManager::QuicSentPacketManager(
QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs)),
rtt_updated_(false),
acked_packets_iter_(last_ack_frame_.packets.rbegin()),
- pto_enabled_(false),
+ pto_enabled_(GetQuicReloadableFlag(quic_default_on_pto)),
max_probe_packets_per_pto_(2),
consecutive_pto_count_(0),
handshake_mode_disabled_(false),
@@ -112,10 +112,13 @@ QuicSentPacketManager::QuicSentPacketManager(
first_pto_srtt_multiplier_(0),
use_standard_deviation_for_pto_(false) {
SetSendAlgorithm(congestion_control_type);
-}
-
-LossDetectionInterface* QuicSentPacketManager::GetInitialLossAlgorithm() {
- return &uber_loss_algorithm_;
+ if (pto_enabled_) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_default_on_pto, 1, 2);
+ // TODO(fayang): change the default values when deprecating
+ // quic_default_on_pto.
+ first_pto_srtt_multiplier_ = 1.5;
+ pto_rttvar_multiplier_ = 2;
+ }
}
QuicSentPacketManager::~QuicSentPacketManager() {}
@@ -191,21 +194,13 @@ void QuicSentPacketManager::SetFromConfig(const QuicConfig& config) {
QUIC_CODE_COUNT(two_aggressive_ptos);
num_tlp_timeout_ptos_ = 2;
}
- if (GetQuicReloadableFlag(quic_arm_pto_with_earliest_sent_time)) {
- if (config.HasClientSentConnectionOption(kPLE1, perspective) ||
- config.HasClientSentConnectionOption(kTLPR, perspective)) {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_arm_pto_with_earliest_sent_time, 1,
- 2);
- first_pto_srtt_multiplier_ = 0.5;
- } else if (config.HasClientSentConnectionOption(kPLE2, perspective)) {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_arm_pto_with_earliest_sent_time, 2,
- 2);
- first_pto_srtt_multiplier_ = 1.5;
- }
+ if (config.HasClientSentConnectionOption(kPLE1, perspective) ||
+ config.HasClientSentConnectionOption(kTLPR, perspective)) {
+ first_pto_srtt_multiplier_ = 0.5;
+ } else if (config.HasClientSentConnectionOption(kPLE2, perspective)) {
+ first_pto_srtt_multiplier_ = 1.5;
}
- if (GetQuicReloadableFlag(quic_use_standard_deviation_for_pto) &&
- config.HasClientSentConnectionOption(kPSDA, perspective)) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_use_standard_deviation_for_pto);
+ if (config.HasClientSentConnectionOption(kPSDA, perspective)) {
use_standard_deviation_for_pto_ = true;
rtt_stats_.EnableStandardDeviationCalculation();
}
@@ -227,9 +222,6 @@ void QuicSentPacketManager::SetFromConfig(const QuicConfig& config) {
(GetQuicReloadableFlag(quic_default_to_bbr) &&
config.HasClientRequestedIndependentOption(kQBIC, perspective))) {
SetSendAlgorithm(kCubicBytes);
- } else if (GetQuicReloadableFlag(quic_enable_pcc3) &&
- config.HasClientRequestedIndependentOption(kTPCC, perspective)) {
- SetSendAlgorithm(kPCC);
}
// Initial window.
@@ -296,23 +288,25 @@ void QuicSentPacketManager::SetFromConfig(const QuicConfig& config) {
uber_loss_algorithm_.EnableAdaptiveReorderingThreshold();
uber_loss_algorithm_.EnableAdaptiveTimeThreshold();
}
- if (GetQuicReloadableFlag(
- quic_skip_packet_threshold_loss_detection_with_runt) &&
- config.HasClientRequestedIndependentOption(kRUNT, perspective)) {
- QUIC_RELOADABLE_FLAG_COUNT_N(
- quic_skip_packet_threshold_loss_detection_with_runt, 1, 2);
+ if (config.HasClientRequestedIndependentOption(kRUNT, perspective)) {
uber_loss_algorithm_.DisablePacketThresholdForRuntPackets();
}
if (config.HasClientSentConnectionOption(kCONH, perspective)) {
conservative_handshake_retransmits_ = true;
}
send_algorithm_->SetFromConfig(config, perspective);
+ loss_algorithm_->SetFromConfig(config, perspective);
if (network_change_visitor_ != nullptr) {
network_change_visitor_->OnCongestionChange();
}
}
+void QuicSentPacketManager::ApplyConnectionOptions(
+ const QuicTagVector& connection_options) {
+ send_algorithm_->ApplyConnectionOptions(connection_options);
+}
+
void QuicSentPacketManager::ResumeConnectionState(
const CachedNetworkParameters& cached_network_params,
bool max_bandwidth_resumption) {
@@ -345,8 +339,8 @@ void QuicSentPacketManager::AdjustNetworkParameters(
send_algorithm_->AdjustNetworkParameters(params);
if (debug_delegate_ != nullptr) {
debug_delegate_->OnAdjustNetworkParameters(
- bandwidth, rtt.IsZero() ? rtt_stats_.SmoothedOrInitialRtt() : rtt,
- old_cwnd, send_algorithm_->GetCongestionWindow());
+ bandwidth, rtt.IsZero() ? rtt_stats_.MinOrInitialRtt() : rtt, old_cwnd,
+ send_algorithm_->GetCongestionWindow());
}
}
@@ -862,8 +856,9 @@ void QuicSentPacketManager::MaybeSendProbePackets() {
// Find out the packet number space to send probe packets.
if (!GetEarliestPacketSentTimeForPto(&packet_number_space)
.IsInitialized()) {
- QUIC_BUG << "earlist_sent_time not initialized when trying to send PTO "
- "retransmissions";
+ QUIC_BUG_IF(unacked_packets_.perspective() == Perspective::IS_SERVER)
+ << "earlist_sent_time not initialized when trying to send PTO "
+ "retransmissions";
return;
}
}
@@ -903,6 +898,12 @@ void QuicSentPacketManager::AdjustPendingTimerTransmissions() {
}
void QuicSentPacketManager::EnableIetfPtoAndLossDetection() {
+ if (pto_enabled_) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_default_on_pto, 2, 2);
+ // Disable handshake mode.
+ handshake_mode_disabled_ = true;
+ return;
+ }
pto_enabled_ = true;
handshake_mode_disabled_ = true;
// Default to 1 packet per PTO and skip a packet number. Arm the 1st PTO with
@@ -946,9 +947,17 @@ void QuicSentPacketManager::InvokeLossDetection(QuicTime time) {
packets_acked_.back().packet_number);
largest_newly_acked_ = packets_acked_.back().packet_number;
}
- loss_algorithm_->DetectLosses(unacked_packets_, time, rtt_stats_,
- largest_newly_acked_, packets_acked_,
- &packets_lost_);
+ LossDetectionInterface::DetectionStats detection_stats =
+ loss_algorithm_->DetectLosses(unacked_packets_, time, rtt_stats_,
+ largest_newly_acked_, packets_acked_,
+ &packets_lost_);
+
+ if (detection_stats.sent_packets_max_sequence_reordering >
+ stats_->sent_packets_max_sequence_reordering) {
+ stats_->sent_packets_max_sequence_reordering =
+ detection_stats.sent_packets_max_sequence_reordering;
+ }
+
for (const LostPacket& packet : packets_lost_) {
QuicTransmissionInfo* info =
unacked_packets_.GetMutableTransmissionInfo(packet.packet_number);
@@ -1085,8 +1094,12 @@ const QuicTime QuicSentPacketManager::GetRetransmissionTime() const {
PacketNumberSpace packet_number_space = NUM_PACKET_NUMBER_SPACES;
// earliest_right_edge is the earliest sent time of the last in flight
// packet of all packet number spaces.
- const QuicTime earliest_right_edge =
+ QuicTime earliest_right_edge =
GetEarliestPacketSentTimeForPto(&packet_number_space);
+ if (!earliest_right_edge.IsInitialized()) {
+ // Arm PTO from now if there is no in flight packets.
+ earliest_right_edge = clock_->ApproximateNow();
+ }
if (first_pto_srtt_multiplier_ > 0 &&
packet_number_space == APPLICATION_DATA &&
consecutive_pto_count_ == 0) {
@@ -1187,10 +1200,11 @@ const QuicTime::Delta QuicSentPacketManager::GetRetransmissionDelay() const {
const QuicTime::Delta QuicSentPacketManager::GetProbeTimeoutDelay() const {
DCHECK(pto_enabled_);
if (rtt_stats_.smoothed_rtt().IsZero()) {
- if (rtt_stats_.initial_rtt().IsZero()) {
- return QuicTime::Delta::FromSeconds(1);
- }
- return 2 * rtt_stats_.initial_rtt();
+ // Respect kMinHandshakeTimeoutMs to avoid a potential amplification attack.
+ QUIC_BUG_IF(rtt_stats_.initial_rtt().IsZero());
+ return std::max(3 * rtt_stats_.initial_rtt(),
+ QuicTime::Delta::FromMilliseconds(kMinHandshakeTimeoutMs)) *
+ (1 << consecutive_pto_count_);
}
const QuicTime::Delta rtt_var = use_standard_deviation_for_pto_
? rtt_stats_.GetStandardOrMeanDeviation()
@@ -1411,9 +1425,12 @@ void QuicSentPacketManager::OnApplicationLimited() {
}
}
-QuicTime QuicSentPacketManager::GetNextReleaseTime() const {
- return using_pacing_ ? pacing_sender_.ideal_next_packet_send_time()
- : QuicTime::Zero();
+NextReleaseTimeResult QuicSentPacketManager::GetNextReleaseTime() const {
+ if (!using_pacing_) {
+ return {QuicTime::Zero(), false};
+ }
+
+ return pacing_sender_.GetNextReleaseTime();
}
void QuicSentPacketManager::SetInitialRtt(QuicTime::Delta rtt) {
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 5f1de705bb3..371fa814537 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
@@ -120,6 +120,8 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager {
virtual void SetFromConfig(const QuicConfig& config);
+ void ApplyConnectionOptions(const QuicTagVector& connection_options);
+
// Pass the CachedNetworkParameters to the send algorithm.
void ResumeConnectionState(
const CachedNetworkParameters& cached_network_params,
@@ -339,7 +341,7 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager {
unacked_packets_.SetSessionNotifier(session_notifier);
}
- QuicTime GetNextReleaseTime() const;
+ NextReleaseTimeResult GetNextReleaseTime() const;
QuicPacketCount initial_congestion_window() const {
return initial_congestion_window_;
@@ -366,6 +368,10 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager {
return unacked_packets_;
}
+ const UberLossAlgorithm* uber_loss_algorithm() const {
+ return &uber_loss_algorithm_;
+ }
+
// Sets the send algorithm to the given congestion control type and points the
// pacing sender at |send_algorithm_|. Can be called any number of times.
void SetSendAlgorithm(CongestionControlType congestion_control_type);
@@ -490,9 +496,6 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager {
// Sets the initial RTT of the connection.
void SetInitialRtt(QuicTime::Delta rtt);
- // Should only be called from constructor.
- LossDetectionInterface* GetInitialLossAlgorithm();
-
// Called when handshake is confirmed to remove the retransmittable frames
// from all packets of HANDSHAKE_DATA packet number space to ensure they don't
// get retransmitted and will eventually be removed from unacked packets map.
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 98e6af0cfea..79fc798568b 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
@@ -43,14 +43,17 @@ MATCHER(PacketNumberEq, "") {
class MockDebugDelegate : public QuicSentPacketManager::DebugDelegate {
public:
- MOCK_METHOD2(OnSpuriousPacketRetransmission,
- void(TransmissionType transmission_type,
- QuicByteCount byte_size));
- MOCK_METHOD4(OnPacketLoss,
- void(QuicPacketNumber lost_packet_number,
- EncryptionLevel encryption_level,
- TransmissionType transmission_type,
- QuicTime detection_time));
+ MOCK_METHOD(void,
+ OnSpuriousPacketRetransmission,
+ (TransmissionType transmission_type, QuicByteCount byte_size),
+ (override));
+ MOCK_METHOD(void,
+ OnPacketLoss,
+ (QuicPacketNumber lost_packet_number,
+ EncryptionLevel encryption_level,
+ TransmissionType transmission_type,
+ QuicTime detection_time),
+ (override));
};
class QuicSentPacketManagerTest : public QuicTest {
@@ -105,8 +108,6 @@ class QuicSentPacketManagerTest : public QuicTest {
EXPECT_CALL(*send_algorithm_, GetCongestionControlType())
.WillRepeatedly(Return(kInitialCongestionControlType));
- EXPECT_CALL(*send_algorithm_, HasReliableBandwidthEstimate())
- .Times(AnyNumber());
EXPECT_CALL(*send_algorithm_, BandwidthEstimate())
.Times(AnyNumber())
.WillRepeatedly(Return(QuicBandwidth::Zero()));
@@ -526,7 +527,6 @@ TEST_F(QuicSentPacketManagerTest,
// Since 1 has been retransmitted, it has already been lost, and so the
// send algorithm is not informed that it has been ACK'd.
ExpectUpdatedRtt(1);
- EXPECT_CALL(*send_algorithm_, RevertRetransmissionTimeout());
manager_.OnAckFrameStart(QuicPacketNumber(1), QuicTime::Delta::Infinite(),
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
@@ -622,6 +622,7 @@ TEST_F(QuicSentPacketManagerTest, RetransmitTwiceThenAckFirst) {
EXPECT_EQ(1u, stats_.packets_spuriously_retransmitted);
EXPECT_EQ(1u, stats_.packets_lost);
EXPECT_LT(QuicTime::Delta::Zero(), stats_.total_loss_detection_time);
+ EXPECT_LE(1u, stats_.sent_packets_max_sequence_reordering);
}
TEST_F(QuicSentPacketManagerTest, AckOriginalTransmission) {
@@ -826,6 +827,9 @@ TEST_F(QuicSentPacketManagerTest, RttZeroDelta) {
}
TEST_F(QuicSentPacketManagerTest, TailLossProbeTimeout) {
+ if (GetQuicReloadableFlag(quic_default_on_pto)) {
+ return;
+ }
QuicSentPacketManagerPeer::SetMaxTailLossProbes(&manager_, 2);
// Send 1 packet.
@@ -886,6 +890,9 @@ TEST_F(QuicSentPacketManagerTest, TailLossProbeTimeout) {
}
TEST_F(QuicSentPacketManagerTest, TailLossProbeThenRTO) {
+ if (GetQuicReloadableFlag(quic_default_on_pto)) {
+ return;
+ }
QuicSentPacketManagerPeer::SetMaxTailLossProbes(&manager_, 2);
// Send 100 packets.
@@ -1178,6 +1185,9 @@ TEST_F(QuicSentPacketManagerTest,
}
TEST_F(QuicSentPacketManagerTest, RetransmissionTimeout) {
+ if (GetQuicReloadableFlag(quic_default_on_pto)) {
+ return;
+ }
StrictMock<MockDebugDelegate> debug_delegate;
manager_.SetDebugDelegate(&debug_delegate);
@@ -1225,6 +1235,9 @@ TEST_F(QuicSentPacketManagerTest, RetransmissionTimeout) {
}
TEST_F(QuicSentPacketManagerTest, RetransmissionTimeoutOnePacket) {
+ if (GetQuicReloadableFlag(quic_default_on_pto)) {
+ return;
+ }
// Set the 1RTO connection option.
QuicConfig client_config;
QuicTagVector options;
@@ -1259,6 +1272,9 @@ TEST_F(QuicSentPacketManagerTest, RetransmissionTimeoutOnePacket) {
}
TEST_F(QuicSentPacketManagerTest, NewRetransmissionTimeout) {
+ if (GetQuicReloadableFlag(quic_default_on_pto)) {
+ return;
+ }
QuicConfig client_config;
QuicTagVector options;
options.push_back(kNRTO);
@@ -1311,6 +1327,9 @@ TEST_F(QuicSentPacketManagerTest, NewRetransmissionTimeout) {
}
TEST_F(QuicSentPacketManagerTest, TwoRetransmissionTimeoutsAckSecond) {
+ if (GetQuicReloadableFlag(quic_default_on_pto)) {
+ return;
+ }
// Send 1 packet.
SendDataPacket(1);
@@ -1342,6 +1361,9 @@ TEST_F(QuicSentPacketManagerTest, TwoRetransmissionTimeoutsAckSecond) {
}
TEST_F(QuicSentPacketManagerTest, TwoRetransmissionTimeoutsAckFirst) {
+ if (GetQuicReloadableFlag(quic_default_on_pto)) {
+ return;
+ }
// Send 1 packet.
SendDataPacket(1);
@@ -1462,6 +1484,9 @@ TEST_F(QuicSentPacketManagerTest,
}
TEST_F(QuicSentPacketManagerTest, GetTransmissionTimeTailLossProbe) {
+ if (GetQuicReloadableFlag(quic_default_on_pto)) {
+ return;
+ }
QuicSentPacketManagerPeer::SetMaxTailLossProbes(&manager_, 2);
SendDataPacket(1);
SendDataPacket(2);
@@ -1495,6 +1520,9 @@ TEST_F(QuicSentPacketManagerTest, GetTransmissionTimeTailLossProbe) {
}
TEST_F(QuicSentPacketManagerTest, TLPRWithPendingStreamData) {
+ if (GetQuicReloadableFlag(quic_default_on_pto)) {
+ return;
+ }
QuicConfig config;
QuicTagVector options;
@@ -1545,6 +1573,9 @@ TEST_F(QuicSentPacketManagerTest, TLPRWithPendingStreamData) {
}
TEST_F(QuicSentPacketManagerTest, TLPRWithoutPendingStreamData) {
+ if (GetQuicReloadableFlag(quic_default_on_pto)) {
+ return;
+ }
QuicConfig config;
QuicTagVector options;
@@ -1593,6 +1624,9 @@ TEST_F(QuicSentPacketManagerTest, TLPRWithoutPendingStreamData) {
}
TEST_F(QuicSentPacketManagerTest, GetTransmissionTimeSpuriousRTO) {
+ if (GetQuicReloadableFlag(quic_default_on_pto)) {
+ return;
+ }
RttStats* rtt_stats = const_cast<RttStats*>(manager_.GetRttStats());
rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(100),
QuicTime::Delta::Zero(), QuicTime::Zero());
@@ -1648,6 +1682,9 @@ TEST_F(QuicSentPacketManagerTest, GetTransmissionTimeSpuriousRTO) {
}
TEST_F(QuicSentPacketManagerTest, GetTransmissionDelayMin) {
+ if (GetQuicReloadableFlag(quic_default_on_pto)) {
+ return;
+ }
SendDataPacket(1);
// Provide a 1ms RTT sample.
const_cast<RttStats*>(manager_.GetRttStats())
@@ -1670,6 +1707,9 @@ TEST_F(QuicSentPacketManagerTest, GetTransmissionDelayMin) {
}
TEST_F(QuicSentPacketManagerTest, GetTransmissionDelayMax) {
+ if (GetQuicReloadableFlag(quic_default_on_pto)) {
+ return;
+ }
SendDataPacket(1);
// Provide a 60s RTT sample.
const_cast<RttStats*>(manager_.GetRttStats())
@@ -1681,6 +1721,9 @@ TEST_F(QuicSentPacketManagerTest, GetTransmissionDelayMax) {
}
TEST_F(QuicSentPacketManagerTest, GetTransmissionDelayExponentialBackoff) {
+ if (GetQuicReloadableFlag(quic_default_on_pto)) {
+ return;
+ }
SendDataPacket(1);
QuicTime::Delta delay = QuicTime::Delta::FromMilliseconds(500);
@@ -1698,6 +1741,9 @@ TEST_F(QuicSentPacketManagerTest, GetTransmissionDelayExponentialBackoff) {
}
TEST_F(QuicSentPacketManagerTest, RetransmissionDelay) {
+ if (GetQuicReloadableFlag(quic_default_on_pto)) {
+ return;
+ }
RttStats* rtt_stats = const_cast<RttStats*>(manager_.GetRttStats());
const int64_t kRttMs = 250;
const int64_t kDeviationMs = 5;
@@ -1959,6 +2005,9 @@ TEST_F(QuicSentPacketManagerTest, NegotiateClientCongestionControlFromOptions) {
}
TEST_F(QuicSentPacketManagerTest, NegotiateNoMinTLPFromOptionsAtServer) {
+ if (GetQuicReloadableFlag(quic_default_on_pto)) {
+ return;
+ }
QuicConfig config;
QuicTagVector options;
@@ -1987,6 +2036,9 @@ TEST_F(QuicSentPacketManagerTest, NegotiateNoMinTLPFromOptionsAtServer) {
}
TEST_F(QuicSentPacketManagerTest, NegotiateNoMinTLPFromOptionsAtClient) {
+ if (GetQuicReloadableFlag(quic_default_on_pto)) {
+ return;
+ }
QuicConfig client_config;
QuicTagVector options;
@@ -2015,6 +2067,9 @@ TEST_F(QuicSentPacketManagerTest, NegotiateNoMinTLPFromOptionsAtClient) {
}
TEST_F(QuicSentPacketManagerTest, NegotiateNoMinRTOFromOptionsAtServer) {
+ if (GetQuicReloadableFlag(quic_default_on_pto)) {
+ return;
+ }
QuicConfig config;
QuicTagVector options;
@@ -2037,6 +2092,9 @@ TEST_F(QuicSentPacketManagerTest, NegotiateNoMinRTOFromOptionsAtServer) {
}
TEST_F(QuicSentPacketManagerTest, NegotiateNoMinRTOFromOptionsAtClient) {
+ if (GetQuicReloadableFlag(quic_default_on_pto)) {
+ return;
+ }
QuicConfig client_config;
QuicTagVector options;
@@ -2060,6 +2118,9 @@ TEST_F(QuicSentPacketManagerTest, NegotiateNoMinRTOFromOptionsAtClient) {
}
TEST_F(QuicSentPacketManagerTest, NegotiateNoTLPFromOptionsAtServer) {
+ if (GetQuicReloadableFlag(quic_default_on_pto)) {
+ return;
+ }
QuicConfig config;
QuicTagVector options;
@@ -2072,6 +2133,9 @@ TEST_F(QuicSentPacketManagerTest, NegotiateNoTLPFromOptionsAtServer) {
}
TEST_F(QuicSentPacketManagerTest, NegotiateNoTLPFromOptionsAtClient) {
+ if (GetQuicReloadableFlag(quic_default_on_pto)) {
+ return;
+ }
QuicConfig client_config;
QuicTagVector options;
@@ -2085,6 +2149,9 @@ TEST_F(QuicSentPacketManagerTest, NegotiateNoTLPFromOptionsAtClient) {
}
TEST_F(QuicSentPacketManagerTest, Negotiate1TLPFromOptionsAtServer) {
+ if (GetQuicReloadableFlag(quic_default_on_pto)) {
+ return;
+ }
QuicConfig config;
QuicTagVector options;
@@ -2097,6 +2164,9 @@ TEST_F(QuicSentPacketManagerTest, Negotiate1TLPFromOptionsAtServer) {
}
TEST_F(QuicSentPacketManagerTest, Negotiate1TLPFromOptionsAtClient) {
+ if (GetQuicReloadableFlag(quic_default_on_pto)) {
+ return;
+ }
QuicConfig client_config;
QuicTagVector options;
@@ -2110,6 +2180,9 @@ TEST_F(QuicSentPacketManagerTest, Negotiate1TLPFromOptionsAtClient) {
}
TEST_F(QuicSentPacketManagerTest, NegotiateTLPRttFromOptionsAtServer) {
+ if (GetQuicReloadableFlag(quic_default_on_pto)) {
+ return;
+ }
QuicConfig config;
QuicTagVector options;
@@ -2123,6 +2196,9 @@ TEST_F(QuicSentPacketManagerTest, NegotiateTLPRttFromOptionsAtServer) {
}
TEST_F(QuicSentPacketManagerTest, NegotiateTLPRttFromOptionsAtClient) {
+ if (GetQuicReloadableFlag(quic_default_on_pto)) {
+ return;
+ }
QuicConfig client_config;
QuicTagVector options;
@@ -2137,6 +2213,9 @@ TEST_F(QuicSentPacketManagerTest, NegotiateTLPRttFromOptionsAtClient) {
}
TEST_F(QuicSentPacketManagerTest, NegotiateNewRTOFromOptionsAtServer) {
+ if (GetQuicReloadableFlag(quic_default_on_pto)) {
+ return;
+ }
EXPECT_FALSE(QuicSentPacketManagerPeer::GetUseNewRto(&manager_));
QuicConfig config;
QuicTagVector options;
@@ -2150,6 +2229,9 @@ TEST_F(QuicSentPacketManagerTest, NegotiateNewRTOFromOptionsAtServer) {
}
TEST_F(QuicSentPacketManagerTest, NegotiateNewRTOFromOptionsAtClient) {
+ if (GetQuicReloadableFlag(quic_default_on_pto)) {
+ return;
+ }
EXPECT_FALSE(QuicSentPacketManagerPeer::GetUseNewRto(&manager_));
QuicConfig client_config;
QuicTagVector options;
@@ -2531,6 +2613,9 @@ TEST_F(QuicSentPacketManagerTest,
// Regression test for b/133771183.
TEST_F(QuicSentPacketManagerTest, PacketInLimbo) {
+ if (GetQuicReloadableFlag(quic_default_on_pto)) {
+ return;
+ }
QuicSentPacketManagerPeer::SetMaxTailLossProbes(&manager_, 2);
// Send SHLO.
SendCryptoPacket(1);
@@ -2583,6 +2668,9 @@ TEST_F(QuicSentPacketManagerTest, PacketInLimbo) {
}
TEST_F(QuicSentPacketManagerTest, RtoFiresNoPacketToRetransmit) {
+ if (GetQuicReloadableFlag(quic_default_on_pto)) {
+ return;
+ }
// Send 10 packets.
for (size_t i = 1; i <= 10; ++i) {
SendDataPacket(i);
@@ -2619,21 +2707,28 @@ TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeout) {
SendDataPacket(1, ENCRYPTION_FORWARD_SECURE);
// Verify PTO is correctly set.
+ int pto_rttvar_multiplier =
+ GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4;
QuicTime::Delta expected_pto_delay =
- srtt + 4 * rtt_stats->mean_deviation() +
+ srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() +
QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
+ QuicTime packet1_sent_time = clock_.Now();
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());
+ QuicTime deadline = clock_.Now() + expected_pto_delay;
+ if (GetQuicReloadableFlag(quic_default_on_pto)) {
+ // Verify PTO is set based on left edge.
+ deadline = packet1_sent_time + expected_pto_delay;
+ }
+ EXPECT_EQ(deadline, manager_.GetRetransmissionTime());
EXPECT_EQ(0u, stats_.pto_count);
// Invoke PTO.
- clock_.AdvanceTime(expected_pto_delay);
+ clock_.AdvanceTime(deadline - clock_.Now());
manager_.OnRetransmissionTimeout();
EXPECT_EQ(QuicTime::Delta::Zero(), manager_.TimeUntilSend(clock_.Now()));
EXPECT_EQ(1u, stats_.pto_count);
@@ -2664,7 +2759,7 @@ TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeout) {
ENCRYPTION_FORWARD_SECURE));
expected_pto_delay =
rtt_stats->SmoothedOrInitialRtt() +
- std::max(4 * rtt_stats->mean_deviation(),
+ std::max(pto_rttvar_multiplier * rtt_stats->mean_deviation(),
QuicTime::Delta::FromMilliseconds(1)) +
QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
@@ -2680,6 +2775,7 @@ TEST_F(QuicSentPacketManagerTest, SendOneProbePacket) {
.WillRepeatedly(Return(10 * kDefaultTCPMSS));
SendDataPacket(1, ENCRYPTION_FORWARD_SECURE);
+ QuicTime packet1_sent_time = clock_.Now();
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10));
SendDataPacket(2, ENCRYPTION_FORWARD_SECURE);
@@ -2688,14 +2784,20 @@ TEST_F(QuicSentPacketManagerTest, SendOneProbePacket) {
QuicTime::Delta::Zero(), QuicTime::Zero());
QuicTime::Delta srtt = rtt_stats->smoothed_rtt();
// Verify PTO period is correctly set.
+ int pto_rttvar_multiplier =
+ GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4;
QuicTime::Delta expected_pto_delay =
- srtt + 4 * rtt_stats->mean_deviation() +
+ srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() +
QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
- EXPECT_EQ(clock_.Now() + expected_pto_delay,
- manager_.GetRetransmissionTime());
+ QuicTime deadline = clock_.Now() + expected_pto_delay;
+ if (GetQuicReloadableFlag(quic_default_on_pto)) {
+ // Verify PTO is set based on left edge.
+ deadline = packet1_sent_time + expected_pto_delay;
+ }
+ EXPECT_EQ(deadline, manager_.GetRetransmissionTime());
// Invoke PTO.
- clock_.AdvanceTime(expected_pto_delay);
+ clock_.AdvanceTime(deadline - clock_.Now());
manager_.OnRetransmissionTimeout();
EXPECT_EQ(QuicTime::Delta::Zero(), manager_.TimeUntilSend(clock_.Now()));
@@ -2773,9 +2875,12 @@ TEST_F(QuicSentPacketManagerTest, PtoTimeoutIncludesMaxAckDelay) {
QuicTime::Delta srtt = rtt_stats->smoothed_rtt();
SendDataPacket(1, ENCRYPTION_FORWARD_SECURE);
+ QuicTime packet1_sent_time = clock_.Now();
// Verify PTO is correctly set and ack delay is included.
+ int pto_rttvar_multiplier =
+ GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4;
QuicTime::Delta expected_pto_delay =
- srtt + 4 * rtt_stats->mean_deviation() +
+ srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() +
QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
EXPECT_EQ(clock_.Now() + expected_pto_delay,
manager_.GetRetransmissionTime());
@@ -2786,12 +2891,15 @@ TEST_F(QuicSentPacketManagerTest, PtoTimeoutIncludesMaxAckDelay) {
// 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());
+ QuicTime deadline = clock_.Now() + expected_pto_delay;
+ if (GetQuicReloadableFlag(quic_default_on_pto)) {
+ deadline = packet1_sent_time + expected_pto_delay;
+ }
+ EXPECT_EQ(deadline, manager_.GetRetransmissionTime());
EXPECT_EQ(0u, stats_.pto_count);
// Invoke PTO.
- clock_.AdvanceTime(expected_pto_delay);
+ clock_.AdvanceTime(deadline - clock_.Now());
manager_.OnRetransmissionTimeout();
EXPECT_EQ(QuicTime::Delta::Zero(), manager_.TimeUntilSend(clock_.Now()));
EXPECT_EQ(1u, stats_.pto_count);
@@ -2819,7 +2927,7 @@ TEST_F(QuicSentPacketManagerTest, PtoTimeoutIncludesMaxAckDelay) {
ENCRYPTION_FORWARD_SECURE));
expected_pto_delay =
rtt_stats->SmoothedOrInitialRtt() +
- std::max(4 * rtt_stats->mean_deviation(),
+ std::max(pto_rttvar_multiplier * rtt_stats->mean_deviation(),
QuicTime::Delta::FromMilliseconds(1)) +
QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
@@ -2853,7 +2961,7 @@ TEST_F(QuicSentPacketManagerTest, PtoTimeoutIncludesMaxAckDelay) {
expected_pto_delay =
rtt_stats->SmoothedOrInitialRtt() +
- std::max(4 * rtt_stats->mean_deviation(),
+ std::max(pto_rttvar_multiplier * rtt_stats->mean_deviation(),
QuicTime::Delta::FromMilliseconds(1)) +
QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
for (size_t i = 101; i < 110; i++) {
@@ -2891,22 +2999,29 @@ TEST_F(QuicSentPacketManagerTest, StartExponentialBackoffSince2ndPto) {
QuicTime::Delta srtt = rtt_stats->smoothed_rtt();
SendDataPacket(1, ENCRYPTION_FORWARD_SECURE);
+ QuicTime packet1_sent_time = clock_.Now();
// Verify PTO is correctly set.
+ int pto_rttvar_multiplier =
+ GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4;
QuicTime::Delta expected_pto_delay =
- srtt + 4 * rtt_stats->mean_deviation() +
+ srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() +
QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
- EXPECT_EQ(clock_.Now() + expected_pto_delay,
+ EXPECT_EQ(packet1_sent_time + 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());
+ QuicTime deadline = clock_.Now() + expected_pto_delay;
+ if (GetQuicReloadableFlag(quic_default_on_pto)) {
+ // Verify PTO is set based on left edge.
+ deadline = packet1_sent_time + expected_pto_delay;
+ }
+ EXPECT_EQ(deadline, manager_.GetRetransmissionTime());
EXPECT_EQ(0u, stats_.pto_count);
// Invoke PTO.
- clock_.AdvanceTime(expected_pto_delay);
+ clock_.AdvanceTime(deadline - clock_.Now());
manager_.OnRetransmissionTimeout();
EXPECT_EQ(QuicTime::Delta::Zero(), manager_.TimeUntilSend(clock_.Now()));
EXPECT_EQ(1u, stats_.pto_count);
@@ -3017,6 +3132,9 @@ TEST_F(QuicSentPacketManagerTest, PtoTimeoutRttVarMultiple) {
// Regression test for b/143962153
TEST_F(QuicSentPacketManagerTest, RtoNotInFlightPacket) {
+ if (GetQuicReloadableFlag(quic_default_on_pto)) {
+ return;
+ }
QuicSentPacketManagerPeer::SetMaxTailLossProbes(&manager_, 2);
// Send SHLO.
QuicStreamFrame crypto_frame(1, false, 0, quiche::QuicheStringPiece());
@@ -3094,8 +3212,10 @@ TEST_F(QuicSentPacketManagerTest, Aggressive1Pto) {
// Verify PTO period gets set correctly.
QuicTime sent_time = clock_.Now();
+ int pto_rttvar_multiplier =
+ GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4;
expected_pto_delay =
- srtt + 4 * rtt_stats->mean_deviation() +
+ srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() +
QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
EXPECT_EQ(sent_time + expected_pto_delay * 2,
manager_.GetRetransmissionTime());
@@ -3156,8 +3276,10 @@ TEST_F(QuicSentPacketManagerTest, Aggressive2Ptos) {
RetransmitDataPacket(5, type, ENCRYPTION_FORWARD_SECURE);
})));
manager_.MaybeSendProbePackets();
+ int pto_rttvar_multiplier =
+ GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4;
expected_pto_delay =
- srtt + 4 * rtt_stats->mean_deviation() +
+ srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() +
QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
// Verify PTO period gets set correctly.
@@ -3195,8 +3317,10 @@ TEST_F(QuicSentPacketManagerTest, ClientMultiplePacketNumberSpacePtoTimeout) {
// Send packet 1.
SendDataPacket(1, ENCRYPTION_INITIAL);
// Verify PTO is correctly set.
+ int pto_rttvar_multiplier =
+ GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4;
QuicTime::Delta expected_pto_delay =
- srtt + 4 * rtt_stats->mean_deviation() +
+ srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() +
QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
EXPECT_EQ(clock_.Now() + expected_pto_delay,
manager_.GetRetransmissionTime());
@@ -3284,8 +3408,10 @@ TEST_F(QuicSentPacketManagerTest, ServerMultiplePacketNumberSpacePtoTimeout) {
SendDataPacket(1, ENCRYPTION_INITIAL);
const QuicTime packet1_sent_time = clock_.Now();
// Verify PTO is correctly set.
+ int pto_rttvar_multiplier =
+ GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4;
QuicTime::Delta expected_pto_delay =
- srtt + 4 * rtt_stats->mean_deviation() +
+ srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() +
QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
EXPECT_EQ(packet1_sent_time + expected_pto_delay,
manager_.GetRetransmissionTime());
@@ -3326,7 +3452,6 @@ TEST_F(QuicSentPacketManagerTest, ServerMultiplePacketNumberSpacePtoTimeout) {
}
TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeoutByLeftEdge) {
- SetQuicReloadableFlag(quic_arm_pto_with_earliest_sent_time, true);
EnablePto(k1PTO);
// Use PTOS and PLE1.
QuicConfig config;
@@ -3350,8 +3475,10 @@ TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeoutByLeftEdge) {
SendDataPacket(1, ENCRYPTION_FORWARD_SECURE);
// Verify PTO is correctly set.
+ int pto_rttvar_multiplier =
+ GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4;
QuicTime::Delta expected_pto_delay =
- srtt + 4 * rtt_stats->mean_deviation() +
+ srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() +
QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
const QuicTime packet1_sent_time = clock_.Now();
EXPECT_EQ(packet1_sent_time + expected_pto_delay,
@@ -3391,7 +3518,7 @@ TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeoutByLeftEdge) {
ENCRYPTION_FORWARD_SECURE));
expected_pto_delay =
rtt_stats->SmoothedOrInitialRtt() +
- std::max(4 * rtt_stats->mean_deviation(),
+ std::max(pto_rttvar_multiplier * rtt_stats->mean_deviation(),
QuicTime::Delta::FromMilliseconds(1)) +
QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
@@ -3401,7 +3528,6 @@ TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeoutByLeftEdge) {
}
TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeoutByLeftEdge2) {
- SetQuicReloadableFlag(quic_arm_pto_with_earliest_sent_time, true);
EnablePto(k1PTO);
// Use PTOS and PLE2.
QuicConfig config;
@@ -3425,8 +3551,10 @@ TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeoutByLeftEdge2) {
SendDataPacket(1, ENCRYPTION_FORWARD_SECURE);
// Verify PTO is correctly set.
+ int pto_rttvar_multiplier =
+ GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4;
QuicTime::Delta expected_pto_delay =
- srtt + 4 * rtt_stats->mean_deviation() +
+ srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() +
QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
const QuicTime packet1_sent_time = clock_.Now();
EXPECT_EQ(packet1_sent_time + expected_pto_delay,
@@ -3456,7 +3584,7 @@ TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeoutByLeftEdge2) {
// Verify PTO period gets set to twice the expected value and based on
// packet3 (right edge).
expected_pto_delay =
- srtt + 4 * rtt_stats->mean_deviation() +
+ srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() +
QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
QuicTime packet3_sent_time = clock_.Now();
EXPECT_EQ(packet3_sent_time + expected_pto_delay * 2,
@@ -3473,7 +3601,7 @@ TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeoutByLeftEdge2) {
ENCRYPTION_FORWARD_SECURE));
expected_pto_delay =
rtt_stats->SmoothedOrInitialRtt() +
- std::max(4 * rtt_stats->mean_deviation(),
+ std::max(pto_rttvar_multiplier * rtt_stats->mean_deviation(),
QuicTime::Delta::FromMilliseconds(1)) +
QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
@@ -3484,7 +3612,6 @@ TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeoutByLeftEdge2) {
}
TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeoutUsingStandardDeviation) {
- SetQuicReloadableFlag(quic_use_standard_deviation_for_pto, true);
EnablePto(k1PTO);
// Use PTOS and PSDA.
QuicConfig config;
@@ -3514,8 +3641,10 @@ TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeoutUsingStandardDeviation) {
SendDataPacket(1, ENCRYPTION_FORWARD_SECURE);
// Verify PTO is correctly set using standard deviation.
+ int pto_rttvar_multiplier =
+ GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4;
QuicTime::Delta expected_pto_delay =
- srtt + 4 * rtt_stats->GetStandardOrMeanDeviation() +
+ srtt + pto_rttvar_multiplier * rtt_stats->GetStandardOrMeanDeviation() +
QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
EXPECT_EQ(clock_.Now() + expected_pto_delay,
manager_.GetRetransmissionTime());
@@ -3523,7 +3652,6 @@ TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeoutUsingStandardDeviation) {
TEST_F(QuicSentPacketManagerTest,
ComputingProbeTimeoutByLeftEdgeMultiplePacketNumberSpaces) {
- SetQuicReloadableFlag(quic_arm_pto_with_earliest_sent_time, true);
manager_.EnableMultiplePacketNumberSpacesSupport();
EnablePto(k1PTO);
// Use PTOS and PLE1.
@@ -3550,8 +3678,10 @@ TEST_F(QuicSentPacketManagerTest,
SendDataPacket(1, ENCRYPTION_INITIAL);
const QuicTime packet1_sent_time = clock_.Now();
// Verify PTO is correctly set.
+ int pto_rttvar_multiplier =
+ GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4;
QuicTime::Delta expected_pto_delay =
- srtt + 4 * rtt_stats->mean_deviation() +
+ srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() +
QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
EXPECT_EQ(packet1_sent_time + expected_pto_delay,
manager_.GetRetransmissionTime());
@@ -3599,7 +3729,6 @@ TEST_F(QuicSentPacketManagerTest,
TEST_F(QuicSentPacketManagerTest,
ComputingProbeTimeoutByLeftEdge2MultiplePacketNumberSpaces) {
- SetQuicReloadableFlag(quic_arm_pto_with_earliest_sent_time, true);
manager_.EnableMultiplePacketNumberSpacesSupport();
EnablePto(k1PTO);
// Use PTOS and PLE2.
@@ -3626,8 +3755,10 @@ TEST_F(QuicSentPacketManagerTest,
SendDataPacket(1, ENCRYPTION_INITIAL);
const QuicTime packet1_sent_time = clock_.Now();
// Verify PTO is correctly set.
+ int pto_rttvar_multiplier =
+ GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4;
QuicTime::Delta expected_pto_delay =
- srtt + 4 * rtt_stats->mean_deviation() +
+ srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() +
QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
EXPECT_EQ(packet1_sent_time + expected_pto_delay,
manager_.GetRetransmissionTime());
@@ -3722,8 +3853,6 @@ TEST_F(QuicSentPacketManagerTest, NoPacketThresholdDetectionForRuntPackets) {
EXPECT_TRUE(
QuicSentPacketManagerPeer::UsePacketThresholdForRuntPackets(&manager_));
- SetQuicReloadableFlag(quic_skip_packet_threshold_loss_detection_with_runt,
- true);
QuicConfig config;
QuicTagVector options;
options.push_back(kRUNT);
@@ -3779,6 +3908,96 @@ TEST_F(QuicSentPacketManagerTest, GetPathDegradingDelay) {
EXPECT_EQ(expected_delay, manager_.GetPathDegradingDelay());
}
+// Regression test for b/154050235.
+TEST_F(QuicSentPacketManagerTest, ExponentialBackoffWithNoRttMeasurement) {
+ QuicSentPacketManagerPeer::SetPerspective(&manager_, Perspective::IS_CLIENT);
+ manager_.EnableIetfPtoAndLossDetection();
+ RttStats* rtt_stats = const_cast<RttStats*>(manager_.GetRttStats());
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(kInitialRttMs),
+ rtt_stats->initial_rtt());
+ EXPECT_TRUE(rtt_stats->smoothed_rtt().IsZero());
+
+ SendCryptoPacket(1);
+ QuicTime::Delta expected_pto_delay =
+ QuicTime::Delta::FromMilliseconds(3 * kInitialRttMs);
+ EXPECT_EQ(clock_.Now() + expected_pto_delay,
+ manager_.GetRetransmissionTime());
+
+ // Invoke PTO.
+ clock_.AdvanceTime(expected_pto_delay);
+ manager_.OnRetransmissionTimeout();
+
+ EXPECT_CALL(notifier_, RetransmitFrames(_, _))
+ .WillOnce(WithArgs<1>(Invoke([this]() { RetransmitCryptoPacket(3); })));
+ manager_.MaybeSendProbePackets();
+ if (GetQuicReloadableFlag(quic_default_on_pto)) {
+ manager_.AdjustPendingTimerTransmissions();
+ }
+ // Verify exponential backoff of the PTO timeout.
+ EXPECT_EQ(clock_.Now() + 2 * expected_pto_delay,
+ manager_.GetRetransmissionTime());
+}
+
+TEST_F(QuicSentPacketManagerTest, PtoDelayWithTinyInitialRtt) {
+ manager_.EnableIetfPtoAndLossDetection();
+ RttStats* rtt_stats = const_cast<RttStats*>(manager_.GetRttStats());
+ // Assume client provided a tiny initial RTT.
+ rtt_stats->set_initial_rtt(QuicTime::Delta::FromMicroseconds(1));
+ EXPECT_EQ(QuicTime::Delta::FromMicroseconds(1), rtt_stats->initial_rtt());
+ EXPECT_TRUE(rtt_stats->smoothed_rtt().IsZero());
+
+ SendCryptoPacket(1);
+ QuicTime::Delta expected_pto_delay = QuicTime::Delta::FromMilliseconds(10);
+ // Verify kMinHandshakeTimeoutMs is respected.
+ EXPECT_EQ(clock_.Now() + expected_pto_delay,
+ manager_.GetRetransmissionTime());
+
+ // Invoke PTO.
+ clock_.AdvanceTime(expected_pto_delay);
+ manager_.OnRetransmissionTimeout();
+
+ EXPECT_CALL(notifier_, RetransmitFrames(_, _))
+ .WillOnce(WithArgs<1>(Invoke([this]() { RetransmitCryptoPacket(3); })));
+ manager_.MaybeSendProbePackets();
+ if (GetQuicReloadableFlag(quic_default_on_pto)) {
+ manager_.AdjustPendingTimerTransmissions();
+ }
+ // Verify exponential backoff of the PTO timeout.
+ EXPECT_EQ(clock_.Now() + 2 * expected_pto_delay,
+ manager_.GetRetransmissionTime());
+}
+
+TEST_F(QuicSentPacketManagerTest, HandshakeAckCausesInitialKeyDropping) {
+ manager_.EnableMultiplePacketNumberSpacesSupport();
+ QuicSentPacketManagerPeer::SetPerspective(&manager_, Perspective::IS_CLIENT);
+ // Send INITIAL packet 1.
+ SendDataPacket(1, ENCRYPTION_INITIAL);
+ QuicTime::Delta expected_pto_delay =
+ QuicTime::Delta::FromMilliseconds(3 * kInitialRttMs);
+ EXPECT_EQ(clock_.Now() + expected_pto_delay,
+ manager_.GetRetransmissionTime());
+ // Send HANDSHAKE ack.
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10));
+ SendAckPacket(2, /*largest_acked=*/1, ENCRYPTION_HANDSHAKE);
+ // Sending HANDSHAKE packet causes dropping of INITIAL key.
+ EXPECT_CALL(notifier_, HasUnackedCryptoData()).WillRepeatedly(Return(false));
+ EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false));
+ manager_.NeuterUnencryptedPackets();
+ // There is no in flight packets.
+ EXPECT_FALSE(manager_.HasInFlightPackets());
+ // Verify PTO timer gets rearmed from now because of anti-amplification.
+ EXPECT_EQ(clock_.Now() + expected_pto_delay,
+ manager_.GetRetransmissionTime());
+
+ // Invoke PTO.
+ clock_.AdvanceTime(expected_pto_delay);
+ manager_.OnRetransmissionTimeout();
+ // Verify nothing to probe (and connection will send PING for current
+ // encryption level).
+ EXPECT_CALL(notifier_, RetransmitFrames(_, _)).Times(0);
+ manager_.MaybeSendProbePackets();
+}
+
} // 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 5376bfdddde..0f00ff3843d 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
@@ -45,24 +45,6 @@ class ClosedStreamsCleanUpDelegate : public QuicAlarm::Delegate {
QuicSession* session_;
};
-// TODO(renjietang): remove this function once
-// gfe2_reloadable_flag_quic_write_with_transmission is deprecated.
-void CountTransmissionTypeFlag(TransmissionType type) {
- switch (type) {
- case NOT_RETRANSMISSION:
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_write_with_transmission, 1, 4);
- break;
- case HANDSHAKE_RETRANSMISSION:
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_write_with_transmission, 2, 4);
- break;
- case LOSS_RETRANSMISSION:
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_write_with_transmission, 3, 4);
- break;
- default:
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_write_with_transmission, 4, 4);
- }
-}
-
} // namespace
#define ENDPOINT \
@@ -93,6 +75,7 @@ QuicSession::QuicSession(
num_expected_unidirectional_static_streams),
num_dynamic_incoming_streams_(0),
num_draining_incoming_streams_(0),
+ num_draining_outgoing_streams_(0),
num_outgoing_static_streams_(0),
num_incoming_static_streams_(0),
num_locally_closed_incoming_streams_highest_offset_(0),
@@ -117,11 +100,11 @@ QuicSession::QuicSession(
supported_versions_(supported_versions),
use_http2_priority_write_scheduler_(false),
is_configured_(false),
- num_expected_unidirectional_static_streams_(
- num_expected_unidirectional_static_streams),
enable_round_robin_scheduling_(false),
- write_with_transmission_(
- GetQuicReloadableFlag(quic_write_with_transmission)) {
+ deprecate_draining_streams_(
+ GetQuicReloadableFlag(quic_deprecate_draining_streams)),
+ break_close_loop_(
+ GetQuicReloadableFlag(quic_break_session_stream_close_loop)) {
closed_streams_clean_up_alarm_ =
QuicWrapUnique<QuicAlarm>(connection_->alarm_factory()->CreateAlarm(
new ClosedStreamsCleanUpDelegate(this)));
@@ -129,6 +112,14 @@ QuicSession::QuicSession(
connection_->version().handshake_protocol == PROTOCOL_TLS1_3) {
config_.SetStatelessResetTokenToSend(GetStatelessResetToken());
}
+ if (VersionHasIetfQuicFrames(transport_version())) {
+ config_.SetMaxUnidirectionalStreamsToSend(
+ config_.GetMaxUnidirectionalStreamsToSend() +
+ num_expected_unidirectional_static_streams);
+ }
+ if (break_close_loop_) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_break_session_stream_close_loop);
+ }
}
void QuicSession::Initialize() {
@@ -301,6 +292,10 @@ void QuicSession::OnOneRttPacketAcknowledged() {
GetMutableCryptoStream()->OnOneRttPacketAcknowledged();
}
+void QuicSession::OnHandshakePacketSent() {
+ GetMutableCryptoStream()->OnHandshakePacketSent();
+}
+
void QuicSession::PendingStreamOnRstStream(const QuicRstStreamFrame& frame) {
DCHECK(VersionUsesHttp3(transport_version()));
QuicStreamId stream_id = frame.stream_id;
@@ -398,11 +393,16 @@ void QuicSession::OnConnectionClosed(const QuicConnectionCloseFrame& frame,
RecordConnectionCloseAtServer(frame.quic_error_code, source);
}
- if (on_closed_frame_.extracted_error_code == QUIC_NO_ERROR) {
+ if (on_closed_frame_.quic_error_code == QUIC_NO_ERROR) {
// Save all of the connection close information
on_closed_frame_ = frame;
}
+ if (GetQuicReloadableFlag(quic_notify_handshaker_on_connection_close)) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_notify_handshaker_on_connection_close);
+ GetMutableCryptoStream()->OnConnectionClosed(frame.quic_error_code, source);
+ }
+
// Copy all non static streams in a new map for the ease of deleting.
QuicSmallMap<QuicStreamId, QuicStream*, 10> non_static_streams;
for (const auto& it : stream_map_) {
@@ -431,8 +431,8 @@ void QuicSession::OnConnectionClosed(const QuicConnectionCloseFrame& frame,
if (visitor_) {
visitor_->OnConnectionClosed(connection_->connection_id(),
- frame.extracted_error_code,
- frame.error_details, source);
+ frame.quic_error_code, frame.error_details,
+ source);
}
}
@@ -558,9 +558,6 @@ void QuicSession::OnCanWrite() {
"write blocked.";
return;
}
- if (!write_with_transmission_) {
- 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
@@ -685,7 +682,7 @@ bool QuicSession::HasPendingHandshake() const {
}
uint64_t QuicSession::GetNumOpenDynamicStreams() const {
- return stream_map_.size() - draining_streams_.size() +
+ return stream_map_.size() - GetNumDrainingStreams() +
locally_closed_streams_highest_offset_.size() -
num_incoming_static_streams_ - num_outgoing_static_streams_;
}
@@ -714,10 +711,7 @@ QuicConsumedData QuicSession::WritevData(
return QuicConsumedData(0, false);
}
- if (write_with_transmission_) {
- SetTransmissionType(type);
- CountTransmissionTypeFlag(type);
- }
+ SetTransmissionType(type);
const auto current_level = connection()->encryption_level();
if (level.has_value()) {
connection()->SetDefaultEncryptionLevel(level.value());
@@ -743,10 +737,7 @@ size_t QuicSession::SendCryptoData(EncryptionLevel level,
QuicStreamOffset offset,
TransmissionType type) {
DCHECK(QuicVersionUsesCryptoFrames(transport_version()));
- if (write_with_transmission_) {
- SetTransmissionType(type);
- CountTransmissionTypeFlag(type);
- }
+ SetTransmissionType(type);
const auto current_level = connection()->encryption_level();
connection_->SetDefaultEncryptionLevel(level);
const auto bytes_consumed =
@@ -758,10 +749,7 @@ size_t QuicSession::SendCryptoData(EncryptionLevel level,
bool QuicSession::WriteControlFrame(const QuicFrame& frame,
TransmissionType type) {
- if (write_with_transmission_) {
- SetTransmissionType(type);
- CountTransmissionTypeFlag(type);
- }
+ SetTransmissionType(type);
return connection_->SendControlFrame(frame);
}
@@ -776,6 +764,10 @@ void QuicSession::SendRstStream(QuicStreamId id,
connection_->OnStreamReset(id, error);
}
+ if (break_close_loop_) {
+ return;
+ }
+
if (error != QUIC_STREAM_NO_ERROR && QuicContainsKey(zombie_streams_, id)) {
OnStreamDoneWaitingForAcks(id);
return;
@@ -783,6 +775,26 @@ void QuicSession::SendRstStream(QuicStreamId id,
CloseStreamInner(id, true);
}
+void QuicSession::ResetStream(QuicStreamId id,
+ QuicRstStreamErrorCode error,
+ QuicStreamOffset bytes_written) {
+ DCHECK(break_close_loop_);
+ QuicStream* stream = GetStream(id);
+ if (stream != nullptr && stream->is_static()) {
+ connection()->CloseConnection(
+ QUIC_INVALID_STREAM_ID, "Try to reset a static stream",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return;
+ }
+
+ if (stream != nullptr) {
+ stream->Reset(error);
+ return;
+ }
+
+ SendRstStream(id, error, bytes_written);
+}
+
void QuicSession::MaybeSendRstStreamFrame(QuicStreamId id,
QuicRstStreamErrorCode error,
QuicStreamOffset bytes_written) {
@@ -875,6 +887,11 @@ void QuicSession::CloseStreamInner(QuicStreamId stream_id, bool rst_sent) {
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
return;
}
+ if (break_close_loop_) {
+ stream->CloseReadSide();
+ stream->CloseWriteSide();
+ return;
+ }
StreamType type = stream->type();
// Tell the stream that a RST has been sent.
@@ -904,16 +921,27 @@ void QuicSession::CloseStreamInner(QuicStreamId stream_id, bool rst_sent) {
InsertLocallyClosedStreamsHighestOffset(
stream_id, stream->flow_controller()->highest_received_byte_offset());
}
+ bool stream_was_draining = false;
+ if (deprecate_draining_streams_) {
+ stream_was_draining = stream->was_draining();
+ QUIC_DVLOG_IF(1, stream_was_draining)
+ << ENDPOINT << "Stream " << stream_id << " was draining";
+ }
stream_map_.erase(it);
if (IsIncomingStream(stream_id)) {
--num_dynamic_incoming_streams_;
}
-
- const bool stream_was_draining =
- draining_streams_.find(stream_id) != draining_streams_.end();
+ if (!deprecate_draining_streams_) {
+ stream_was_draining =
+ draining_streams_.find(stream_id) != draining_streams_.end();
+ }
if (stream_was_draining) {
if (IsIncomingStream(stream_id)) {
+ QUIC_BUG_IF(num_draining_incoming_streams_ == 0);
--num_draining_incoming_streams_;
+ } else if (deprecate_draining_streams_) {
+ QUIC_BUG_IF(num_draining_outgoing_streams_ == 0);
+ --num_draining_outgoing_streams_;
}
draining_streams_.erase(stream_id);
} else if (VersionHasIetfQuicFrames(transport_version())) {
@@ -923,6 +951,10 @@ void QuicSession::CloseStreamInner(QuicStreamId stream_id, bool rst_sent) {
// Do not bother informing stream ID manager if connection is closed.
v99_streamid_manager_.OnStreamClosed(stream_id);
}
+ } else if (stream_id_manager_.handles_accounting() && had_fin_or_rst &&
+ connection_->connected()) {
+ stream_id_manager_.OnStreamClosed(
+ /*is_incoming=*/IsIncomingStream(stream_id));
}
stream->OnClose();
@@ -935,12 +967,100 @@ void QuicSession::CloseStreamInner(QuicStreamId stream_id, bool rst_sent) {
}
}
+void QuicSession::OnStreamClosed(QuicStreamId stream_id) {
+ QUIC_DVLOG(1) << ENDPOINT << "Closing stream: " << stream_id;
+ DCHECK(break_close_loop_);
+ StreamMap::iterator it = stream_map_.find(stream_id);
+ if (it == stream_map_.end()) {
+ QUIC_DVLOG(1) << ENDPOINT << "Stream is already closed: " << stream_id;
+ return;
+ }
+ QuicStream* stream = it->second.get();
+ StreamType type = stream->type();
+
+ if (stream->IsWaitingForAcks()) {
+ zombie_streams_[stream->id()] = std::move(it->second);
+ } else {
+ // Clean up the stream since it is no longer waiting for acks.
+ 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);
+ if (!closed_streams_clean_up_alarm_->IsSet()) {
+ closed_streams_clean_up_alarm_->Set(
+ connection_->clock()->ApproximateNow());
+ }
+ }
+
+ if (!stream->HasReceivedFinalOffset()) {
+ // 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.
+ // If this is an outgoing stream, it is technically open from peer's
+ // perspective. Do not inform stream Id manager yet.
+ DCHECK(!stream->was_draining());
+ InsertLocallyClosedStreamsHighestOffset(
+ stream_id, stream->flow_controller()->highest_received_byte_offset());
+ stream_map_.erase(it);
+ if (IsIncomingStream(stream_id)) {
+ --num_dynamic_incoming_streams_;
+ }
+ return;
+ }
+
+ bool stream_was_draining = false;
+ if (deprecate_draining_streams_) {
+ stream_was_draining = stream->was_draining();
+ QUIC_DVLOG_IF(1, stream_was_draining)
+ << ENDPOINT << "Stream " << stream_id << " was draining";
+ }
+ stream_map_.erase(it);
+ if (IsIncomingStream(stream_id)) {
+ --num_dynamic_incoming_streams_;
+ }
+ if (!deprecate_draining_streams_) {
+ stream_was_draining =
+ draining_streams_.find(stream_id) != draining_streams_.end();
+ }
+ if (stream_was_draining) {
+ if (IsIncomingStream(stream_id)) {
+ QUIC_BUG_IF(num_draining_incoming_streams_ == 0);
+ --num_draining_incoming_streams_;
+ } else if (deprecate_draining_streams_) {
+ QUIC_BUG_IF(num_draining_outgoing_streams_ == 0);
+ --num_draining_outgoing_streams_;
+ }
+ draining_streams_.erase(stream_id);
+ // Stream Id manager has been informed with draining streams.
+ return;
+ }
+ if (!connection_->connected()) {
+ // Do not bother informing stream ID manager if connection has been
+ // disconnected.
+ return;
+ }
+ if (stream_id_manager_.handles_accounting() &&
+ !VersionHasIetfQuicFrames(transport_version())) {
+ stream_id_manager_.OnStreamClosed(
+ /*is_incoming=*/IsIncomingStream(stream_id));
+ }
+ if (IsIncomingStream(stream_id)) {
+ // Stream Id manager is only interested in peer initiated stream IDs.
+ if (VersionHasIetfQuicFrames(transport_version())) {
+ v99_streamid_manager_.OnStreamClosed(stream_id);
+ }
+ return;
+ }
+ if (!VersionHasIetfQuicFrames(transport_version())) {
+ OnCanCreateNewOutgoingStream(type != BIDIRECTIONAL);
+ }
+}
+
void QuicSession::ClosePendingStream(QuicStreamId stream_id) {
QUIC_DVLOG(1) << ENDPOINT << "Closing stream " << stream_id;
-
+ DCHECK(VersionHasIetfQuicFrames(transport_version()));
pending_stream_map_.erase(stream_id);
- if (VersionHasIetfQuicFrames(transport_version()) &&
- connection_->connected()) {
+ if (connection_->connected()) {
v99_streamid_manager_.OnStreamClosed(stream_id);
}
}
@@ -970,6 +1090,11 @@ void QuicSession::OnFinalByteOffsetReceived(
flow_controller_.AddBytesConsumed(offset_diff);
locally_closed_streams_highest_offset_.erase(it);
+ if (stream_id_manager_.handles_accounting() &&
+ !VersionHasIetfQuicFrames(transport_version())) {
+ stream_id_manager_.OnStreamClosed(
+ /*is_incoming=*/IsIncomingStream(stream_id));
+ }
if (IsIncomingStream(stream_id)) {
--num_locally_closed_incoming_streams_highest_offset_;
if (VersionHasIetfQuicFrames(transport_version())) {
@@ -1006,6 +1131,18 @@ void QuicSession::OnConfigNegotiated() {
QUIC_DVLOG(1) << ENDPOINT
<< "Setting Bidirectional outgoing_max_streams_ to "
<< max_streams;
+ if (perspective_ == Perspective::IS_CLIENT &&
+ max_streams <
+ v99_streamid_manager_.max_outgoing_bidirectional_streams()) {
+ connection_->CloseConnection(
+ QUIC_MAX_STREAMS_ERROR,
+ quiche::QuicheStrCat(
+ "new bidirectional limit ", max_streams,
+ " decreases the current limit: ",
+ v99_streamid_manager_.max_outgoing_bidirectional_streams()),
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return;
+ }
if (v99_streamid_manager_.MaybeAllowNewOutgoingBidirectionalStreams(
max_streams)) {
OnCanCreateNewOutgoingStream(/*unidirectional = */ false);
@@ -1015,14 +1152,16 @@ void QuicSession::OnConfigNegotiated() {
if (config_.HasReceivedMaxUnidirectionalStreams()) {
max_streams = config_.ReceivedMaxUnidirectionalStreams();
}
- if (max_streams < num_expected_unidirectional_static_streams_) {
- // TODO(ianswett): Change this to an application error for HTTP/3.
- QUIC_DLOG(ERROR) << "Received unidirectional stream limit of "
- << max_streams << " < "
- << num_expected_unidirectional_static_streams_;
+ if (max_streams <
+ v99_streamid_manager_.max_outgoing_unidirectional_streams()) {
connection_->CloseConnection(
- QUIC_MAX_STREAMS_ERROR, "New unidirectional stream limit is too low.",
+ QUIC_MAX_STREAMS_ERROR,
+ quiche::QuicheStrCat(
+ "new unidirectional limit ", max_streams,
+ " decreases the current limit: ",
+ v99_streamid_manager_.max_outgoing_unidirectional_streams()),
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return;
}
QUIC_DVLOG(1) << ENDPOINT
<< "Setting Unidirectional outgoing_max_streams_ to "
@@ -1196,6 +1335,7 @@ void QuicSession::HandleRstOnValidNonexistentStream(
}
void QuicSession::OnNewStreamFlowControlWindow(QuicStreamOffset new_window) {
+ DCHECK_EQ(connection_->version().handshake_protocol, PROTOCOL_QUIC_CRYPTO);
QUIC_DVLOG(1) << ENDPOINT << "OnNewStreamFlowControlWindow " << new_window;
if (new_window < kMinimumFlowControlSendWindow &&
!connection_->version().AllowsLowFlowControlLimits()) {
@@ -1212,19 +1352,22 @@ void QuicSession::OnNewStreamFlowControlWindow(QuicStreamOffset new_window) {
for (auto const& kv : stream_map_) {
QUIC_DVLOG(1) << ENDPOINT << "Informing stream " << kv.first
<< " of new stream flow control window " << new_window;
- kv.second->UpdateSendWindowOffset(new_window);
+ if (!kv.second->ConfigSendWindowOffset(new_window)) {
+ return;
+ }
}
if (!QuicVersionUsesCryptoFrames(transport_version())) {
QUIC_DVLOG(1)
<< ENDPOINT
<< "Informing crypto stream of new stream flow control window "
<< new_window;
- GetMutableCryptoStream()->UpdateSendWindowOffset(new_window);
+ GetMutableCryptoStream()->ConfigSendWindowOffset(new_window);
}
}
void QuicSession::OnNewStreamUnidirectionalFlowControlWindow(
QuicStreamOffset new_window) {
+ DCHECK_EQ(connection_->version().handshake_protocol, PROTOCOL_TLS1_3);
QUIC_DVLOG(1) << ENDPOINT << "OnNewStreamUnidirectionalFlowControlWindow "
<< new_window;
// Inform all existing outgoing unidirectional streams about the new window.
@@ -1239,12 +1382,15 @@ void QuicSession::OnNewStreamUnidirectionalFlowControlWindow(
}
QUIC_DVLOG(1) << ENDPOINT << "Informing unidirectional stream " << id
<< " of new stream flow control window " << new_window;
- kv.second->UpdateSendWindowOffset(new_window);
+ if (!kv.second->ConfigSendWindowOffset(new_window)) {
+ return;
+ }
}
}
void QuicSession::OnNewStreamOutgoingBidirectionalFlowControlWindow(
QuicStreamOffset new_window) {
+ DCHECK_EQ(connection_->version().handshake_protocol, PROTOCOL_TLS1_3);
QUIC_DVLOG(1) << ENDPOINT
<< "OnNewStreamOutgoingBidirectionalFlowControlWindow "
<< new_window;
@@ -1260,12 +1406,15 @@ void QuicSession::OnNewStreamOutgoingBidirectionalFlowControlWindow(
}
QUIC_DVLOG(1) << ENDPOINT << "Informing outgoing bidirectional stream "
<< id << " of new stream flow control window " << new_window;
- kv.second->UpdateSendWindowOffset(new_window);
+ if (!kv.second->ConfigSendWindowOffset(new_window)) {
+ return;
+ }
}
}
void QuicSession::OnNewStreamIncomingBidirectionalFlowControlWindow(
QuicStreamOffset new_window) {
+ DCHECK_EQ(connection_->version().handshake_protocol, PROTOCOL_TLS1_3);
QUIC_DVLOG(1) << ENDPOINT
<< "OnNewStreamIncomingBidirectionalFlowControlWindow "
<< new_window;
@@ -1281,19 +1430,36 @@ void QuicSession::OnNewStreamIncomingBidirectionalFlowControlWindow(
}
QUIC_DVLOG(1) << ENDPOINT << "Informing incoming bidirectional stream "
<< id << " of new stream flow control window " << new_window;
- kv.second->UpdateSendWindowOffset(new_window);
+ if (!kv.second->ConfigSendWindowOffset(new_window)) {
+ return;
+ }
}
}
void QuicSession::OnNewSessionFlowControlWindow(QuicStreamOffset new_window) {
QUIC_DVLOG(1) << ENDPOINT << "OnNewSessionFlowControlWindow " << new_window;
- if (new_window < kMinimumFlowControlSendWindow &&
- !connection_->version().AllowsLowFlowControlLimits()) {
+ bool close_connection = false;
+ if (!connection_->version().AllowsLowFlowControlLimits()) {
+ if (new_window < kMinimumFlowControlSendWindow) {
+ close_connection = true;
+ QUIC_LOG_FIRST_N(ERROR, 1)
+ << "Peer sent us an invalid session flow control send window: "
+ << new_window << ", below default: " << kMinimumFlowControlSendWindow;
+ }
+ } else if (perspective_ == Perspective::IS_CLIENT &&
+ new_window < flow_controller_.send_window_offset()) {
+ // The client receives a lower limit than remembered, violating
+ // https://tools.ietf.org/html/draft-ietf-quic-transport-27#section-7.3.1
QUIC_LOG_FIRST_N(ERROR, 1)
<< "Peer sent us an invalid session flow control send window: "
- << new_window << ", below default: " << kMinimumFlowControlSendWindow;
+ << new_window
+ << ", below current: " << flow_controller_.send_window_offset();
+ close_connection = true;
+ }
+ if (close_connection) {
connection_->CloseConnection(
- QUIC_FLOW_CONTROL_INVALID_WINDOW, "New connection window too low",
+ QUIC_FLOW_CONTROL_INVALID_WINDOW,
+ quiche::QuicheStrCat("New connection window too low: ", new_window),
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
return;
}
@@ -1332,12 +1498,20 @@ void QuicSession::OnNewEncryptionKeyAvailable(
std::unique_ptr<QuicEncrypter> encrypter) {
connection()->SetEncrypter(level, std::move(encrypter));
- if (GetQuicRestartFlag(quic_send_settings_on_write_key_available) &&
- connection_->version().handshake_protocol == PROTOCOL_TLS1_3 &&
+ if (connection_->version().handshake_protocol == PROTOCOL_TLS1_3 &&
+ (perspective() == Perspective::IS_CLIENT ||
+ GetQuicReloadableFlag(quic_change_default_encryption_level))) {
+ QUIC_DVLOG(1) << ENDPOINT << "Set default encryption level to "
+ << EncryptionLevelToString(level);
+ QUIC_RELOADABLE_FLAG_COUNT(quic_change_default_encryption_level);
+ connection()->SetDefaultEncryptionLevel(level);
+ return;
+ }
+
+ if (connection_->version().handshake_protocol == PROTOCOL_TLS1_3 &&
level == ENCRYPTION_FORWARD_SECURE) {
// Set connection's default encryption level once 1-RTT write key is
// available.
- QUIC_RESTART_FLAG_COUNT_N(quic_send_settings_on_write_key_available, 1, 2);
QUIC_DVLOG(1) << ENDPOINT << "Set default encryption level to "
<< EncryptionLevelToString(level);
connection()->SetDefaultEncryptionLevel(level);
@@ -1379,12 +1553,6 @@ void QuicSession::SetDefaultEncryptionLevel(EncryptionLevel level) {
void QuicSession::OnOneRttKeysAvailable() {
DCHECK_EQ(PROTOCOL_TLS1_3, connection_->version().handshake_protocol);
- if (!GetQuicRestartFlag(quic_send_settings_on_write_key_available)) {
- QUIC_DVLOG(1) << ENDPOINT << "Set default encryption level to "
- << EncryptionLevelToString(ENCRYPTION_FORWARD_SECURE);
- connection()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
- }
-
QUIC_BUG_IF(!GetCryptoStream()->crypto_negotiated_params().cipher_suite)
<< ENDPOINT << "Handshake completes without cipher suite negotiation.";
QUIC_BUG_IF(!config_.negotiated())
@@ -1477,7 +1645,7 @@ void QuicSession::ActivateStream(std::unique_ptr<QuicStream> stream) {
QuicStreamId stream_id = stream->id();
bool is_static = stream->is_static();
QUIC_DVLOG(1) << ENDPOINT << "num_streams: " << stream_map_.size()
- << ". activating " << stream_id;
+ << ". activating stream " << stream_id;
DCHECK(!QuicContainsKey(stream_map_, stream_id));
stream_map_[stream_id] = std::move(stream);
if (IsIncomingStream(stream_id)) {
@@ -1486,13 +1654,11 @@ void QuicSession::ActivateStream(std::unique_ptr<QuicStream> stream) {
} else if (is_static) {
++num_outgoing_static_streams_;
}
-
- if (VersionHasIetfQuicFrames(transport_version()) &&
- !QuicUtils::IsBidirectionalStreamId(stream_id) && is_static) {
- DCHECK_LE(num_incoming_static_streams_,
- num_expected_unidirectional_static_streams_);
- DCHECK_LE(num_outgoing_static_streams_,
- num_expected_unidirectional_static_streams_);
+ if (stream_id_manager_.handles_accounting() && !is_static &&
+ !VersionHasIetfQuicFrames(transport_version())) {
+ // Do not inform stream ID manager of static streams.
+ stream_id_manager_.ActivateStream(
+ /*is_incoming=*/IsIncomingStream(stream_id));
}
}
@@ -1585,7 +1751,11 @@ QuicStream* QuicSession::GetOrCreateStream(const QuicStreamId stream_id) {
if (!stream_id_manager_.CanOpenIncomingStream(
GetNumOpenIncomingStreams())) {
// Refuse to open the stream.
- SendRstStream(stream_id, QUIC_REFUSED_STREAM, 0);
+ if (break_close_loop_) {
+ ResetStream(stream_id, QUIC_REFUSED_STREAM, 0);
+ } else {
+ SendRstStream(stream_id, QUIC_REFUSED_STREAM, 0);
+ }
return nullptr;
}
}
@@ -1593,8 +1763,25 @@ QuicStream* QuicSession::GetOrCreateStream(const QuicStreamId stream_id) {
return CreateIncomingStream(stream_id);
}
-void QuicSession::StreamDraining(QuicStreamId stream_id) {
+void QuicSession::StreamDraining(QuicStreamId stream_id, bool unidirectional) {
DCHECK(QuicContainsKey(stream_map_, stream_id));
+ if (deprecate_draining_streams_) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_deprecate_draining_streams);
+ QUIC_DVLOG(1) << ENDPOINT << "Stream " << stream_id << " is draining";
+ if (VersionHasIetfQuicFrames(transport_version())) {
+ v99_streamid_manager_.OnStreamClosed(stream_id);
+ } else if (stream_id_manager_.handles_accounting()) {
+ stream_id_manager_.OnStreamClosed(
+ /*is_incoming=*/IsIncomingStream(stream_id));
+ }
+ if (IsIncomingStream(stream_id)) {
+ ++num_draining_incoming_streams_;
+ return;
+ }
+ ++num_draining_outgoing_streams_;
+ OnCanCreateNewOutgoingStream(unidirectional);
+ return;
+ }
if (!QuicContainsKey(draining_streams_, stream_id)) {
draining_streams_.insert(stream_id);
if (IsIncomingStream(stream_id)) {
@@ -1602,6 +1789,9 @@ void QuicSession::StreamDraining(QuicStreamId stream_id) {
}
if (VersionHasIetfQuicFrames(transport_version())) {
v99_streamid_manager_.OnStreamClosed(stream_id);
+ } else if (stream_id_manager_.handles_accounting()) {
+ stream_id_manager_.OnStreamClosed(
+ /*is_incoming=*/IsIncomingStream(stream_id));
}
}
if (!IsIncomingStream(stream_id)) {
@@ -1735,11 +1925,19 @@ bool QuicSession::IsStaticStream(QuicStreamId id) const {
}
size_t QuicSession::GetNumOpenIncomingStreams() const {
+ DCHECK(!VersionHasIetfQuicFrames(transport_version()));
+ if (stream_id_manager_.handles_accounting()) {
+ return stream_id_manager_.num_open_incoming_streams();
+ }
return num_dynamic_incoming_streams_ - num_draining_incoming_streams_ +
num_locally_closed_incoming_streams_highest_offset_;
}
size_t QuicSession::GetNumOpenOutgoingStreams() const {
+ DCHECK(!VersionHasIetfQuicFrames(transport_version()));
+ if (stream_id_manager_.handles_accounting()) {
+ return stream_id_manager_.num_open_outgoing_streams();
+ }
DCHECK_GE(GetNumDynamicOutgoingStreams() +
GetNumLocallyClosedOutgoingStreamsHighestOffset(),
GetNumDrainingOutgoingStreams());
@@ -1749,11 +1947,22 @@ size_t QuicSession::GetNumOpenOutgoingStreams() const {
}
size_t QuicSession::GetNumActiveStreams() const {
- return stream_map_.size() - draining_streams_.size() -
+ if (!VersionHasIetfQuicFrames(transport_version()) &&
+ stream_id_manager_.handles_accounting()) {
+ // Exclude locally_closed_streams when determine whether to keep connection
+ // alive.
+ return stream_id_manager_.num_open_incoming_streams() +
+ stream_id_manager_.num_open_outgoing_streams() -
+ locally_closed_streams_highest_offset_.size();
+ }
+ return stream_map_.size() - GetNumDrainingStreams() -
num_incoming_static_streams_ - num_outgoing_static_streams_;
}
size_t QuicSession::GetNumDrainingStreams() const {
+ if (deprecate_draining_streams_) {
+ return num_draining_incoming_streams_ + num_draining_outgoing_streams_;
+ }
return draining_streams_.size();
}
@@ -1796,6 +2005,9 @@ size_t QuicSession::GetNumDynamicOutgoingStreams() const {
}
size_t QuicSession::GetNumDrainingOutgoingStreams() const {
+ if (deprecate_draining_streams_) {
+ return num_draining_outgoing_streams_;
+ }
DCHECK_GE(draining_streams_.size(), num_draining_incoming_streams_);
return draining_streams_.size() - num_draining_incoming_streams_;
}
@@ -1840,7 +2052,7 @@ size_t QuicSession::MaxAvailableUnidirectionalStreams() const {
bool QuicSession::IsIncomingStream(QuicStreamId id) const {
if (VersionHasIetfQuicFrames(transport_version())) {
- return v99_streamid_manager_.IsIncomingStream(id);
+ return !QuicUtils::IsOutgoingStreamId(version(), id, perspective_);
}
return stream_id_manager_.IsIncomingStream(id);
}
@@ -1974,9 +2186,6 @@ void QuicSession::OnFrameLost(const QuicFrame& frame) {
void QuicSession::RetransmitFrames(const QuicFrames& frames,
TransmissionType type) {
QuicConnection::ScopedPacketFlusher retransmission_flusher(connection_);
- if (!write_with_transmission_) {
- SetTransmissionType(type);
- }
for (const QuicFrame& frame : frames) {
if (frame.type == MESSAGE_FRAME) {
// Do not retransmit MESSAGE frames.
@@ -2070,18 +2279,12 @@ bool QuicSession::RetransmitLostData() {
bool uses_crypto_frames = QuicVersionUsesCryptoFrames(transport_version());
QuicCryptoStream* crypto_stream = GetMutableCryptoStream();
if (uses_crypto_frames && crypto_stream->HasPendingCryptoRetransmission()) {
- if (!write_with_transmission_) {
- SetTransmissionType(HANDSHAKE_RETRANSMISSION);
- }
crypto_stream->WritePendingCryptoRetransmission();
}
// Retransmit crypto data in stream 1 frames (version < 47).
if (!uses_crypto_frames &&
QuicContainsKey(streams_with_pending_retransmission_,
QuicUtils::GetCryptoStreamId(transport_version()))) {
- if (!write_with_transmission_) {
- SetTransmissionType(HANDSHAKE_RETRANSMISSION);
- }
// Retransmit crypto data first.
QuicStream* crypto_stream =
GetStream(QuicUtils::GetCryptoStreamId(transport_version()));
@@ -2096,9 +2299,6 @@ bool QuicSession::RetransmitLostData() {
}
}
if (control_frame_manager_.HasPendingRetransmission()) {
- if (!write_with_transmission_) {
- SetTransmissionType(LOSS_RETRANSMISSION);
- }
control_frame_manager_.OnCanWrite();
if (control_frame_manager_.HasPendingRetransmission()) {
return false;
@@ -2112,9 +2312,6 @@ bool QuicSession::RetransmitLostData() {
const QuicStreamId id = streams_with_pending_retransmission_.begin()->first;
QuicStream* stream = GetStream(id);
if (stream != nullptr) {
- if (!write_with_transmission_) {
- SetTransmissionType(LOSS_RETRANSMISSION);
- }
stream->OnCanWrite();
DCHECK(CheckStreamWriteBlocked(stream));
if (stream->HasPendingRetransmission()) {
@@ -2260,5 +2457,9 @@ void QuicSession::OnAlpnSelected(quiche::QuicheStringPiece alpn) {
<< "ALPN selected: " << alpn;
}
+void QuicSession::NeuterCryptoDataOfEncryptionLevel(EncryptionLevel level) {
+ GetMutableCryptoStream()->NeuterStreamDataOfEncryptionLevel(level);
+}
+
#undef ENDPOINT // undef for jumbo builds
} // namespace quic
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 ac99a3f7584..5a1ebbc602c 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
@@ -126,6 +126,7 @@ class QUIC_EXPORT_PRIVATE QuicSession
void OnStopSendingFrame(const QuicStopSendingFrame& frame) override;
void OnPacketDecrypted(EncryptionLevel level) override;
void OnOneRttPacketAcknowledged() override;
+ void OnHandshakePacketSent() override;
// QuicStreamFrameDataProducer
WriteStreamDataResult WriteStreamData(QuicStreamId id,
@@ -198,13 +199,17 @@ class QUIC_EXPORT_PRIVATE QuicSession
// will be sent in specified transmission |type|.
bool WriteControlFrame(const QuicFrame& frame, TransmissionType type);
- // Close the stream in both directions.
- // TODO(renjietang): rename this method as it sends both RST_STREAM and
- // STOP_SENDING in IETF QUIC.
+ // Called by stream to send RST_STREAM (and STOP_SENDING).
virtual void SendRstStream(QuicStreamId id,
QuicRstStreamErrorCode error,
QuicStreamOffset bytes_written);
+ // Called to send RST_STREAM (and STOP_SENDING) and close stream. If stream
+ // |id| does not exist, just send RST_STREAM (and STOP_SENDING).
+ virtual void ResetStream(QuicStreamId id,
+ QuicRstStreamErrorCode error,
+ QuicStreamOffset bytes_written);
+
// Called when the session wants to go away and not accept any new streams.
virtual void SendGoAway(QuicErrorCode error_code, const std::string& reason);
@@ -217,9 +222,15 @@ class QUIC_EXPORT_PRIVATE QuicSession
// Create and transmit a STOP_SENDING frame
virtual void SendStopSending(uint16_t code, QuicStreamId stream_id);
- // Removes the stream associated with 'stream_id' from the active stream map.
+ // Close stream |stream_id|. Whether sending RST_STREAM (and STOP_SENDING)
+ // depends on the sending and receiving states.
+ // TODO(fayang): Deprecate CloseStream, instead always use ResetStream to
+ // close a stream from session.
virtual void CloseStream(QuicStreamId stream_id);
+ // Called by stream |stream_id| when it gets closed.
+ virtual void OnStreamClosed(QuicStreamId stream_id);
+
// Returns true if outgoing packets will be encrypted, even if the server
// hasn't confirmed the handshake yet.
virtual bool IsEncryptionEstablished() const;
@@ -316,10 +327,16 @@ class QUIC_EXPORT_PRIVATE QuicSession
// Returns the number of currently open peer initiated streams, excluding
// static streams.
+ // TODO(fayang): remove this and instead use
+ // LegacyStreamIdManager::num_open_incoming_streams() in tests when
+ // deprecating quic_stream_id_manager_handles_accounting.
size_t GetNumOpenIncomingStreams() const;
// Returns the number of currently open self initiated streams, excluding
// static streams.
+ // TODO(fayang): remove this and instead use
+ // LegacyStreamIdManager::num_open_outgoing_streams() in tests when
+ // deprecating quic_stream_id_manager_handles_accounting.
size_t GetNumOpenOutgoingStreams() const;
// Returns the number of open peer initiated static streams.
@@ -365,7 +382,7 @@ class QUIC_EXPORT_PRIVATE QuicSession
bool goaway_received() const { return goaway_received_; }
// Returns the Google QUIC error code
- QuicErrorCode error() const { return on_closed_frame_.extracted_error_code; }
+ QuicErrorCode error() const { return on_closed_frame_.quic_error_code; }
const std::string& error_details() const {
return on_closed_frame_.error_details;
}
@@ -375,12 +392,6 @@ class QUIC_EXPORT_PRIVATE QuicSession
QuicConnectionCloseType close_type() const {
return on_closed_frame_.close_type;
}
- QuicIetfTransportErrorCodes transport_error_code() const {
- return on_closed_frame_.transport_error_code;
- }
- uint16_t application_error_code() const {
- return on_closed_frame_.application_error_code;
- }
Perspective perspective() const { return perspective_; }
@@ -406,16 +417,11 @@ class QUIC_EXPORT_PRIVATE QuicSession
QuicStream* GetOrCreateStream(const QuicStreamId stream_id);
// Mark a stream as draining.
- virtual void StreamDraining(QuicStreamId id);
+ void StreamDraining(QuicStreamId id, bool unidirectional);
// Returns true if this stream should yield writes to another blocked stream.
virtual bool ShouldYield(QuicStreamId stream_id);
- // Set transmission type of next sending packets.
- // TODO(b/136274541): Remove this method or or make it private after
- // gfe2_reloadable_flag_quic_write_with_transmission is deprecated.
- void SetTransmissionType(TransmissionType type);
-
// Clean up closed_streams_.
void CleanUpClosedStreams();
@@ -453,16 +459,8 @@ class QUIC_EXPORT_PRIVATE QuicSession
bool is_configured() const { return is_configured_; }
- QuicStreamCount num_expected_unidirectional_static_streams() const {
- return num_expected_unidirectional_static_streams_;
- }
-
- // Set the number of unidirectional stream that the peer is allowed to open to
- // be |max_stream| + |num_expected_static_streams_|.
- void ConfigureMaxDynamicStreamsToSend(QuicStreamCount max_stream) {
- config_.SetMaxUnidirectionalStreamsToSend(
- max_stream + num_expected_unidirectional_static_streams_);
- }
+ // Called to neuter crypto data of encryption |level|.
+ void NeuterCryptoDataOfEncryptionLevel(EncryptionLevel level);
// Returns the ALPN values to negotiate on this session.
virtual std::vector<std::string> GetAlpnsToOffer() const {
@@ -480,7 +478,26 @@ class QUIC_EXPORT_PRIVATE QuicSession
// uses TLS handshake.
virtual void OnAlpnSelected(quiche::QuicheStringPiece alpn);
- bool write_with_transmission() const { return write_with_transmission_; }
+ bool deprecate_draining_streams() const {
+ return deprecate_draining_streams_;
+ }
+
+ bool break_close_loop() const { return break_close_loop_; }
+
+ // Called on clients by the crypto handshaker to provide application state
+ // necessary for sending application data in 0-RTT. The state provided here is
+ // the same state that was provided to the crypto handshaker in
+ // QuicCryptoClientStream::OnApplicationState on a previous connection.
+ // Application protocols that require state to be carried over from the
+ // previous connection to support 0-RTT data must implement this method to
+ // ingest this state. For example, an HTTP/3 QuicSession would implement this
+ // function to process the remembered server SETTINGS frame and apply those
+ // SETTINGS to 0-RTT data. This function returns true if the application state
+ // has been successfully processed, and false if there was an error processing
+ // the cached state and the connection should be closed.
+ virtual bool SetApplicationState(ApplicationState* /*cached_state*/) {
+ return true;
+ }
protected:
using StreamMap = QuicSmallMap<QuicStreamId, std::unique_ptr<QuicStream>, 10>;
@@ -508,6 +525,9 @@ class QUIC_EXPORT_PRIVATE QuicSession
// Adds |stream| to the stream map.
virtual void ActivateStream(std::unique_ptr<QuicStream> stream);
+ // Set transmission type of next sending packets.
+ void SetTransmissionType(TransmissionType type);
+
// Returns the stream ID for a new outgoing bidirectional/unidirectional
// stream, and increments the underlying counter.
QuicStreamId GetNextOutgoingBidirectionalStreamId();
@@ -530,6 +550,7 @@ class QUIC_EXPORT_PRIVATE QuicSession
// Performs the work required to close |stream_id|. If |rst_sent| then a
// Reset Stream frame has already been sent for this stream.
+ // TODO(fayang): Remove CloseStreamInner.
virtual void CloseStreamInner(QuicStreamId stream_id, bool rst_sent);
// When a stream is closed locally, it may not yet know how many bytes the
@@ -546,6 +567,10 @@ class QUIC_EXPORT_PRIVATE QuicSession
// ProcessPendingStream().
virtual bool UsesPendingStreams() const { return false; }
+ spdy::SpdyPriority GetSpdyPriorityofStream(QuicStreamId stream_id) const {
+ return write_blocked_streams_.GetSpdyPriorityofStream(stream_id);
+ }
+
StreamMap& stream_map() { return stream_map_; }
const StreamMap& stream_map() const { return stream_map_; }
@@ -734,10 +759,12 @@ class QUIC_EXPORT_PRIVATE QuicSession
// Set of stream ids that are "draining" -- a FIN has been sent and received,
// but the stream object still exists because not all the received data has
// been consumed.
- QuicUnorderedSet<QuicStreamId> draining_streams_;
+ // TODO(fayang): Remove draining_streams_ when deprecate
+ // quic_deprecate_draining_streams.
+ QuicHashSet<QuicStreamId> draining_streams_;
// Set of stream ids that are waiting for acks excluding crypto stream id.
- QuicUnorderedSet<QuicStreamId> streams_waiting_for_acks_;
+ QuicHashSet<QuicStreamId> streams_waiting_for_acks_;
// TODO(fayang): Consider moving LegacyQuicStreamIdManager into
// UberQuicStreamIdManager.
@@ -748,11 +775,23 @@ class QUIC_EXPORT_PRIVATE QuicSession
UberQuicStreamIdManager v99_streamid_manager_;
// A counter for peer initiated dynamic streams which are in the stream_map_.
+ // TODO(fayang): Remove this when deprecating
+ // quic_stream_id_manager_handles_accounting.
size_t num_dynamic_incoming_streams_;
- // A counter for peer initiated streams which are in the draining_streams_.
+ // A counter for peer initiated streams which have sent and received FIN but
+ // waiting for application to consume data.
+ // TODO(fayang): Remove this when deprecating
+ // quic_stream_id_manager_handles_accounting.
size_t num_draining_incoming_streams_;
+ // A counter for self initiated streams which have sent and received FIN but
+ // waiting for application to consume data. Only used when
+ // deprecate_draining_streams_ is true.
+ // TODO(fayang): Remove this when deprecating
+ // quic_stream_id_manager_handles_accounting.
+ size_t num_draining_outgoing_streams_;
+
// A counter for self initiated static streams which are in
// stream_map_.
size_t num_outgoing_static_streams_;
@@ -763,6 +802,8 @@ class QUIC_EXPORT_PRIVATE QuicSession
// A counter for peer initiated streams which are in the
// locally_closed_streams_highest_offset_.
+ // TODO(fayang): Remove this when deprecating
+ // quic_stream_id_manager_handles_accounting.
size_t num_locally_closed_incoming_streams_highest_offset_;
// Received information for a connection close.
@@ -809,14 +850,14 @@ class QUIC_EXPORT_PRIVATE QuicSession
// configured and is ready for general operation.
bool is_configured_;
- // The number of expected static streams.
- QuicStreamCount num_expected_unidirectional_static_streams_;
-
// If true, enables round robin scheduling.
bool enable_round_robin_scheduling_;
- // Latched value of gfe2_reloadable_flag_quic_write_with_transmission.
- const bool write_with_transmission_;
+ // Latched value of quic_deprecate_draining_streams.
+ const bool deprecate_draining_streams_;
+
+ // Latched value of quic_break_session_stream_close_loop.
+ const bool break_close_loop_;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_session_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_session_test.cc
index 4da502dc422..9d5e977d0a6 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
@@ -83,7 +83,8 @@ class TestCryptoStream : public QuicCryptoStream, public QuicCryptoHandshaker {
EXPECT_TRUE(
session()->config()->FillTransportParameters(&transport_parameters));
error = session()->config()->ProcessTransportParameters(
- transport_parameters, CLIENT, &error_details);
+ transport_parameters, CLIENT, /* is_resumption = */ false,
+ &error_details);
} else {
CryptoHandshakeMessage msg;
session()->config()->ToHandshakeMessage(&msg, transport_version());
@@ -117,15 +118,16 @@ class TestCryptoStream : public QuicCryptoStream, public QuicCryptoHandshaker {
}
void OnPacketDecrypted(EncryptionLevel /*level*/) override {}
void OnOneRttPacketAcknowledged() override {}
+ void OnHandshakePacketSent() override {}
void OnHandshakeDoneReceived() override {}
HandshakeState GetHandshakeState() const override {
return one_rtt_keys_available() ? HANDSHAKE_COMPLETE : HANDSHAKE_START;
}
- MOCK_METHOD0(OnCanWrite, void());
+ MOCK_METHOD(void, OnCanWrite, (), (override));
bool HasPendingCryptoRetransmission() const override { return false; }
- MOCK_CONST_METHOD0(HasPendingRetransmission, bool());
+ MOCK_METHOD(bool, HasPendingRetransmission, (), (const, override));
private:
using QuicCryptoStream::session;
@@ -155,11 +157,13 @@ class TestStream : public QuicStream {
void OnDataAvailable() override {}
- MOCK_METHOD0(OnCanWrite, void());
- MOCK_METHOD4(RetransmitStreamData,
- bool(QuicStreamOffset, QuicByteCount, bool, TransmissionType));
+ MOCK_METHOD(void, OnCanWrite, (), (override));
+ MOCK_METHOD(bool,
+ RetransmitStreamData,
+ (QuicStreamOffset, QuicByteCount, bool, TransmissionType),
+ (override));
- MOCK_CONST_METHOD0(HasPendingRetransmission, bool());
+ MOCK_METHOD(bool, HasPendingRetransmission, (), (const, override));
};
class TestSession : public QuicSession {
@@ -211,9 +215,9 @@ class TestSession : public QuicSession {
TestStream* CreateIncomingStream(QuicStreamId id) override {
// Enforce the limit on the number of open streams.
- if (GetNumOpenIncomingStreams() + 1 >
- max_open_incoming_bidirectional_streams() &&
- !VersionHasIetfQuicFrames(connection()->transport_version())) {
+ if (!VersionHasIetfQuicFrames(connection()->transport_version()) &&
+ GetNumOpenIncomingStreams() + 1 >
+ max_open_incoming_bidirectional_streams()) {
// No need to do this test for version 99; it's done by
// QuicSession::GetOrCreateStream.
connection()->CloseConnection(
@@ -286,7 +290,10 @@ class TestSession : public QuicSession {
return consumed;
}
- MOCK_METHOD1(OnCanCreateNewOutgoingStream, void(bool unidirectional));
+ MOCK_METHOD(void,
+ OnCanCreateNewOutgoingStream,
+ (bool unidirectional),
+ (override));
void set_writev_consumes_all_data(bool val) {
writev_consumes_all_data_ = val;
@@ -1771,21 +1778,6 @@ TEST_P(QuicSessionTestServer, InvalidStreamFlowControlWindowInHandshake) {
session_.OnConfigNegotiated();
}
-TEST_P(QuicSessionTestServer, InvalidSessionFlowControlWindowInHandshake) {
- // Test that receipt of an invalid (< default) session flow control window
- // from the peer results in the connection being torn down.
- const uint32_t kInvalidWindow = kMinimumFlowControlSendWindow - 1;
- QuicConfigPeer::SetReceivedInitialSessionFlowControlWindow(session_.config(),
- kInvalidWindow);
- if (!connection_->version().AllowsLowFlowControlLimits()) {
- EXPECT_CALL(*connection_,
- CloseConnection(QUIC_FLOW_CONTROL_INVALID_WINDOW, _, _));
- } else {
- EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0);
- }
- session_.OnConfigNegotiated();
-}
-
// Test negotiation of custom server initial flow control window.
TEST_P(QuicSessionTestServer, CustomFlowControlWindow) {
QuicTagVector copt;
@@ -1883,7 +1875,7 @@ TEST_P(QuicSessionTestServer, DrainingStreamsDoNotCountAsOpenedOutgoing) {
QuicStreamFrame data1(stream_id, true, 0, quiche::QuicheStringPiece("HT"));
session_.OnStreamFrame(data1);
EXPECT_CALL(session_, OnCanCreateNewOutgoingStream(false)).Times(1);
- session_.StreamDraining(stream_id);
+ session_.StreamDraining(stream_id, /*unidirectional=*/false);
}
TEST_P(QuicSessionTestServer, NoPendingStreams) {
@@ -1931,20 +1923,20 @@ TEST_P(QuicSessionTestServer, RstPendingStreams) {
session_.OnStreamFrame(data1);
EXPECT_TRUE(QuicSessionPeer::GetPendingStream(&session_, stream_id));
EXPECT_EQ(0, session_.num_incoming_streams_created());
- EXPECT_EQ(0u, session_.GetNumOpenIncomingStreams());
+ EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(&session_));
QuicRstStreamFrame rst1(kInvalidControlFrameId, stream_id,
QUIC_ERROR_PROCESSING_STREAM, 12);
session_.OnRstStream(rst1);
EXPECT_FALSE(QuicSessionPeer::GetPendingStream(&session_, stream_id));
EXPECT_EQ(0, session_.num_incoming_streams_created());
- EXPECT_EQ(0u, session_.GetNumOpenIncomingStreams());
+ EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(&session_));
QuicStreamFrame data2(stream_id, false, 0, quiche::QuicheStringPiece("HT"));
session_.OnStreamFrame(data2);
EXPECT_FALSE(QuicSessionPeer::GetPendingStream(&session_, stream_id));
EXPECT_EQ(0, session_.num_incoming_streams_created());
- EXPECT_EQ(0u, session_.GetNumOpenIncomingStreams());
+ EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(&session_));
}
TEST_P(QuicSessionTestServer, OnFinPendingStreams) {
@@ -1960,7 +1952,7 @@ TEST_P(QuicSessionTestServer, OnFinPendingStreams) {
EXPECT_FALSE(QuicSessionPeer::GetPendingStream(&session_, stream_id));
EXPECT_EQ(0, session_.num_incoming_streams_created());
- EXPECT_EQ(0u, session_.GetNumOpenIncomingStreams());
+ EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(&session_));
}
TEST_P(QuicSessionTestServer, PendingStreamOnWindowUpdate) {
@@ -2013,9 +2005,9 @@ TEST_P(QuicSessionTestServer, DrainingStreamsDoNotCountAsOpened) {
i += QuicUtils::StreamIdDelta(connection_->transport_version())) {
QuicStreamFrame data1(i, true, 0, quiche::QuicheStringPiece("HT"));
session_.OnStreamFrame(data1);
- EXPECT_EQ(1u, session_.GetNumOpenIncomingStreams());
- session_.StreamDraining(i);
- EXPECT_EQ(0u, session_.GetNumOpenIncomingStreams());
+ EXPECT_EQ(1u, QuicSessionPeer::GetNumOpenDynamicStreams(&session_));
+ session_.StreamDraining(i, /*unidirectional=*/false);
+ EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(&session_));
}
}
@@ -2048,6 +2040,57 @@ TEST_P(QuicSessionTestClient, AvailableBidirectionalStreamsClient) {
&session_, GetNthClientInitiatedBidirectionalId(1)));
}
+TEST_P(QuicSessionTestClient, InvalidSessionFlowControlWindowInHandshake) {
+ // Test that receipt of an invalid (< default for gQUIC, < current for TLS)
+ // session flow control window from the peer results in the connection being
+ // torn down.
+ const uint32_t kInvalidWindow = kMinimumFlowControlSendWindow - 1;
+ QuicConfigPeer::SetReceivedInitialSessionFlowControlWindow(session_.config(),
+ kInvalidWindow);
+ EXPECT_CALL(*connection_,
+ CloseConnection(QUIC_FLOW_CONTROL_INVALID_WINDOW, _, _));
+ session_.OnConfigNegotiated();
+}
+
+TEST_P(QuicSessionTestClient, InvalidBidiStreamLimitInHandshake) {
+ // IETF QUIC only feature.
+ if (!VersionHasIetfQuicFrames(transport_version())) {
+ return;
+ }
+ QuicConfigPeer::SetReceivedMaxBidirectionalStreams(
+ session_.config(), kDefaultMaxStreamsPerConnection - 1);
+ EXPECT_CALL(*connection_, CloseConnection(QUIC_MAX_STREAMS_ERROR, _, _));
+ session_.OnConfigNegotiated();
+}
+
+TEST_P(QuicSessionTestClient, InvalidUniStreamLimitInHandshake) {
+ // IETF QUIC only feature.
+ if (!VersionHasIetfQuicFrames(transport_version())) {
+ return;
+ }
+ QuicConfigPeer::SetReceivedMaxUnidirectionalStreams(
+ session_.config(), kDefaultMaxStreamsPerConnection - 1);
+ EXPECT_CALL(*connection_, CloseConnection(QUIC_MAX_STREAMS_ERROR, _, _));
+ session_.OnConfigNegotiated();
+}
+
+TEST_P(QuicSessionTestClient, InvalidStreamFlowControlWindowInHandshake) {
+ // IETF QUIC only feature.
+ if (!VersionHasIetfQuicFrames(transport_version())) {
+ return;
+ }
+ session_.CreateOutgoingBidirectionalStream();
+ session_.CreateOutgoingBidirectionalStream();
+ QuicConfigPeer::SetReceivedInitialMaxStreamDataBytesOutgoingBidirectional(
+ session_.config(), kMinimumFlowControlSendWindow - 1);
+
+ EXPECT_CALL(*connection_, CloseConnection(_, _, _))
+ .WillOnce(
+ Invoke(connection_, &MockQuicConnection::ReallyCloseConnection));
+ EXPECT_CALL(*connection_, SendConnectionClosePacket(_, _));
+ session_.OnConfigNegotiated();
+}
+
TEST_P(QuicSessionTestClient, OnMaxStreamFrame) {
if (!VersionUsesHttp3(transport_version())) {
return;
@@ -2387,8 +2430,14 @@ TEST_P(QuicSessionTestServer, RetransmitLostDataCausesConnectionClose) {
session_.OnFrameLost(QuicFrame(frame));
// Retransmit stream data causes connection close. Stream has not sent fin
// yet, so an RST is sent.
- EXPECT_CALL(*stream, OnCanWrite())
- .WillOnce(Invoke(stream, &QuicStream::OnClose));
+ if (session_.break_close_loop()) {
+ EXPECT_CALL(*stream, OnCanWrite()).WillOnce(Invoke([this, stream]() {
+ session_.CloseStream(stream->id());
+ }));
+ } else {
+ EXPECT_CALL(*stream, OnCanWrite())
+ .WillOnce(Invoke(stream, &QuicStream::OnClose));
+ }
if (VersionHasIetfQuicFrames(transport_version())) {
// Once for the RST_STREAM, once for the STOP_SENDING
EXPECT_CALL(*connection_, SendControlFrame(_))
@@ -2746,6 +2795,7 @@ TEST_P(QuicSessionTestServer, OnStopSendingForWriteClosedStream) {
TestStream* stream = session_.CreateOutgoingBidirectionalStream();
QuicStreamId stream_id = stream->id();
+ QuicStreamPeer::SetFinSent(stream);
stream->CloseWriteSide();
EXPECT_TRUE(stream->write_side_closed());
QuicStopSendingFrame frame(1, stream_id, 123);
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 86beaef0f7b..40a67bba21c 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
@@ -4,6 +4,7 @@
#include "net/third_party/quiche/src/quic/core/quic_stream.h"
+#include <limits>
#include <string>
#include "net/third_party/quiche/src/quic/core/quic_error_codes.h"
@@ -29,15 +30,15 @@ namespace quic {
namespace {
-size_t DefaultFlowControlWindow(ParsedQuicVersion version) {
+QuicByteCount DefaultFlowControlWindow(ParsedQuicVersion version) {
if (!version.AllowsLowFlowControlLimits()) {
return kDefaultFlowControlSendWindow;
}
return 0;
}
-size_t GetInitialStreamFlowControlWindowToSend(QuicSession* session,
- QuicStreamId stream_id) {
+QuicByteCount GetInitialStreamFlowControlWindowToSend(QuicSession* session,
+ QuicStreamId stream_id) {
ParsedQuicVersion version = session->connection()->version();
if (version.handshake_protocol != PROTOCOL_TLS1_3) {
return session->config()->GetInitialStreamFlowControlWindowToSend();
@@ -60,8 +61,8 @@ size_t GetInitialStreamFlowControlWindowToSend(QuicSession* session,
->GetInitialMaxStreamDataBytesIncomingBidirectionalToSend();
}
-size_t GetReceivedFlowControlWindow(QuicSession* session,
- QuicStreamId stream_id) {
+QuicByteCount GetReceivedFlowControlWindow(QuicSession* session,
+ QuicStreamId stream_id) {
ParsedQuicVersion version = session->connection()->version();
if (version.handshake_protocol != PROTOCOL_TLS1_3) {
if (session->config()->HasReceivedInitialStreamFlowControlWindowBytes()) {
@@ -189,7 +190,7 @@ void PendingStream::OnStreamFrame(const QuicStreamFrame& frame) {
}
// This count includes duplicate data received.
- size_t frame_payload_size = frame.data_length;
+ QuicByteCount frame_payload_size = frame.data_length;
stream_bytes_read_ += frame_payload_size;
// Flow control is interested in tracking highest received offset.
@@ -257,7 +258,7 @@ bool PendingStream::MaybeIncreaseHighestReceivedOffset(
return true;
}
-void PendingStream::MarkConsumed(size_t num_bytes) {
+void PendingStream::MarkConsumed(QuicByteCount num_bytes) {
sequencer_.MarkConsumed(num_bytes);
}
@@ -353,6 +354,7 @@ QuicStream::QuicStream(QuicStreamId id,
buffered_data_threshold_(GetQuicFlag(FLAGS_quic_buffered_data_threshold)),
is_static_(is_static),
deadline_(QuicTime::Zero()),
+ was_draining_(false),
type_(VersionHasIetfQuicFrames(session->transport_version()) &&
type != CRYPTO
? QuicUtils::GetStreamType(id_,
@@ -361,10 +363,10 @@ QuicStream::QuicStream(QuicStreamId id,
: type),
perspective_(session->perspective()) {
if (type_ == WRITE_UNIDIRECTIONAL) {
- set_fin_received(true);
+ fin_received_ = true;
CloseReadSide();
} else if (type_ == READ_UNIDIRECTIONAL) {
- set_fin_sent(true);
+ fin_sent_ = true;
CloseWriteSide();
}
if (type_ != CRYPTO) {
@@ -431,9 +433,14 @@ void QuicStream::OnStreamFrame(const QuicStreamFrame& frame) {
}
if (frame.fin) {
- fin_received_ = true;
- if (fin_sent_) {
- session_->StreamDraining(id_);
+ if (!session_->deprecate_draining_streams() || !fin_received_) {
+ fin_received_ = true;
+ if (fin_sent_) {
+ DCHECK(!was_draining_ || !session_->deprecate_draining_streams());
+ session_->StreamDraining(id_,
+ /*unidirectional=*/type_ != BIDIRECTIONAL);
+ was_draining_ = true;
+ }
}
}
@@ -446,7 +453,7 @@ void QuicStream::OnStreamFrame(const QuicStreamFrame& frame) {
}
// This count includes duplicate data received.
- size_t frame_payload_size = frame.data_length;
+ QuicByteCount frame_payload_size = frame.data_length;
stream_bytes_read_ += frame_payload_size;
// Flow control is interested in tracking highest received offset.
@@ -455,7 +462,10 @@ void QuicStream::OnStreamFrame(const QuicStreamFrame& frame) {
MaybeIncreaseHighestReceivedOffset(frame.offset + frame_payload_size)) {
// As the highest received offset has changed, check to see if this is a
// violation of flow control.
- if (flow_controller_->FlowControlViolation() ||
+ QUIC_BUG_IF(!flow_controller_.has_value())
+ << ENDPOINT << "OnStreamFrame called on stream without flow control";
+ if ((flow_controller_.has_value() &&
+ flow_controller_->FlowControlViolation()) ||
connection_flow_controller_->FlowControlViolation()) {
OnUnrecoverableError(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA,
"Flow control violation after increasing offset");
@@ -519,7 +529,10 @@ void QuicStream::OnStreamReset(const QuicRstStreamFrame& frame) {
}
MaybeIncreaseHighestReceivedOffset(frame.byte_offset);
- if (flow_controller_->FlowControlViolation() ||
+ QUIC_BUG_IF(!flow_controller_.has_value())
+ << ENDPOINT << "OnStreamReset called on stream without flow control";
+ if ((flow_controller_.has_value() &&
+ flow_controller_->FlowControlViolation()) ||
connection_flow_controller_->FlowControlViolation()) {
OnUnrecoverableError(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA,
"Flow control violation after increasing offset");
@@ -560,11 +573,23 @@ void QuicStream::OnFinRead() {
CloseReadSide();
}
+void QuicStream::SetFinSent() {
+ DCHECK(!VersionUsesHttp3(transport_version()));
+ fin_sent_ = true;
+}
+
void QuicStream::Reset(QuicRstStreamErrorCode error) {
stream_error_ = error;
- // Sending a RstStream results in calling CloseStream.
session()->SendRstStream(id(), error, stream_bytes_written());
rst_sent_ = true;
+ if (session_->break_close_loop()) {
+ if (read_side_closed_ && write_side_closed_ && !IsWaitingForAcks()) {
+ session()->OnStreamDoneWaitingForAcks(id_);
+ return;
+ }
+ CloseReadSide();
+ CloseWriteSide();
+ }
}
void QuicStream::OnUnrecoverableError(QuicErrorCode error,
@@ -660,6 +685,11 @@ void QuicStream::OnCanWrite() {
}
void QuicStream::MaybeSendBlocked() {
+ if (!flow_controller_.has_value()) {
+ QUIC_BUG << ENDPOINT
+ << "MaybeSendBlocked called on stream without flow control";
+ return;
+ }
if (flow_controller_->ShouldSendBlocked()) {
session_->SendBlocked(id_);
}
@@ -751,7 +781,12 @@ void QuicStream::CloseReadSide() {
if (write_side_closed_) {
QUIC_DVLOG(1) << ENDPOINT << "Closing stream " << id();
- session_->CloseStream(id());
+ if (session_->break_close_loop()) {
+ session_->OnStreamClosed(id());
+ OnClose();
+ } else {
+ session_->CloseStream(id());
+ }
}
}
@@ -764,7 +799,12 @@ void QuicStream::CloseWriteSide() {
write_side_closed_ = true;
if (read_side_closed_) {
QUIC_DVLOG(1) << ENDPOINT << "Closing stream " << id();
- session_->CloseStream(id());
+ if (session_->break_close_loop()) {
+ session_->OnStreamClosed(id());
+ OnClose();
+ } else {
+ session_->CloseStream(id());
+ }
}
}
@@ -787,8 +827,12 @@ void QuicStream::StopReading() {
}
void QuicStream::OnClose() {
- CloseReadSide();
- CloseWriteSide();
+ if (session()->break_close_loop()) {
+ DCHECK(read_side_closed_ && write_side_closed_);
+ } else {
+ CloseReadSide();
+ CloseWriteSide();
+ }
if (!fin_sent_ && !rst_sent_) {
// For flow control accounting, tell the peer how many bytes have been
@@ -801,7 +845,8 @@ void QuicStream::OnClose() {
rst_sent_ = true;
}
- if (flow_controller_->FlowControlViolation() ||
+ if (!flow_controller_.has_value() ||
+ flow_controller_->FlowControlViolation() ||
connection_flow_controller_->FlowControlViolation()) {
return;
}
@@ -823,6 +868,12 @@ void QuicStream::OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) {
return;
}
+ if (!flow_controller_.has_value()) {
+ QUIC_BUG << ENDPOINT
+ << "OnWindowUpdateFrame called on stream without flow control";
+ return;
+ }
+
if (flow_controller_->UpdateSendWindowOffset(frame.max_data)) {
// Let session unblock this stream.
session_->MarkConnectionLevelWriteBlocked(id_);
@@ -831,6 +882,12 @@ void QuicStream::OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) {
bool QuicStream::MaybeIncreaseHighestReceivedOffset(
QuicStreamOffset new_offset) {
+ if (!flow_controller_.has_value()) {
+ QUIC_BUG << ENDPOINT
+ << "MaybeIncreaseHighestReceivedOffset called on stream without "
+ "flow control";
+ return false;
+ }
uint64_t increment =
new_offset - flow_controller_->highest_received_byte_offset();
if (!flow_controller_->UpdateHighestReceivedOffset(new_offset)) {
@@ -849,6 +906,11 @@ bool QuicStream::MaybeIncreaseHighestReceivedOffset(
}
void QuicStream::AddBytesSent(QuicByteCount bytes) {
+ if (!flow_controller_.has_value()) {
+ QUIC_BUG << ENDPOINT
+ << "AddBytesSent called on stream without flow control";
+ return;
+ }
flow_controller_->AddBytesSent(bytes);
if (stream_contributes_to_connection_flow_control_) {
connection_flow_controller_->AddBytesSent(bytes);
@@ -862,6 +924,12 @@ void QuicStream::AddBytesConsumed(QuicByteCount bytes) {
// QuicStreamSequencers used by QuicCryptoStream.
return;
}
+ if (!flow_controller_.has_value()) {
+ QUIC_BUG
+ << ENDPOINT
+ << "AddBytesConsumed called on non-crypto stream without flow control";
+ return;
+ }
// Only adjust stream level flow controller if still reading.
if (!read_side_closed_) {
flow_controller_->AddBytesConsumed(bytes);
@@ -872,11 +940,27 @@ void QuicStream::AddBytesConsumed(QuicByteCount bytes) {
}
}
-void QuicStream::UpdateSendWindowOffset(QuicStreamOffset new_window) {
- if (flow_controller_->UpdateSendWindowOffset(new_window)) {
+bool QuicStream::ConfigSendWindowOffset(QuicStreamOffset new_offset) {
+ if (!flow_controller_.has_value()) {
+ QUIC_BUG << ENDPOINT
+ << "ConfigSendWindowOffset called on stream without flow control";
+ return false;
+ }
+ if (perspective_ == Perspective::IS_CLIENT &&
+ session()->version().AllowsLowFlowControlLimits() &&
+ new_offset < flow_controller_->send_window_offset()) {
+ OnUnrecoverableError(
+ QUIC_FLOW_CONTROL_INVALID_WINDOW,
+ quiche::QuicheStrCat("New stream max data ", new_offset,
+ " decreases current limit: ",
+ flow_controller_->send_window_offset()));
+ return false;
+ }
+ if (flow_controller_->UpdateSendWindowOffset(new_offset)) {
// Let session unblock this stream.
session_->MarkConnectionLevelWriteBlocked(id_);
}
+ return true;
}
void QuicStream::AddRandomPaddingAfterFin() {
@@ -999,7 +1083,7 @@ bool QuicStream::IsWaitingForAcks() const {
(send_buffer_.stream_bytes_outstanding() || fin_outstanding_);
}
-size_t QuicStream::ReadableBytes() const {
+QuicByteCount QuicStream::ReadableBytes() const {
return sequencer_.ReadableBytes();
}
@@ -1021,7 +1105,7 @@ void QuicStream::WriteBufferedData() {
}
// Size of buffered data.
- size_t write_length = BufferedDataBytes();
+ QuicByteCount write_length = BufferedDataBytes();
// A FIN with zero data payload should not be flow control blocked.
bool fin_with_zero_data = (fin_buffered_ && write_length == 0);
@@ -1029,7 +1113,14 @@ void QuicStream::WriteBufferedData() {
bool fin = fin_buffered_;
// How much data flow control permits to be written.
- QuicByteCount send_window = flow_controller_->SendWindowSize();
+ QuicByteCount send_window;
+ if (flow_controller_.has_value()) {
+ send_window = flow_controller_->SendWindowSize();
+ } else {
+ send_window = std::numeric_limits<QuicByteCount>::max();
+ QUIC_BUG << ENDPOINT
+ << "WriteBufferedData called on stream without flow control";
+ }
if (stream_contributes_to_connection_flow_control_) {
send_window =
std::min(send_window, connection_flow_controller_->SendWindowSize());
@@ -1046,13 +1137,10 @@ void QuicStream::WriteBufferedData() {
fin = false;
// Writing more data would be a violation of flow control.
- write_length = static_cast<size_t>(send_window);
+ write_length = send_window;
QUIC_DVLOG(1) << "stream " << id() << " shortens write length to "
<< write_length << " due to flow control";
}
- if (!session_->write_with_transmission()) {
- session_->SetTransmissionType(NOT_RETRANSMISSION);
- }
StreamSendingState state = fin ? FIN : NO_FIN;
if (fin && add_random_padding_after_fin_) {
@@ -1082,10 +1170,14 @@ void QuicStream::WriteBufferedData() {
MaybeSendBlocked();
}
if (fin && consumed_data.fin_consumed) {
+ DCHECK(!fin_sent_);
fin_sent_ = true;
fin_outstanding_ = true;
if (fin_received_) {
- session_->StreamDraining(id_);
+ DCHECK(!was_draining_);
+ session_->StreamDraining(id_,
+ /*unidirectional=*/type_ != BIDIRECTIONAL);
+ was_draining_ = true;
}
CloseWriteSide();
} else if (fin && !consumed_data.fin_consumed) {
@@ -1124,7 +1216,7 @@ const QuicIntervalSet<QuicStreamOffset>& QuicStream::bytes_acked() const {
return send_buffer_.bytes_acked();
}
-void QuicStream::OnStreamDataConsumed(size_t bytes_consumed) {
+void QuicStream::OnStreamDataConsumed(QuicByteCount bytes_consumed) {
send_buffer_.OnStreamDataConsumed(bytes_consumed);
}
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 aa2e11d5a60..fe9d04c021f 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
@@ -76,7 +76,7 @@ class QUIC_EXPORT_PRIVATE PendingStream
const QuicStreamSequencer* sequencer() const { return &sequencer_; }
- void MarkConsumed(size_t num_bytes);
+ void MarkConsumed(QuicByteCount num_bytes);
// Tells the sequencer to ignore all incoming data itself and not call
// OnDataAvailable().
@@ -165,10 +165,12 @@ class QUIC_EXPORT_PRIVATE QuicStream
// stream to write any pending data.
virtual void OnCanWrite();
- // Called by the session just before the object is destroyed.
+ // Called just before the object is destroyed.
// The object should not be accessed after OnClose is called.
// Sends a RST_STREAM with code QUIC_RST_ACKNOWLEDGEMENT if neither a FIN nor
// a RST_STREAM has been sent.
+ // TODO(fayang): move this to protected when deprecating
+ // quic_break_session_stream_close_loop.
virtual void OnClose();
// Called by the session when the endpoint receives a RST_STREAM from the
@@ -199,7 +201,7 @@ class QUIC_EXPORT_PRIVATE QuicStream
bool IsWaitingForAcks() const;
// Number of bytes available to read.
- size_t ReadableBytes() const;
+ QuicByteCount ReadableBytes() const;
QuicRstStreamErrorCode stream_error() const { return stream_error_; }
QuicErrorCode connection_error() const { return connection_error_; }
@@ -224,8 +226,6 @@ class QUIC_EXPORT_PRIVATE QuicStream
size_t busy_counter() const { return busy_counter_; }
void set_busy_counter(size_t busy_counter) { busy_counter_ = busy_counter; }
- void set_fin_sent(bool fin_sent) { fin_sent_ = fin_sent; }
- void set_fin_received(bool fin_received) { fin_received_ = fin_received; }
void set_rst_sent(bool rst_sent) { rst_sent_ = rst_sent; }
void set_rst_received(bool rst_received) { rst_received_ = rst_received; }
@@ -244,9 +244,8 @@ class QUIC_EXPORT_PRIVATE QuicStream
// Returns true if the highest offset did increase.
bool MaybeIncreaseHighestReceivedOffset(QuicStreamOffset new_offset);
- // Updates the flow controller's send window offset and calls OnCanWrite if
- // it was blocked before.
- void UpdateSendWindowOffset(QuicStreamOffset new_offset);
+ // Set the flow controller's send window offset from session config.
+ bool ConfigSendWindowOffset(QuicStreamOffset new_offset);
// Returns true if the stream has received either a RST_STREAM or a FIN -
// either of which gives a definitive number of bytes which the peer has
@@ -357,19 +356,23 @@ class QUIC_EXPORT_PRIVATE QuicStream
// Does not send a FIN. May cause the stream to be closed.
virtual void CloseWriteSide();
+ // Close the read side of the stream. May cause the stream to be closed.
+ // Subclasses and consumers should use StopReading to terminate reading early
+ // if expecting a FIN. Can be used directly by subclasses if not expecting a
+ // FIN.
+ // TODO(fayang): move this to protected when removing
+ // QuicSession::CloseStream.
+ void CloseReadSide();
+
// Returns true if the stream is static.
bool is_static() const { return is_static_; }
+ bool was_draining() const { return was_draining_; }
+
static spdy::SpdyStreamPrecedence CalculateDefaultPriority(
const QuicSession* session);
protected:
- // 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
- // FIN.
- void CloseReadSide();
-
// Called when data of [offset, offset + data_length] is buffered in send
// buffer.
virtual void OnDataBuffered(
@@ -389,7 +392,7 @@ class QUIC_EXPORT_PRIVATE QuicStream
virtual void OnCanWriteNewData() {}
// Called when |bytes_consumed| bytes has been consumed.
- virtual void OnStreamDataConsumed(size_t bytes_consumed);
+ virtual void OnStreamDataConsumed(QuicByteCount bytes_consumed);
// Called by the stream sequencer as bytes are consumed from the buffer.
// If the receive window has dropped below the threshold, then send a
@@ -403,6 +406,10 @@ class QUIC_EXPORT_PRIVATE QuicStream
// this virtual so that subclasses can implement their own logics.
virtual void OnDeadlinePassed();
+ // Called to set fin_sent_. This is only used by Google QUIC while body is
+ // empty.
+ void SetFinSent();
+
StreamDelegateInterface* stream_delegate() { return stream_delegate_; }
bool fin_buffered() const { return fin_buffered_; }
@@ -532,6 +539,10 @@ class QUIC_EXPORT_PRIVATE QuicStream
// If initialized, reset this stream at this deadline.
QuicTime deadline_;
+ // True if this stream has entered draining state. Only used when
+ // quic_deprecate_draining_streams is true.
+ bool was_draining_;
+
// Indicates whether this stream is bidirectional, read unidirectional or
// write unidirectional.
const StreamType type_;
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager.cc b/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager.cc
index c6869a23b12..ba31decd2b9 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager.cc
@@ -10,6 +10,7 @@
#include "net/third_party/quiche/src/quic/core/quic_constants.h"
#include "net/third_party/quiche/src/quic/core/quic_session.h"
#include "net/third_party/quiche/src/quic/core/quic_utils.h"
+#include "net/third_party/quiche/src/quic/core/quic_versions.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"
@@ -24,40 +25,31 @@ QuicStreamIdManager::QuicStreamIdManager(
DelegateInterface* delegate,
bool unidirectional,
Perspective perspective,
- QuicTransportVersion transport_version,
+ ParsedQuicVersion version,
QuicStreamCount max_allowed_outgoing_streams,
QuicStreamCount max_allowed_incoming_streams)
: delegate_(delegate),
unidirectional_(unidirectional),
perspective_(perspective),
- transport_version_(transport_version),
+ version_(version),
outgoing_max_streams_(max_allowed_outgoing_streams),
next_outgoing_stream_id_(GetFirstOutgoingStreamId()),
outgoing_stream_count_(0),
incoming_actual_max_streams_(max_allowed_incoming_streams),
- // Advertised max starts at actual because it's communicated in the
- // handshake.
incoming_advertised_max_streams_(max_allowed_incoming_streams),
incoming_initial_max_open_streams_(max_allowed_incoming_streams),
incoming_stream_count_(0),
largest_peer_created_stream_id_(
- QuicUtils::GetInvalidStreamId(transport_version)),
- max_streams_window_(0) {
- CalculateIncomingMaxStreamsWindow();
-}
+ QuicUtils::GetInvalidStreamId(version.transport_version)) {}
QuicStreamIdManager::~QuicStreamIdManager() {}
-// The peer sends a streams blocked frame when it can not open any more
-// streams because it has runs into the limit.
bool QuicStreamIdManager::OnStreamsBlockedFrame(
const QuicStreamsBlockedFrame& frame,
std::string* error_details) {
- // Ensure that the frame has the correct directionality.
DCHECK_EQ(frame.unidirectional, unidirectional_);
if (frame.stream_count > incoming_advertised_max_streams_) {
// Peer thinks it can send more streams that we've told it.
- // This is a protocol error.
*error_details = quiche::QuicheStrCat(
"StreamsBlockedFrame's stream count ", frame.stream_count,
" exceeds incoming max stream ", incoming_advertised_max_streams_);
@@ -65,8 +57,7 @@ bool QuicStreamIdManager::OnStreamsBlockedFrame(
}
if (frame.stream_count < incoming_actual_max_streams_) {
// Peer thinks it's blocked on a stream count that is less than our current
- // max. Inform the peer of the correct stream count. Sending a MAX_STREAMS
- // frame in this case is not controlled by the window.
+ // max. Inform the peer of the correct stream count.
SendMaxStreamsFrame();
}
return true;
@@ -90,8 +81,9 @@ bool QuicStreamIdManager::MaybeAllowNewOutgoingStreams(
void QuicStreamIdManager::SetMaxOpenIncomingStreams(
QuicStreamCount max_open_streams) {
QUIC_BUG_IF(incoming_stream_count_ > 0)
- << "non-zero stream count when setting max incoming stream.";
- QUIC_LOG_IF(WARNING, incoming_initial_max_open_streams_ != max_open_streams)
+ << "non-zero incoming stream count " << incoming_stream_count_
+ << " when setting max incoming stream to " << max_open_streams;
+ QUIC_DLOG_IF(WARNING, incoming_initial_max_open_streams_ != max_open_streams)
<< quiche::QuicheStrCat(
unidirectional_ ? "unidirectional " : "bidirectional: ",
"incoming stream limit changed from ",
@@ -99,12 +91,12 @@ void QuicStreamIdManager::SetMaxOpenIncomingStreams(
incoming_actual_max_streams_ = max_open_streams;
incoming_advertised_max_streams_ = max_open_streams;
incoming_initial_max_open_streams_ = max_open_streams;
- CalculateIncomingMaxStreamsWindow();
}
void QuicStreamIdManager::MaybeSendMaxStreamsFrame() {
if ((incoming_advertised_max_streams_ - incoming_stream_count_) >
- max_streams_window_) {
+ (incoming_initial_max_open_streams_ /
+ GetQuicFlag(FLAGS_quic_max_streams_window_divisor))) {
// window too large, no advertisement
return;
}
@@ -118,39 +110,36 @@ void QuicStreamIdManager::SendMaxStreamsFrame() {
void QuicStreamIdManager::OnStreamClosed(QuicStreamId stream_id) {
DCHECK_NE(QuicUtils::IsBidirectionalStreamId(stream_id), unidirectional_);
- if (!IsIncomingStream(stream_id)) {
+ if (QuicUtils::IsOutgoingStreamId(version_, stream_id, perspective_)) {
// Nothing to do for outgoing streams.
return;
}
// If the stream is inbound, we can increase the actual stream limit and maybe
- // advertise the new limit to the peer. Have to check to make sure that we do
- // not exceed the maximum.
+ // advertise the new limit to the peer.
if (incoming_actual_max_streams_ == QuicUtils::GetMaxStreamCount()) {
// Reached the maximum stream id value that the implementation
// supports. Nothing can be done here.
return;
}
- // One stream closed ... another can be opened.
+ // One stream closed, and another one can be opened.
incoming_actual_max_streams_++;
MaybeSendMaxStreamsFrame();
}
QuicStreamId QuicStreamIdManager::GetNextOutgoingStreamId() {
- // Applications should always consult CanOpenNextOutgoingStream() first.
- // If they ask for stream ids that violate the limit, it's an implementation
- // bug.
QUIC_BUG_IF(outgoing_stream_count_ >= outgoing_max_streams_)
<< "Attempt to allocate a new outgoing stream that would exceed the "
"limit ("
<< outgoing_max_streams_ << ")";
QuicStreamId id = next_outgoing_stream_id_;
- next_outgoing_stream_id_ += QuicUtils::StreamIdDelta(transport_version_);
+ next_outgoing_stream_id_ +=
+ QuicUtils::StreamIdDelta(version_.transport_version);
outgoing_stream_count_++;
return id;
}
bool QuicStreamIdManager::CanOpenNextOutgoingStream() const {
- DCHECK(VersionHasIetfQuicFrames(transport_version_));
+ DCHECK(VersionHasIetfQuicFrames(version_.transport_version));
return outgoing_stream_count_ < outgoing_max_streams_;
}
@@ -159,23 +148,25 @@ bool QuicStreamIdManager::MaybeIncreaseLargestPeerStreamId(
std::string* error_details) {
// |stream_id| must be an incoming stream of the right directionality.
DCHECK_NE(QuicUtils::IsBidirectionalStreamId(stream_id), unidirectional_);
- DCHECK_NE(QuicUtils::IsServerInitiatedStreamId(transport_version_, stream_id),
- perspective() == Perspective::IS_SERVER);
+ DCHECK_NE(QuicUtils::IsServerInitiatedStreamId(version_.transport_version,
+ stream_id),
+ perspective_ == Perspective::IS_SERVER);
if (available_streams_.erase(stream_id) == 1) {
// stream_id is available.
return true;
}
if (largest_peer_created_stream_id_ !=
- QuicUtils::GetInvalidStreamId(transport_version_)) {
+ QuicUtils::GetInvalidStreamId(version_.transport_version)) {
DCHECK_GT(stream_id, largest_peer_created_stream_id_);
}
// Calculate increment of incoming_stream_count_ by creating stream_id.
- const QuicStreamCount delta = QuicUtils::StreamIdDelta(transport_version_);
+ const QuicStreamCount delta =
+ QuicUtils::StreamIdDelta(version_.transport_version);
const QuicStreamId least_new_stream_id =
largest_peer_created_stream_id_ ==
- QuicUtils::GetInvalidStreamId(transport_version_)
+ QuicUtils::GetInvalidStreamId(version_.transport_version)
? GetFirstIncomingStreamId()
: largest_peer_created_stream_id_ + delta;
const QuicStreamCount stream_count_increment =
@@ -203,59 +194,36 @@ bool QuicStreamIdManager::MaybeIncreaseLargestPeerStreamId(
bool QuicStreamIdManager::IsAvailableStream(QuicStreamId id) const {
DCHECK_NE(QuicUtils::IsBidirectionalStreamId(id), unidirectional_);
- if (!IsIncomingStream(id)) {
+ if (QuicUtils::IsOutgoingStreamId(version_, id, perspective_)) {
// Stream IDs under next_ougoing_stream_id_ are either open or previously
// open but now closed.
return id >= next_outgoing_stream_id_;
}
// For peer created streams, we also need to consider available streams.
return largest_peer_created_stream_id_ ==
- QuicUtils::GetInvalidStreamId(transport_version_) ||
+ QuicUtils::GetInvalidStreamId(version_.transport_version) ||
id > largest_peer_created_stream_id_ ||
QuicContainsKey(available_streams_, id);
}
-bool QuicStreamIdManager::IsIncomingStream(QuicStreamId id) const {
- DCHECK_NE(QuicUtils::IsBidirectionalStreamId(id), unidirectional_);
- // The 0x1 bit in the stream id indicates whether the stream id is
- // server- or client- initiated. Next_OUTGOING_stream_id_ has that bit
- // set based on whether this node is a server or client. Thus, if the stream
- // id in question has the 0x1 bit set opposite of next_OUTGOING_stream_id_,
- // then that stream id is incoming -- it is for streams initiated by the peer.
- return (id & 0x1) != (next_outgoing_stream_id_ & 0x1);
-}
-
QuicStreamId QuicStreamIdManager::GetFirstOutgoingStreamId() const {
return (unidirectional_) ? QuicUtils::GetFirstUnidirectionalStreamId(
- transport_version_, perspective())
+ version_.transport_version, perspective_)
: QuicUtils::GetFirstBidirectionalStreamId(
- transport_version_, perspective());
+ version_.transport_version, perspective_);
}
QuicStreamId QuicStreamIdManager::GetFirstIncomingStreamId() const {
return (unidirectional_) ? QuicUtils::GetFirstUnidirectionalStreamId(
- transport_version_, peer_perspective())
+ version_.transport_version,
+ QuicUtils::InvertPerspective(perspective_))
: QuicUtils::GetFirstBidirectionalStreamId(
- transport_version_, peer_perspective());
-}
-
-Perspective QuicStreamIdManager::perspective() const {
- return perspective_;
+ version_.transport_version,
+ QuicUtils::InvertPerspective(perspective_));
}
-Perspective QuicStreamIdManager::peer_perspective() const {
- return QuicUtils::InvertPerspective(perspective());
-}
-
-QuicStreamCount QuicStreamIdManager::available_incoming_streams() {
+QuicStreamCount QuicStreamIdManager::available_incoming_streams() const {
return incoming_advertised_max_streams_ - incoming_stream_count_;
}
-void QuicStreamIdManager::CalculateIncomingMaxStreamsWindow() {
- max_streams_window_ = incoming_actual_max_streams_ / kMaxStreamsWindowDivisor;
- if (max_streams_window_ == 0) {
- max_streams_window_ = 1;
- }
-}
-
} // namespace quic
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 fa4b1a06b47..9e6ef20112a 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
@@ -17,16 +17,7 @@ class QuicSessionPeer;
class QuicStreamIdManagerPeer;
} // namespace test
-// Amount to increment a stream ID value to get the next stream ID in
-// the stream ID space.
-const QuicStreamId kV99StreamIdIncrement = 4;
-
-// This constant controls the size of the window when deciding whether
-// to generate a MAX_STREAMS frame or not. See the discussion of the
-// window, below, for more details.
-const int kMaxStreamsWindowDivisor = 2;
-
-// This class manages the stream ids for Version 99/IETF QUIC.
+// This class manages the stream ids for IETF QUIC.
class QUIC_EXPORT_PRIVATE QuicStreamIdManager {
public:
class QUIC_EXPORT_PRIVATE DelegateInterface {
@@ -41,7 +32,7 @@ class QUIC_EXPORT_PRIVATE QuicStreamIdManager {
QuicStreamIdManager(DelegateInterface* delegate,
bool unidirectional,
Perspective perspective,
- QuicTransportVersion transport_version,
+ ParsedQuicVersion version,
QuicStreamCount max_allowed_outgoing_streams,
QuicStreamCount max_allowed_incoming_streams);
@@ -52,7 +43,7 @@ class QUIC_EXPORT_PRIVATE QuicStreamIdManager {
std::string DebugString() const {
return quiche::QuicheStrCat(
" { unidirectional_: ", unidirectional_,
- ", perspective: ", perspective(),
+ ", perspective: ", perspective_,
", outgoing_max_streams_: ", outgoing_max_streams_,
", next_outgoing_stream_id_: ", next_outgoing_stream_id_,
", outgoing_stream_count_: ", outgoing_stream_count_,
@@ -62,7 +53,7 @@ class QUIC_EXPORT_PRIVATE QuicStreamIdManager {
", incoming_stream_count_: ", incoming_stream_count_,
", available_streams_.size(): ", available_streams_.size(),
", largest_peer_created_stream_id_: ", largest_peer_created_stream_id_,
- ", max_streams_window_: ", max_streams_window_, " }");
+ " }");
}
// Processes the STREAMS_BLOCKED frame. If error is encountered, populates
@@ -70,7 +61,7 @@ class QUIC_EXPORT_PRIVATE QuicStreamIdManager {
bool OnStreamsBlockedFrame(const QuicStreamsBlockedFrame& frame,
std::string* error_details);
- // Indicates whether the next outgoing stream ID can be allocated or not.
+ // Returns whether the next outgoing stream ID can be allocated or not.
bool CanOpenNextOutgoingStream() const;
// Generate and send a MAX_STREAMS frame.
@@ -83,8 +74,7 @@ class QUIC_EXPORT_PRIVATE QuicStreamIdManager {
void OnStreamClosed(QuicStreamId stream_id);
// Returns the next outgoing stream id. Applications must call
- // CanOpenNextOutgoingStream() first. A QUIC_BUG is logged if this method
- // allocates a stream ID past the peer specified limit.
+ // CanOpenNextOutgoingStream() first.
QuicStreamId GetNextOutgoingStreamId();
void SetMaxOpenIncomingStreams(QuicStreamCount max_open_streams);
@@ -95,42 +85,28 @@ class QUIC_EXPORT_PRIVATE QuicStreamIdManager {
bool MaybeAllowNewOutgoingStreams(QuicStreamCount max_open_streams);
// Checks if the incoming stream ID exceeds the MAX_STREAMS limit. If the
- // limit is exceeded, populates |error_detials| and returns false. Uses the
- // actual maximium, not the most recently advertised value, in order to
- // enforce the Google-QUIC number of open streams behavior.
- // This method should be called exactly once for each incoming stream
- // creation.
+ // limit is exceeded, populates |error_detials| and returns false.
bool MaybeIncreaseLargestPeerStreamId(const QuicStreamId stream_id,
std::string* error_details);
// Returns true if |id| is still available.
bool IsAvailableStream(QuicStreamId id) const;
- // Return true if given stream is peer initiated.
- bool IsIncomingStream(QuicStreamId id) const;
-
QuicStreamCount incoming_initial_max_open_streams() const {
return incoming_initial_max_open_streams_;
}
- QuicStreamCount max_streams_window() const { return max_streams_window_; }
-
QuicStreamId next_outgoing_stream_id() const {
return next_outgoing_stream_id_;
}
// Number of streams that the peer believes that it can still create.
- QuicStreamCount available_incoming_streams();
+ QuicStreamCount available_incoming_streams() const;
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.
- // The advertised incoming amount should never be more than the actual
- // incoming one.
QuicStreamCount outgoing_max_streams() const { return outgoing_max_streams_; }
QuicStreamCount incoming_actual_max_streams() const {
return incoming_actual_max_streams_;
@@ -138,13 +114,9 @@ class QUIC_EXPORT_PRIVATE QuicStreamIdManager {
QuicStreamCount incoming_advertised_max_streams() const {
return incoming_advertised_max_streams_;
}
- // Number of streams that have been opened (including those that have been
- // opened and then closed. Must never exceed outgoing_max_streams
- QuicStreamCount outgoing_stream_count() { return outgoing_stream_count_; }
-
- // Perspective (CLIENT/SERVER) of this node and the peer, respectively.
- Perspective perspective() const;
- Perspective peer_perspective() const;
+ QuicStreamCount outgoing_stream_count() const {
+ return outgoing_stream_count_;
+ }
private:
friend class test::QuicSessionPeer;
@@ -160,10 +132,7 @@ class QUIC_EXPORT_PRIVATE QuicStreamIdManager {
QuicStreamId GetFirstOutgoingStreamId() const;
QuicStreamId GetFirstIncomingStreamId() const;
- void CalculateIncomingMaxStreamsWindow();
-
// Back reference to the session containing this Stream ID Manager.
- // needed to access various session methods, such as perspective()
DelegateInterface* delegate_;
// Whether this stream id manager is for unidrectional (true) or bidirectional
@@ -173,14 +142,12 @@ class QUIC_EXPORT_PRIVATE QuicStreamIdManager {
// Is this manager a client or a server.
const Perspective perspective_;
- // Transport version used for this manager.
- const QuicTransportVersion transport_version_;
+ // QUIC version used for this manager.
+ const ParsedQuicVersion version_;
- // This is the number of streams that this node can initiate.
- // This limit is:
- // - Initiated to a value specified in the constructor
- // - May be updated when the config is received.
- // - Is updated whenever a MAX STREAMS frame is received.
+ // The number of streams that this node can initiate.
+ // This limit is first set when config is negotiated, but may be updated upon
+ // receiving MAX_STREAMS frame.
QuicStreamCount outgoing_max_streams_;
// The ID to use for the next outgoing stream.
@@ -193,31 +160,25 @@ class QUIC_EXPORT_PRIVATE QuicStreamIdManager {
// FOR INCOMING STREAMS
- // The maximum number of streams that can be opened by the peer.
+ // The actual maximum number of streams that can be opened by the peer.
QuicStreamCount incoming_actual_max_streams_;
+ // Max incoming stream number that has been advertised to the peer and is <=
+ // incoming_actual_max_streams_. It is set to incoming_actual_max_streams_
+ // when a MAX_STREAMS is sent.
QuicStreamCount incoming_advertised_max_streams_;
// Initial maximum on the number of open streams allowed.
QuicStreamCount incoming_initial_max_open_streams_;
- // This is the number of streams that have been created -- some are still
- // open, the others have been closed. It is the number that is compared
- // against MAX_STREAMS when deciding whether to accept a new stream or not.
+ // The number of streams that have been created, including open ones and
+ // closed ones.
QuicStreamCount incoming_stream_count_;
// Set of stream ids that are less than the largest stream id that has been
// received, but are nonetheless available to be created.
- QuicUnorderedSet<QuicStreamId> available_streams_;
+ QuicHashSet<QuicStreamId> available_streams_;
QuicStreamId largest_peer_created_stream_id_;
-
- // When incoming streams close the local node sends MAX_STREAMS frames. It
- // does so only when the peer can open fewer than |max_stream_id_window_|
- // streams. That is, when |incoming_actual_max_streams_| -
- // |incoming_advertised_max_streams_| is less than the window.
- // max_streams_window_ is set to 1/2 of the initial number of incoming streams
- // that are allowed (as set in the constructor).
- QuicStreamId max_streams_window_;
};
} // namespace quic
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 3207e59558b..2179ba2c860 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
@@ -24,8 +24,10 @@ namespace {
class MockDelegate : public QuicStreamIdManager::DelegateInterface {
public:
- MOCK_METHOD2(SendMaxStreams,
- void(QuicStreamCount stream_count, bool unidirectional));
+ MOCK_METHOD(void,
+ SendMaxStreams,
+ (QuicStreamCount stream_count, bool unidirectional),
+ (override));
};
struct TestParams {
@@ -71,7 +73,7 @@ class QuicStreamIdManagerTest : public QuicTestWithParam<TestParams> {
: stream_id_manager_(&delegate_,
IsUnidirectional(),
perspective(),
- transport_version(),
+ GetParam().version,
0,
kDefaultMaxStreamsPerConnection) {
DCHECK(VersionHasIetfQuicFrames(transport_version()));
@@ -84,7 +86,7 @@ class QuicStreamIdManagerTest : public QuicTestWithParam<TestParams> {
// Returns the stream ID for the Nth incoming stream (created by the peer)
// of the corresponding directionality of this manager.
QuicStreamId GetNthIncomingStreamId(int n) {
- return kV99StreamIdIncrement * n +
+ return QuicUtils::StreamIdDelta(transport_version()) * n +
(IsUnidirectional()
? QuicUtils::GetFirstUnidirectionalStreamId(
transport_version(),
@@ -115,11 +117,6 @@ TEST_P(QuicStreamIdManagerTest, Initialization) {
stream_id_manager_.incoming_advertised_max_streams());
EXPECT_EQ(kDefaultMaxStreamsPerConnection,
stream_id_manager_.incoming_initial_max_open_streams());
-
- // The window for advertising updates to the MAX STREAM ID is half the number
- // of streams allowed.
- EXPECT_EQ(kDefaultMaxStreamsPerConnection / 2,
- stream_id_manager_.max_streams_window());
}
// This test checks that the stream advertisement window is set to 1
@@ -128,7 +125,6 @@ TEST_P(QuicStreamIdManagerTest, CheckMaxStreamsWindowForSingleStream) {
stream_id_manager_.SetMaxOpenIncomingStreams(1);
EXPECT_EQ(1u, stream_id_manager_.incoming_initial_max_open_streams());
EXPECT_EQ(1u, stream_id_manager_.incoming_actual_max_streams());
- EXPECT_EQ(1u, stream_id_manager_.max_streams_window());
}
TEST_P(QuicStreamIdManagerTest, CheckMaxStreamsBadValuesOverMaxFailsOutgoing) {
@@ -279,18 +275,17 @@ TEST_P(QuicStreamIdManagerTest, GetNextOutgoingStream) {
EXPECT_TRUE(
stream_id_manager_.MaybeAllowNewOutgoingStreams(number_of_streams));
- QuicStreamId stream_id =
- IsUnidirectional()
- ? QuicUtils::GetFirstUnidirectionalStreamId(
- transport_version(), stream_id_manager_.perspective())
- : QuicUtils::GetFirstBidirectionalStreamId(
- transport_version(), stream_id_manager_.perspective());
+ QuicStreamId stream_id = IsUnidirectional()
+ ? QuicUtils::GetFirstUnidirectionalStreamId(
+ transport_version(), perspective())
+ : QuicUtils::GetFirstBidirectionalStreamId(
+ transport_version(), perspective());
EXPECT_EQ(number_of_streams, stream_id_manager_.outgoing_max_streams());
while (number_of_streams) {
EXPECT_TRUE(stream_id_manager_.CanOpenNextOutgoingStream());
EXPECT_EQ(stream_id, stream_id_manager_.GetNextOutgoingStreamId());
- stream_id += kV99StreamIdIncrement;
+ stream_id += QuicUtils::StreamIdDelta(transport_version());
number_of_streams--;
}
@@ -316,23 +311,21 @@ TEST_P(QuicStreamIdManagerTest, MaybeIncreaseLargestPeerStreamId) {
// A bad stream ID results in a closed connection.
std::string error_details;
EXPECT_FALSE(stream_id_manager_.MaybeIncreaseLargestPeerStreamId(
- max_stream_id + kV99StreamIdIncrement, &error_details));
- EXPECT_EQ(
- error_details,
- quiche::QuicheStrCat("Stream id ", max_stream_id + kV99StreamIdIncrement,
- " would exceed stream count limit 100"));
+ max_stream_id + QuicUtils::StreamIdDelta(transport_version()),
+ &error_details));
+ EXPECT_EQ(error_details,
+ quiche::QuicheStrCat(
+ "Stream id ",
+ max_stream_id + QuicUtils::StreamIdDelta(transport_version()),
+ " would exceed stream count limit 100"));
}
TEST_P(QuicStreamIdManagerTest, MaxStreamsWindow) {
- // Test that a MAX_STREAMS frame is generated when the peer has less than
- // |max_streams_window_| streams left that it can initiate.
-
- // First, open, and then close, max_streams_window_ streams. This will
- // max_streams_window_ streams available for the peer -- no MAX_STREAMS
- // should be sent. The -1 is because the check in
- // QuicStreamIdManager::MaybeSendMaxStreamsFrame sends a MAX_STREAMS if the
- // number of available streams at the peer is <= |max_streams_window_|
- int stream_count = stream_id_manager_.max_streams_window() - 1;
+ // Open and then close a number of streams to get close to the threshold of
+ // sending a MAX_STREAM_FRAME.
+ int stream_count = stream_id_manager_.incoming_initial_max_open_streams() /
+ GetQuicFlag(FLAGS_quic_max_streams_window_divisor) -
+ 1;
// Should not get a control-frame transmission since the peer should have
// "plenty" of stream IDs to use.
@@ -342,7 +335,8 @@ TEST_P(QuicStreamIdManagerTest, MaxStreamsWindow) {
QuicStreamId stream_id = GetNthIncomingStreamId(0);
size_t old_available_incoming_streams =
stream_id_manager_.available_incoming_streams();
- while (stream_count) {
+ auto i = stream_count;
+ while (i) {
EXPECT_TRUE(stream_id_manager_.MaybeIncreaseLargestPeerStreamId(stream_id,
nullptr));
@@ -352,12 +346,11 @@ TEST_P(QuicStreamIdManagerTest, MaxStreamsWindow) {
EXPECT_EQ(old_available_incoming_streams,
stream_id_manager_.available_incoming_streams());
- stream_count--;
- stream_id += kV99StreamIdIncrement;
+ i--;
+ stream_id += QuicUtils::StreamIdDelta(transport_version());
}
// Now close them, still should get no MAX_STREAMS
- stream_count = stream_id_manager_.max_streams_window();
stream_id = GetNthIncomingStreamId(0);
QuicStreamCount expected_actual_max =
stream_id_manager_.incoming_actual_max_streams();
@@ -366,7 +359,7 @@ TEST_P(QuicStreamIdManagerTest, MaxStreamsWindow) {
while (stream_count) {
stream_id_manager_.OnStreamClosed(stream_id);
stream_count--;
- stream_id += kV99StreamIdIncrement;
+ stream_id += QuicUtils::StreamIdDelta(transport_version());
expected_actual_max++;
EXPECT_EQ(expected_actual_max,
stream_id_manager_.incoming_actual_max_streams());
@@ -418,24 +411,21 @@ TEST_P(QuicStreamIdManagerTest, MaxStreamsSlidingWindow) {
stream_id_manager_.incoming_advertised_max_streams();
// Open/close enough streams to shrink the window without causing a MAX
- // STREAMS to be generated. The window will open (and a MAX STREAMS generated)
- // when max_streams_window() stream IDs have been made available. The loop
+ // STREAMS to be generated. The loop
// will make that many stream IDs available, so the last CloseStream should
-
// cause a MAX STREAMS frame to be generated.
- int i = static_cast<int>(stream_id_manager_.max_streams_window());
+ int i =
+ static_cast<int>(stream_id_manager_.incoming_initial_max_open_streams() /
+ GetQuicFlag(FLAGS_quic_max_streams_window_divisor));
QuicStreamId id =
QuicStreamIdManagerPeer::GetFirstIncomingStreamId(&stream_id_manager_);
- EXPECT_CALL(
- delegate_,
- SendMaxStreams(first_advert + stream_id_manager_.max_streams_window(),
- IsUnidirectional()));
+ EXPECT_CALL(delegate_, SendMaxStreams(first_advert + i, IsUnidirectional()));
while (i) {
EXPECT_TRUE(
stream_id_manager_.MaybeIncreaseLargestPeerStreamId(id, nullptr));
stream_id_manager_.OnStreamClosed(id);
i--;
- id += kV99StreamIdIncrement;
+ id += QuicUtils::StreamIdDelta(transport_version());
}
}
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 50b5b68eaed..a74526b949e 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
@@ -50,6 +50,7 @@ class QUIC_EXPORT_PRIVATE QuicStreamSequencer {
QuicStreamSequencer(const QuicStreamSequencer&) = delete;
QuicStreamSequencer(QuicStreamSequencer&&) = default;
QuicStreamSequencer& operator=(const QuicStreamSequencer&) = delete;
+ QuicStreamSequencer& operator=(QuicStreamSequencer&&) = default;
virtual ~QuicStreamSequencer();
// If the frame is the next one we need in order to process in-order data,
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 356b62fccc9..0ad984117de 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
@@ -94,6 +94,7 @@ class QUIC_EXPORT_PRIVATE QuicStreamSequencerBuffer {
QuicStreamSequencerBuffer(QuicStreamSequencerBuffer&&) = default;
QuicStreamSequencerBuffer& operator=(const QuicStreamSequencerBuffer&) =
delete;
+ QuicStreamSequencerBuffer& operator=(QuicStreamSequencerBuffer&&) = default;
~QuicStreamSequencerBuffer();
// Free the space used to buffer data.
@@ -212,10 +213,10 @@ class QUIC_EXPORT_PRIVATE QuicStreamSequencerBuffer {
std::string ReceivedFramesDebugString() const;
// The maximum total capacity of this buffer in byte, as constructed.
- const size_t max_buffer_capacity_bytes_;
+ size_t max_buffer_capacity_bytes_;
// How many blocks this buffer would need when it reaches full capacity.
- const size_t blocks_count_;
+ size_t blocks_count_;
// Number of bytes read out of buffer.
QuicStreamOffset total_bytes_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 188eb86f6fe..bdf141267a7 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
@@ -31,13 +31,14 @@ namespace test {
class MockStream : public QuicStreamSequencer::StreamInterface {
public:
- MOCK_METHOD0(OnFinRead, void());
- MOCK_METHOD0(OnDataAvailable, void());
- MOCK_METHOD2(OnUnrecoverableError,
- void(QuicErrorCode error, const std::string& details));
- MOCK_METHOD1(Reset, void(QuicRstStreamErrorCode error));
- MOCK_METHOD0(OnCanWrite, void());
- MOCK_METHOD1(AddBytesConsumed, void(QuicByteCount bytes));
+ MOCK_METHOD(void, OnFinRead, (), (override));
+ MOCK_METHOD(void, OnDataAvailable, (), (override));
+ MOCK_METHOD(void,
+ OnUnrecoverableError,
+ (QuicErrorCode error, const std::string& details),
+ (override));
+ MOCK_METHOD(void, Reset, (QuicRstStreamErrorCode error), (override));
+ MOCK_METHOD(void, AddBytesConsumed, (QuicByteCount bytes), (override));
QuicStreamId id() const override { return 1; }
};
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 eea7b15113e..f30a3be7216 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
@@ -49,7 +49,7 @@ namespace {
const char kData1[] = "FooAndBar";
const char kData2[] = "EepAndBaz";
-const size_t kDataLen = 9;
+const QuicByteCount kDataLen = 9;
class TestStream : public QuicStream {
public:
@@ -61,9 +61,9 @@ class TestStream : public QuicStream {
TestStream(PendingStream* pending, StreamType type, bool is_static)
: QuicStream(pending, type, is_static) {}
- MOCK_METHOD0(OnDataAvailable, void());
+ MOCK_METHOD(void, OnDataAvailable, (), (override));
- MOCK_METHOD0(OnCanWriteNewData, void());
+ MOCK_METHOD(void, OnCanWriteNewData, (), (override));
using QuicStream::CanWriteNewData;
using QuicStream::CanWriteNewDataAfterData;
@@ -125,7 +125,7 @@ class QuicStreamTest : public QuicTestWithParam<ParsedQuicVersion> {
QuicConsumedData CloseStreamOnWriteError(
QuicStreamId id,
- size_t /*write_length*/,
+ QuicByteCount /*write_length*/,
QuicStreamOffset /*offset*/,
StreamSendingState /*state*/,
TransmissionType /*type*/,
@@ -271,7 +271,7 @@ TEST_P(QuicStreamTest, FromPendingStreamThenData) {
TEST_P(QuicStreamTest, WriteAllData) {
Initialize();
- size_t length =
+ QuicByteCount length =
1 + QuicPacketCreator::StreamFramePacketOverhead(
connection_->transport_version(), PACKET_8BYTE_CONNECTION_ID,
PACKET_0BYTE_CONNECTION_ID, !kIncludeVersion,
@@ -360,7 +360,7 @@ TEST_P(QuicStreamTest, WriteOrBufferData) {
Initialize();
EXPECT_FALSE(HasWriteBlockedStreams());
- size_t length =
+ QuicByteCount length =
1 + QuicPacketCreator::StreamFramePacketOverhead(
connection_->transport_version(), PACKET_8BYTE_CONNECTION_ID,
PACKET_0BYTE_CONNECTION_ID, !kIncludeVersion,
@@ -455,7 +455,12 @@ TEST_P(QuicStreamTest, RstAlwaysSentIfNoFinSent) {
// Now close the stream, and expect that we send a RST.
EXPECT_CALL(*session_, SendRstStream(_, _, _));
- stream_->OnClose();
+ if (session_->break_close_loop()) {
+ stream_->CloseReadSide();
+ stream_->CloseWriteSide();
+ } else {
+ stream_->OnClose();
+ }
EXPECT_FALSE(session_->HasUnackedStreamData());
EXPECT_FALSE(fin_sent());
EXPECT_TRUE(rst_sent());
@@ -482,7 +487,12 @@ TEST_P(QuicStreamTest, RstNotSentIfFinSent) {
EXPECT_FALSE(rst_sent());
// Now close the stream, and expect that we do not send a RST.
- stream_->OnClose();
+ if (session_->break_close_loop()) {
+ stream_->CloseReadSide();
+ stream_->CloseWriteSide();
+ } else {
+ stream_->OnClose();
+ }
EXPECT_TRUE(fin_sent());
EXPECT_FALSE(rst_sent());
}
@@ -506,7 +516,12 @@ TEST_P(QuicStreamTest, OnlySendOneRst) {
// Now close the stream (any further resets being sent would break the
// expectation above).
- stream_->OnClose();
+ if (session_->break_close_loop()) {
+ stream_->CloseReadSide();
+ stream_->CloseWriteSide();
+ } else {
+ stream_->OnClose();
+ }
EXPECT_FALSE(fin_sent());
EXPECT_TRUE(rst_sent());
}
@@ -642,7 +657,12 @@ TEST_P(QuicStreamTest, InvalidFinalByteOffsetFromRst) {
CloseConnection(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA, _, _));
stream_->OnStreamReset(rst_frame);
EXPECT_TRUE(stream_->HasReceivedFinalOffset());
- stream_->OnClose();
+ if (session_->break_close_loop()) {
+ stream_->CloseReadSide();
+ stream_->CloseWriteSide();
+ } else {
+ stream_->OnClose();
+ }
}
TEST_P(QuicStreamTest, FinalByteOffsetFromZeroLengthStreamFrame) {
@@ -734,7 +754,7 @@ TEST_P(QuicStreamTest, SetDrainingIncomingOutgoing) {
EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_));
EXPECT_FALSE(stream_->reading_stopped());
- EXPECT_EQ(1u, session_->GetNumOpenIncomingStreams());
+ EXPECT_EQ(1u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get()));
// Outgoing data with FIN.
EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _))
@@ -746,9 +766,8 @@ TEST_P(QuicStreamTest, SetDrainingIncomingOutgoing) {
nullptr);
EXPECT_TRUE(stream_->write_side_closed());
- EXPECT_EQ(1u, QuicSessionPeer::GetDrainingStreams(session_.get())
- ->count(kTestStreamId));
- EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams());
+ EXPECT_EQ(1u, session_->GetNumDrainingStreams());
+ EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get()));
}
TEST_P(QuicStreamTest, SetDrainingOutgoingIncoming) {
@@ -765,7 +784,7 @@ TEST_P(QuicStreamTest, SetDrainingOutgoingIncoming) {
nullptr);
EXPECT_TRUE(stream_->write_side_closed());
- EXPECT_EQ(1u, session_->GetNumOpenIncomingStreams());
+ EXPECT_EQ(1u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get()));
// Incoming data with FIN.
QuicStreamFrame stream_frame_with_fin(stream_->id(), true, 1234, ".");
@@ -775,9 +794,8 @@ TEST_P(QuicStreamTest, SetDrainingOutgoingIncoming) {
EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_));
EXPECT_FALSE(stream_->reading_stopped());
- EXPECT_EQ(1u, QuicSessionPeer::GetDrainingStreams(session_.get())
- ->count(kTestStreamId));
- EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams());
+ EXPECT_EQ(1u, session_->GetNumDrainingStreams());
+ EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get()));
}
TEST_P(QuicStreamTest, EarlyResponseFinHandling) {
@@ -1058,8 +1076,9 @@ TEST_P(QuicStreamTest, WriteBufferedData) {
EXPECT_FALSE(stream_->CanWriteNewData());
// Send buffered data to make buffered data size < threshold.
- size_t data_to_write = 3 * data.length() - 200 -
- GetQuicFlag(FLAGS_quic_buffered_data_threshold) + 1;
+ QuicByteCount data_to_write =
+ 3 * data.length() - 200 -
+ GetQuicFlag(FLAGS_quic_buffered_data_threshold) + 1;
EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
.WillOnce(InvokeWithoutArgs([this, data_to_write]() {
return session_->ConsumeData(stream_->id(), data_to_write, 200u, NO_FIN,
@@ -1192,8 +1211,9 @@ TEST_P(QuicStreamTest, WriteMemSlices) {
EXPECT_EQ(2 * QUICHE_ARRAYSIZE(data) - 100, stream_->BufferedDataBytes());
EXPECT_FALSE(stream_->fin_buffered());
- size_t data_to_write = 2 * QUICHE_ARRAYSIZE(data) - 100 -
- GetQuicFlag(FLAGS_quic_buffered_data_threshold) + 1;
+ QuicByteCount data_to_write =
+ 2 * QUICHE_ARRAYSIZE(data) - 100 -
+ GetQuicFlag(FLAGS_quic_buffered_data_threshold) + 1;
EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
.WillOnce(InvokeWithoutArgs([this, data_to_write]() {
return session_->ConsumeData(stream_->id(), data_to_write, 100u, NO_FIN,
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 d4429e34ceb..adecbcd1514 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
@@ -254,8 +254,8 @@ inline QuicTime::Delta operator*(QuicTime::Delta lhs, int rhs) {
return QuicTime::Delta(lhs.time_offset_ * rhs);
}
inline QuicTime::Delta operator*(QuicTime::Delta lhs, double rhs) {
- return QuicTime::Delta(
- static_cast<int64_t>(std::llround(lhs.time_offset_ * rhs)));
+ return QuicTime::Delta(static_cast<int64_t>(
+ std::llround(static_cast<double>(lhs.time_offset_) * rhs)));
}
inline QuicTime::Delta operator*(int lhs, QuicTime::Delta rhs) {
return rhs * lhs;
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.cc b/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.cc
index 2b0c267f626..433a3ab3285 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.cc
@@ -162,12 +162,13 @@ void QuicTimeWaitListManager::ProcessPacket(
if (!connection_data->ietf_quic) {
QUIC_CODE_COUNT(quic_received_short_header_packet_for_gquic);
}
- if (connection_data->encryption_level == ENCRYPTION_INITIAL) {
+ if (GetQuicRestartFlag(
+ quic_replace_time_wait_list_encryption_level) ||
+ connection_data->encryption_level == ENCRYPTION_INITIAL) {
+ // TODO(b/153096082) Rename this code count.
QUIC_CODE_COUNT(
quic_encryption_none_termination_packets_for_short_header);
- // Send stateless reset in response to short header packets,
- // because ENCRYPTION_INITIAL termination packets will not be
- // processed by clients.
+ // Send stateless reset in response to short header packets.
SendPublicReset(self_address, peer_address, connection_id,
connection_data->ietf_quic,
std::move(packet_context));
@@ -190,6 +191,19 @@ void QuicTimeWaitListManager::ProcessPacket(
packet_context.get());
}
return;
+
+ case SEND_CONNECTION_CLOSE_PACKETS:
+ if (connection_data->termination_packets.empty()) {
+ QUIC_BUG << "There are no termination packets.";
+ return;
+ }
+ for (const auto& packet : connection_data->termination_packets) {
+ SendOrQueuePacket(std::make_unique<QueuedPacket>(
+ self_address, peer_address, packet->Clone()),
+ packet_context.get());
+ }
+ return;
+
case SEND_STATELESS_RESET:
if (header_format == IETF_QUIC_LONG_HEADER_PACKET) {
QUIC_CODE_COUNT(quic_stateless_reset_long_header_packet);
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 c9a5261d62f..64138de14bb 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
@@ -44,6 +44,9 @@ class QUIC_NO_EXPORT QuicTimeWaitListManager
// Send specified termination packets, error if termination packet is
// unavailable.
SEND_TERMINATION_PACKETS,
+ // The same as SEND_TERMINATION_PACKETS except that the corresponding
+ // termination packets are provided by the connection.
+ SEND_CONNECTION_CLOSE_PACKETS,
// Send stateless reset (public reset for GQUIC).
SEND_STATELESS_RESET,
@@ -244,6 +247,7 @@ class QUIC_NO_EXPORT QuicTimeWaitListManager
int num_packets;
bool ietf_quic;
QuicTime time_added;
+ // TODO(b/153096082) Remove this field.
// Encryption level of termination_packets.
EncryptionLevel encryption_level;
// These packets may contain CONNECTION_CLOSE frames, or SREJ messages.
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager_test.cc
index b07c83ea44f..468b21bf78f 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager_test.cc
@@ -113,8 +113,8 @@ class MockAlarmFactory : public QuicAlarmFactory {
return QuicArenaScopedPtr<MockAlarm>(
new MockAlarm(std::move(delegate), alarm_index_++, this));
}
- MOCK_METHOD2(OnAlarmSet, void(int, QuicTime));
- MOCK_METHOD1(OnAlarmCancelled, void(int));
+ MOCK_METHOD(void, OnAlarmSet, (int, QuicTime), ());
+ MOCK_METHOD(void, OnAlarmCancelled, (int), ());
private:
int alarm_index_ = 0;
@@ -322,9 +322,12 @@ TEST_F(QuicTimeWaitListManagerTest, SendConnectionClose) {
termination_packets.push_back(
std::unique_ptr<QuicEncryptedPacket>(new QuicEncryptedPacket(
new char[kConnectionCloseLength], kConnectionCloseLength, true)));
- AddConnectionId(connection_id_, QuicVersionMax(),
- QuicTimeWaitListManager::SEND_TERMINATION_PACKETS,
- &termination_packets);
+ AddConnectionId(
+ connection_id_, QuicVersionMax(),
+ GetQuicRestartFlag(quic_replace_time_wait_list_encryption_level)
+ ? QuicTimeWaitListManager::SEND_CONNECTION_CLOSE_PACKETS
+ : QuicTimeWaitListManager::SEND_TERMINATION_PACKETS,
+ &termination_packets);
EXPECT_CALL(writer_, WritePacket(_, kConnectionCloseLength,
self_address_.host(), peer_address_, _))
.WillOnce(Return(WriteResult(WRITE_STATUS_OK, 1)));
@@ -342,9 +345,12 @@ TEST_F(QuicTimeWaitListManagerTest, SendTwoConnectionCloses) {
termination_packets.push_back(
std::unique_ptr<QuicEncryptedPacket>(new QuicEncryptedPacket(
new char[kConnectionCloseLength], kConnectionCloseLength, true)));
- AddConnectionId(connection_id_, QuicVersionMax(),
- QuicTimeWaitListManager::SEND_TERMINATION_PACKETS,
- &termination_packets);
+ AddConnectionId(
+ connection_id_, QuicVersionMax(),
+ GetQuicRestartFlag(quic_replace_time_wait_list_encryption_level)
+ ? QuicTimeWaitListManager::SEND_CONNECTION_CLOSE_PACKETS
+ : QuicTimeWaitListManager::SEND_TERMINATION_PACKETS,
+ &termination_packets);
EXPECT_CALL(writer_, WritePacket(_, kConnectionCloseLength,
self_address_.host(), peer_address_, _))
.Times(2)
@@ -646,6 +652,30 @@ TEST_F(QuicTimeWaitListManagerTest,
IETF_QUIC_SHORT_HEADER_PACKET, std::make_unique<QuicPerPacketContext>());
}
+TEST_F(QuicTimeWaitListManagerTest,
+ SendConnectionClosePacketsInResponseToShortHeaders) {
+ SetQuicRestartFlag(quic_replace_time_wait_list_encryption_level, true);
+ const size_t kConnectionCloseLength = 100;
+ EXPECT_CALL(visitor_, OnConnectionAddedToTimeWaitList(connection_id_));
+ std::vector<std::unique_ptr<QuicEncryptedPacket>> termination_packets;
+ termination_packets.push_back(
+ std::unique_ptr<QuicEncryptedPacket>(new QuicEncryptedPacket(
+ new char[kConnectionCloseLength], kConnectionCloseLength, true)));
+ // Add a CONNECTION_CLOSE termination packet.
+ time_wait_list_manager_.AddConnectionIdToTimeWait(
+ connection_id_, /*ietf_quic=*/true,
+ QuicTimeWaitListManager::SEND_CONNECTION_CLOSE_PACKETS,
+ ENCRYPTION_INITIAL, &termination_packets);
+ EXPECT_CALL(writer_, WritePacket(_, kConnectionCloseLength,
+ self_address_.host(), peer_address_, _))
+ .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 1)));
+
+ // Processes IETF short header packet.
+ time_wait_list_manager_.ProcessPacket(
+ self_address_, peer_address_, connection_id_,
+ IETF_QUIC_SHORT_HEADER_PACKET, std::make_unique<QuicPerPacketContext>());
+}
+
} // namespace
} // namespace test
} // namespace quic
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 ce24d57113d..36614cd8f0a 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,7 +6,6 @@
#include <cstdint>
-#include "third_party/boringssl/src/include/openssl/ssl.h"
#include "net/third_party/quiche/src/quic/core/quic_error_codes.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h"
@@ -18,12 +17,56 @@ std::ostream& operator<<(std::ostream& os, const QuicConsumedData& s) {
return os;
}
-std::ostream& operator<<(std::ostream& os, const Perspective& s) {
- if (s == Perspective::IS_SERVER) {
- os << "IS_SERVER";
- } else {
- os << "IS_CLIENT";
+std::string PerspectiveToString(Perspective perspective) {
+ if (perspective == Perspective::IS_SERVER) {
+ return "IS_SERVER";
+ }
+ if (perspective == Perspective::IS_CLIENT) {
+ return "IS_CLIENT";
+ }
+ return quiche::QuicheStrCat("Unknown(", static_cast<int>(perspective), ")");
+}
+
+std::ostream& operator<<(std::ostream& os, const Perspective& perspective) {
+ os << PerspectiveToString(perspective);
+ return os;
+}
+
+std::string ConnectionCloseSourceToString(
+ ConnectionCloseSource connection_close_source) {
+ if (connection_close_source == ConnectionCloseSource::FROM_PEER) {
+ return "FROM_PEER";
+ }
+ if (connection_close_source == ConnectionCloseSource::FROM_SELF) {
+ return "FROM_SELF";
}
+ return quiche::QuicheStrCat("Unknown(",
+ static_cast<int>(connection_close_source), ")");
+}
+
+std::ostream& operator<<(std::ostream& os,
+ const ConnectionCloseSource& connection_close_source) {
+ os << ConnectionCloseSourceToString(connection_close_source);
+ return os;
+}
+
+std::string ConnectionCloseBehaviorToString(
+ ConnectionCloseBehavior connection_close_behavior) {
+ if (connection_close_behavior == ConnectionCloseBehavior::SILENT_CLOSE) {
+ return "SILENT_CLOSE";
+ }
+ if (connection_close_behavior ==
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET) {
+ return "SEND_CONNECTION_CLOSE_PACKET";
+ }
+ return quiche::QuicheStrCat("Unknown(",
+ static_cast<int>(connection_close_behavior), ")");
+}
+
+std::ostream& operator<<(
+ std::ostream& os,
+ const ConnectionCloseBehavior& connection_close_behavior) {
+ os << ConnectionCloseBehaviorToString(connection_close_behavior);
return os;
}
@@ -85,465 +128,6 @@ MessageResult::MessageResult(MessageStatus status, QuicMessageId message_id)
case x: \
return #x;
-std::string QuicIetfTransportErrorCodeString(QuicIetfTransportErrorCodes c) {
- if (static_cast<uint64_t>(c) >= 0xff00u) {
- return quiche::QuicheStrCat("Private(", static_cast<uint64_t>(c), ")");
- }
- if (c >= CRYPTO_ERROR_FIRST && c <= CRYPTO_ERROR_LAST) {
- const int tls_error = static_cast<int>(c - CRYPTO_ERROR_FIRST);
- const char* tls_error_description = SSL_alert_desc_string_long(tls_error);
- if (strcmp("unknown", tls_error_description) != 0) {
- return quiche::QuicheStrCat("CRYPTO_ERROR(", tls_error_description, ")");
- }
- return quiche::QuicheStrCat("CRYPTO_ERROR(unknown(", tls_error, "))");
- }
-
- switch (c) {
- RETURN_STRING_LITERAL(NO_IETF_QUIC_ERROR);
- RETURN_STRING_LITERAL(INTERNAL_ERROR);
- RETURN_STRING_LITERAL(SERVER_BUSY_ERROR);
- RETURN_STRING_LITERAL(FLOW_CONTROL_ERROR);
- RETURN_STRING_LITERAL(STREAM_LIMIT_ERROR);
- RETURN_STRING_LITERAL(STREAM_STATE_ERROR);
- RETURN_STRING_LITERAL(FINAL_SIZE_ERROR);
- RETURN_STRING_LITERAL(FRAME_ENCODING_ERROR);
- RETURN_STRING_LITERAL(TRANSPORT_PARAMETER_ERROR);
- RETURN_STRING_LITERAL(CONNECTION_ID_LIMIT_ERROR);
- RETURN_STRING_LITERAL(PROTOCOL_VIOLATION);
- RETURN_STRING_LITERAL(INVALID_TOKEN);
- RETURN_STRING_LITERAL(CRYPTO_BUFFER_EXCEEDED);
- // CRYPTO_ERROR is handled in the if before this switch, these cases do not
- // change behavior and are only here to make the compiler happy.
- case CRYPTO_ERROR_FIRST:
- case CRYPTO_ERROR_LAST:
- DCHECK(false) << "Unexpected error " << static_cast<uint64_t>(c);
- break;
- }
-
- return quiche::QuicheStrCat("Unknown(", static_cast<uint64_t>(c), ")");
-}
-
-std::ostream& operator<<(std::ostream& os,
- const QuicIetfTransportErrorCodes& c) {
- os << QuicIetfTransportErrorCodeString(c);
- return os;
-}
-
-QuicErrorCodeToIetfMapping QuicErrorCodeToTransportErrorCode(
- QuicErrorCode error) {
- switch (error) {
- // TODO(fkastenholz): Currently, all QuicError codes will map
- // to application error codes and the original Google QUIC error
- // code. This will change over time as we go through all calls to
- // CloseConnection() and see whether the call is a Transport or an
- // Application close and what the translated code should be.
- case QUIC_NO_ERROR:
- return {true, {static_cast<uint64_t>(QUIC_NO_ERROR)}};
- case QUIC_INTERNAL_ERROR:
- return {true, {static_cast<uint64_t>(QUIC_INTERNAL_ERROR)}};
- case QUIC_STREAM_DATA_AFTER_TERMINATION:
- return {true,
- {static_cast<uint64_t>(QUIC_STREAM_DATA_AFTER_TERMINATION)}};
- case QUIC_INVALID_PACKET_HEADER:
- return {true, {static_cast<uint64_t>(QUIC_INVALID_PACKET_HEADER)}};
- case QUIC_INVALID_FRAME_DATA:
- return {true, {static_cast<uint64_t>(QUIC_INVALID_FRAME_DATA)}};
- case QUIC_MISSING_PAYLOAD:
- return {true, {static_cast<uint64_t>(QUIC_MISSING_PAYLOAD)}};
- case QUIC_INVALID_FEC_DATA:
- return {true, {static_cast<uint64_t>(QUIC_INVALID_FEC_DATA)}};
- case QUIC_INVALID_STREAM_DATA:
- return {true, {static_cast<uint64_t>(QUIC_INVALID_STREAM_DATA)}};
- case QUIC_OVERLAPPING_STREAM_DATA:
- return {true, {static_cast<uint64_t>(QUIC_OVERLAPPING_STREAM_DATA)}};
- case QUIC_UNENCRYPTED_STREAM_DATA:
- return {true, {static_cast<uint64_t>(QUIC_UNENCRYPTED_STREAM_DATA)}};
- case QUIC_ATTEMPT_TO_SEND_UNENCRYPTED_STREAM_DATA:
- return {true,
- {static_cast<uint64_t>(
- QUIC_ATTEMPT_TO_SEND_UNENCRYPTED_STREAM_DATA)}};
- case QUIC_MAYBE_CORRUPTED_MEMORY:
- return {true, {static_cast<uint64_t>(QUIC_MAYBE_CORRUPTED_MEMORY)}};
- case QUIC_UNENCRYPTED_FEC_DATA:
- return {true, {static_cast<uint64_t>(QUIC_UNENCRYPTED_FEC_DATA)}};
- case QUIC_INVALID_RST_STREAM_DATA:
- return {true, {static_cast<uint64_t>(QUIC_INVALID_RST_STREAM_DATA)}};
- case QUIC_INVALID_CONNECTION_CLOSE_DATA:
- return {true,
- {static_cast<uint64_t>(QUIC_INVALID_CONNECTION_CLOSE_DATA)}};
- case QUIC_INVALID_GOAWAY_DATA:
- return {true, {static_cast<uint64_t>(QUIC_INVALID_GOAWAY_DATA)}};
- case QUIC_INVALID_WINDOW_UPDATE_DATA:
- return {true, {static_cast<uint64_t>(QUIC_INVALID_WINDOW_UPDATE_DATA)}};
- case QUIC_INVALID_BLOCKED_DATA:
- return {true, {static_cast<uint64_t>(QUIC_INVALID_BLOCKED_DATA)}};
- case QUIC_INVALID_STOP_WAITING_DATA:
- return {true, {static_cast<uint64_t>(QUIC_INVALID_STOP_WAITING_DATA)}};
- case QUIC_INVALID_PATH_CLOSE_DATA:
- return {true, {static_cast<uint64_t>(QUIC_INVALID_PATH_CLOSE_DATA)}};
- case QUIC_INVALID_ACK_DATA:
- return {true, {static_cast<uint64_t>(QUIC_INVALID_ACK_DATA)}};
- case QUIC_INVALID_MESSAGE_DATA:
- return {true, {static_cast<uint64_t>(QUIC_INVALID_MESSAGE_DATA)}};
- case QUIC_INVALID_VERSION_NEGOTIATION_PACKET:
- return {true,
- {static_cast<uint64_t>(QUIC_INVALID_VERSION_NEGOTIATION_PACKET)}};
- case QUIC_INVALID_PUBLIC_RST_PACKET:
- return {true, {static_cast<uint64_t>(QUIC_INVALID_PUBLIC_RST_PACKET)}};
- case QUIC_DECRYPTION_FAILURE:
- return {true, {static_cast<uint64_t>(QUIC_DECRYPTION_FAILURE)}};
- case QUIC_ENCRYPTION_FAILURE:
- return {true, {static_cast<uint64_t>(QUIC_ENCRYPTION_FAILURE)}};
- case QUIC_PACKET_TOO_LARGE:
- return {true, {static_cast<uint64_t>(QUIC_PACKET_TOO_LARGE)}};
- case QUIC_PEER_GOING_AWAY:
- return {true, {static_cast<uint64_t>(QUIC_PEER_GOING_AWAY)}};
- case QUIC_INVALID_STREAM_ID:
- return {true, {static_cast<uint64_t>(QUIC_INVALID_STREAM_ID)}};
- case QUIC_INVALID_PRIORITY:
- return {true, {static_cast<uint64_t>(QUIC_INVALID_PRIORITY)}};
- case QUIC_TOO_MANY_OPEN_STREAMS:
- return {true, {static_cast<uint64_t>(QUIC_TOO_MANY_OPEN_STREAMS)}};
- case QUIC_TOO_MANY_AVAILABLE_STREAMS:
- return {true, {static_cast<uint64_t>(QUIC_TOO_MANY_AVAILABLE_STREAMS)}};
- case QUIC_PUBLIC_RESET:
- return {true, {static_cast<uint64_t>(QUIC_PUBLIC_RESET)}};
- case QUIC_INVALID_VERSION:
- return {true, {static_cast<uint64_t>(QUIC_INVALID_VERSION)}};
- case QUIC_INVALID_HEADER_ID:
- return {true, {static_cast<uint64_t>(QUIC_INVALID_HEADER_ID)}};
- case QUIC_INVALID_NEGOTIATED_VALUE:
- return {true, {static_cast<uint64_t>(QUIC_INVALID_NEGOTIATED_VALUE)}};
- case QUIC_DECOMPRESSION_FAILURE:
- return {true, {static_cast<uint64_t>(QUIC_DECOMPRESSION_FAILURE)}};
- case QUIC_NETWORK_IDLE_TIMEOUT:
- return {true, {static_cast<uint64_t>(QUIC_NETWORK_IDLE_TIMEOUT)}};
- case QUIC_HANDSHAKE_TIMEOUT:
- return {true, {static_cast<uint64_t>(QUIC_HANDSHAKE_TIMEOUT)}};
- case QUIC_ERROR_MIGRATING_ADDRESS:
- return {true, {static_cast<uint64_t>(QUIC_ERROR_MIGRATING_ADDRESS)}};
- case QUIC_ERROR_MIGRATING_PORT:
- return {true, {static_cast<uint64_t>(QUIC_ERROR_MIGRATING_PORT)}};
- case QUIC_PACKET_WRITE_ERROR:
- return {true, {static_cast<uint64_t>(QUIC_PACKET_WRITE_ERROR)}};
- case QUIC_PACKET_READ_ERROR:
- return {true, {static_cast<uint64_t>(QUIC_PACKET_READ_ERROR)}};
- case QUIC_EMPTY_STREAM_FRAME_NO_FIN:
- return {true, {static_cast<uint64_t>(QUIC_EMPTY_STREAM_FRAME_NO_FIN)}};
- case QUIC_INVALID_HEADERS_STREAM_DATA:
- return {true, {static_cast<uint64_t>(QUIC_INVALID_HEADERS_STREAM_DATA)}};
- case QUIC_HEADERS_STREAM_DATA_DECOMPRESS_FAILURE:
- return {
- true,
- {static_cast<uint64_t>(QUIC_HEADERS_STREAM_DATA_DECOMPRESS_FAILURE)}};
- case QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA:
- return {
- true,
- {static_cast<uint64_t>(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA)}};
- case QUIC_FLOW_CONTROL_SENT_TOO_MUCH_DATA:
- return {true,
- {static_cast<uint64_t>(QUIC_FLOW_CONTROL_SENT_TOO_MUCH_DATA)}};
- case QUIC_FLOW_CONTROL_INVALID_WINDOW:
- return {true, {static_cast<uint64_t>(QUIC_FLOW_CONTROL_INVALID_WINDOW)}};
- case QUIC_CONNECTION_IP_POOLED:
- return {true, {static_cast<uint64_t>(QUIC_CONNECTION_IP_POOLED)}};
- case QUIC_TOO_MANY_OUTSTANDING_SENT_PACKETS:
- return {true,
- {static_cast<uint64_t>(QUIC_TOO_MANY_OUTSTANDING_SENT_PACKETS)}};
- case QUIC_TOO_MANY_OUTSTANDING_RECEIVED_PACKETS:
- return {
- true,
- {static_cast<uint64_t>(QUIC_TOO_MANY_OUTSTANDING_RECEIVED_PACKETS)}};
- case QUIC_CONNECTION_CANCELLED:
- return {true, {static_cast<uint64_t>(QUIC_CONNECTION_CANCELLED)}};
- case QUIC_BAD_PACKET_LOSS_RATE:
- return {true, {static_cast<uint64_t>(QUIC_BAD_PACKET_LOSS_RATE)}};
- case QUIC_PUBLIC_RESETS_POST_HANDSHAKE:
- return {true, {static_cast<uint64_t>(QUIC_PUBLIC_RESETS_POST_HANDSHAKE)}};
- case QUIC_FAILED_TO_SERIALIZE_PACKET:
- return {true, {static_cast<uint64_t>(QUIC_FAILED_TO_SERIALIZE_PACKET)}};
- case QUIC_TOO_MANY_RTOS:
- return {true, {static_cast<uint64_t>(QUIC_TOO_MANY_RTOS)}};
- case QUIC_HANDSHAKE_FAILED:
- return {true, {static_cast<uint64_t>(QUIC_HANDSHAKE_FAILED)}};
- case QUIC_CRYPTO_TAGS_OUT_OF_ORDER:
- return {true, {static_cast<uint64_t>(QUIC_CRYPTO_TAGS_OUT_OF_ORDER)}};
- case QUIC_CRYPTO_TOO_MANY_ENTRIES:
- return {true, {static_cast<uint64_t>(QUIC_CRYPTO_TOO_MANY_ENTRIES)}};
- case QUIC_CRYPTO_INVALID_VALUE_LENGTH:
- return {true, {static_cast<uint64_t>(QUIC_CRYPTO_INVALID_VALUE_LENGTH)}};
- case QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE:
- return {true,
- {static_cast<uint64_t>(
- QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE)}};
- case QUIC_INVALID_CRYPTO_MESSAGE_TYPE:
- return {true, {static_cast<uint64_t>(QUIC_INVALID_CRYPTO_MESSAGE_TYPE)}};
- case QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER:
- return {true,
- {static_cast<uint64_t>(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER)}};
- case QUIC_INVALID_CHANNEL_ID_SIGNATURE:
- return {true, {static_cast<uint64_t>(QUIC_INVALID_CHANNEL_ID_SIGNATURE)}};
- case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND:
- return {true,
- {static_cast<uint64_t>(QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND)}};
- case QUIC_CRYPTO_MESSAGE_PARAMETER_NO_OVERLAP:
- return {
- true,
- {static_cast<uint64_t>(QUIC_CRYPTO_MESSAGE_PARAMETER_NO_OVERLAP)}};
- case QUIC_CRYPTO_MESSAGE_INDEX_NOT_FOUND:
- return {true,
- {static_cast<uint64_t>(QUIC_CRYPTO_MESSAGE_INDEX_NOT_FOUND)}};
- case QUIC_UNSUPPORTED_PROOF_DEMAND:
- return {true, {static_cast<uint64_t>(QUIC_UNSUPPORTED_PROOF_DEMAND)}};
- case QUIC_CRYPTO_INTERNAL_ERROR:
- return {true, {static_cast<uint64_t>(QUIC_CRYPTO_INTERNAL_ERROR)}};
- case QUIC_CRYPTO_VERSION_NOT_SUPPORTED:
- return {true, {static_cast<uint64_t>(QUIC_CRYPTO_VERSION_NOT_SUPPORTED)}};
- case QUIC_CRYPTO_NO_SUPPORT:
- return {true, {static_cast<uint64_t>(QUIC_CRYPTO_NO_SUPPORT)}};
- case QUIC_CRYPTO_TOO_MANY_REJECTS:
- return {true, {static_cast<uint64_t>(QUIC_CRYPTO_TOO_MANY_REJECTS)}};
- case QUIC_PROOF_INVALID:
- return {true, {static_cast<uint64_t>(QUIC_PROOF_INVALID)}};
- case QUIC_CRYPTO_DUPLICATE_TAG:
- return {true, {static_cast<uint64_t>(QUIC_CRYPTO_DUPLICATE_TAG)}};
- case QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT:
- return {true,
- {static_cast<uint64_t>(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT)}};
- case QUIC_CRYPTO_SERVER_CONFIG_EXPIRED:
- return {true, {static_cast<uint64_t>(QUIC_CRYPTO_SERVER_CONFIG_EXPIRED)}};
- case QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED:
- return {true,
- {static_cast<uint64_t>(QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED)}};
- case QUIC_CRYPTO_MESSAGE_WHILE_VALIDATING_CLIENT_HELLO:
- return {true,
- {static_cast<uint64_t>(
- QUIC_CRYPTO_MESSAGE_WHILE_VALIDATING_CLIENT_HELLO)}};
- case QUIC_CRYPTO_UPDATE_BEFORE_HANDSHAKE_COMPLETE:
- return {true,
- {static_cast<uint64_t>(
- QUIC_CRYPTO_UPDATE_BEFORE_HANDSHAKE_COMPLETE)}};
- case QUIC_CRYPTO_CHLO_TOO_LARGE:
- return {true, {static_cast<uint64_t>(QUIC_CRYPTO_CHLO_TOO_LARGE)}};
- case QUIC_VERSION_NEGOTIATION_MISMATCH:
- return {true, {static_cast<uint64_t>(QUIC_VERSION_NEGOTIATION_MISMATCH)}};
- case QUIC_BAD_MULTIPATH_FLAG:
- return {true, {static_cast<uint64_t>(QUIC_BAD_MULTIPATH_FLAG)}};
- case QUIC_MULTIPATH_PATH_DOES_NOT_EXIST:
- return {true,
- {static_cast<uint64_t>(QUIC_MULTIPATH_PATH_DOES_NOT_EXIST)}};
- case QUIC_MULTIPATH_PATH_NOT_ACTIVE:
- return {true, {static_cast<uint64_t>(QUIC_MULTIPATH_PATH_NOT_ACTIVE)}};
- case QUIC_IP_ADDRESS_CHANGED:
- return {true, {static_cast<uint64_t>(QUIC_IP_ADDRESS_CHANGED)}};
- case QUIC_CONNECTION_MIGRATION_NO_MIGRATABLE_STREAMS:
- return {true,
- {static_cast<uint64_t>(
- QUIC_CONNECTION_MIGRATION_NO_MIGRATABLE_STREAMS)}};
- case QUIC_CONNECTION_MIGRATION_TOO_MANY_CHANGES:
- return {
- true,
- {static_cast<uint64_t>(QUIC_CONNECTION_MIGRATION_TOO_MANY_CHANGES)}};
- case QUIC_CONNECTION_MIGRATION_NO_NEW_NETWORK:
- return {
- true,
- {static_cast<uint64_t>(QUIC_CONNECTION_MIGRATION_NO_NEW_NETWORK)}};
- case QUIC_CONNECTION_MIGRATION_NON_MIGRATABLE_STREAM:
- return {true,
- {static_cast<uint64_t>(
- QUIC_CONNECTION_MIGRATION_NON_MIGRATABLE_STREAM)}};
- case QUIC_CONNECTION_MIGRATION_DISABLED_BY_CONFIG:
- return {true,
- {static_cast<uint64_t>(
- QUIC_CONNECTION_MIGRATION_DISABLED_BY_CONFIG)}};
- case QUIC_CONNECTION_MIGRATION_INTERNAL_ERROR:
- return {
- true,
- {static_cast<uint64_t>(QUIC_CONNECTION_MIGRATION_INTERNAL_ERROR)}};
- case QUIC_CONNECTION_MIGRATION_HANDSHAKE_UNCONFIRMED:
- return {true,
- {static_cast<uint64_t>(
- QUIC_CONNECTION_MIGRATION_HANDSHAKE_UNCONFIRMED)}};
- case QUIC_TOO_MANY_STREAM_DATA_INTERVALS:
- return {true,
- {static_cast<uint64_t>(QUIC_TOO_MANY_STREAM_DATA_INTERVALS)}};
- case QUIC_STREAM_SEQUENCER_INVALID_STATE:
- return {true,
- {static_cast<uint64_t>(QUIC_STREAM_SEQUENCER_INVALID_STATE)}};
- case QUIC_TOO_MANY_SESSIONS_ON_SERVER:
- return {true, {static_cast<uint64_t>(QUIC_TOO_MANY_SESSIONS_ON_SERVER)}};
- case QUIC_STREAM_LENGTH_OVERFLOW:
- return {true, {static_cast<uint64_t>(QUIC_STREAM_LENGTH_OVERFLOW)}};
- case QUIC_INVALID_MAX_DATA_FRAME_DATA:
- return {true, {static_cast<uint64_t>(QUIC_INVALID_MAX_DATA_FRAME_DATA)}};
- case QUIC_INVALID_MAX_STREAM_DATA_FRAME_DATA:
- return {true,
- {static_cast<uint64_t>(QUIC_INVALID_MAX_STREAM_DATA_FRAME_DATA)}};
- case QUIC_MAX_STREAMS_DATA:
- return {true, {static_cast<uint64_t>(QUIC_MAX_STREAMS_DATA)}};
- case QUIC_STREAMS_BLOCKED_DATA:
- return {true, {static_cast<uint64_t>(QUIC_STREAMS_BLOCKED_DATA)}};
- case QUIC_INVALID_STREAM_BLOCKED_DATA:
- return {true, {static_cast<uint64_t>(QUIC_INVALID_STREAM_BLOCKED_DATA)}};
- case QUIC_INVALID_NEW_CONNECTION_ID_DATA:
- return {true,
- {static_cast<uint64_t>(QUIC_INVALID_NEW_CONNECTION_ID_DATA)}};
- case QUIC_INVALID_STOP_SENDING_FRAME_DATA:
- return {true,
- {static_cast<uint64_t>(QUIC_INVALID_STOP_SENDING_FRAME_DATA)}};
- case QUIC_INVALID_PATH_CHALLENGE_DATA:
- return {true, {static_cast<uint64_t>(QUIC_INVALID_PATH_CHALLENGE_DATA)}};
- case QUIC_INVALID_PATH_RESPONSE_DATA:
- return {true, {static_cast<uint64_t>(QUIC_INVALID_PATH_RESPONSE_DATA)}};
- case IETF_QUIC_PROTOCOL_VIOLATION:
- return {true, {static_cast<uint64_t>(IETF_QUIC_PROTOCOL_VIOLATION)}};
- case QUIC_INVALID_NEW_TOKEN:
- return {true, {static_cast<uint64_t>(QUIC_INVALID_NEW_TOKEN)}};
- case QUIC_DATA_RECEIVED_ON_WRITE_UNIDIRECTIONAL_STREAM:
- return {true,
- {static_cast<uint64_t>(
- QUIC_DATA_RECEIVED_ON_WRITE_UNIDIRECTIONAL_STREAM)}};
- case QUIC_TRY_TO_WRITE_DATA_ON_READ_UNIDIRECTIONAL_STREAM:
- return {true,
- {static_cast<uint64_t>(
- QUIC_TRY_TO_WRITE_DATA_ON_READ_UNIDIRECTIONAL_STREAM)}};
- case QUIC_INVALID_RETIRE_CONNECTION_ID_DATA:
- return {true,
- {static_cast<uint64_t>(QUIC_INVALID_RETIRE_CONNECTION_ID_DATA)}};
- case QUIC_STREAMS_BLOCKED_ERROR:
- return {true, {static_cast<uint64_t>(QUIC_STREAMS_BLOCKED_ERROR)}};
- case QUIC_MAX_STREAMS_ERROR:
- return {true, {static_cast<uint64_t>(QUIC_MAX_STREAMS_ERROR)}};
- case QUIC_HTTP_DECODER_ERROR:
- return {true, {static_cast<uint64_t>(QUIC_HTTP_DECODER_ERROR)}};
- case QUIC_STALE_CONNECTION_CANCELLED:
- return {true, {static_cast<uint64_t>(QUIC_STALE_CONNECTION_CANCELLED)}};
- case QUIC_IETF_GQUIC_ERROR_MISSING:
- return {true, {static_cast<uint64_t>(QUIC_IETF_GQUIC_ERROR_MISSING)}};
- case QUIC_WINDOW_UPDATE_RECEIVED_ON_READ_UNIDIRECTIONAL_STREAM:
- return {true,
- {static_cast<uint64_t>(
- QUIC_WINDOW_UPDATE_RECEIVED_ON_READ_UNIDIRECTIONAL_STREAM)}};
- case QUIC_TOO_MANY_BUFFERED_CONTROL_FRAMES:
- return {true,
- {static_cast<uint64_t>(QUIC_TOO_MANY_BUFFERED_CONTROL_FRAMES)}};
- case QUIC_TRANSPORT_INVALID_CLIENT_INDICATION:
- return {false, {0u}};
- case QUIC_QPACK_DECOMPRESSION_FAILED:
- return {
- false,
- {static_cast<uint64_t>(IETF_QUIC_HTTP_QPACK_DECOMPRESSION_FAILED)}};
- case QUIC_QPACK_ENCODER_STREAM_ERROR:
- return {
- false,
- {static_cast<uint64_t>(IETF_QUIC_HTTP_QPACK_ENCODER_STREAM_ERROR)}};
- case QUIC_QPACK_DECODER_STREAM_ERROR:
- return {
- false,
- {static_cast<uint64_t>(IETF_QUIC_HTTP_QPACK_DECODER_STREAM_ERROR)}};
- case QUIC_STREAM_DATA_BEYOND_CLOSE_OFFSET:
- return {true,
- {static_cast<uint64_t>(QUIC_STREAM_DATA_BEYOND_CLOSE_OFFSET)}};
- case QUIC_STREAM_MULTIPLE_OFFSET:
- return {true, {static_cast<uint64_t>(QUIC_STREAM_MULTIPLE_OFFSET)}};
- case QUIC_HTTP_FRAME_TOO_LARGE:
- return {false,
- {static_cast<uint64_t>(
- QuicHttp3ErrorCode::IETF_QUIC_HTTP3_EXCESSIVE_LOAD)}};
- case QUIC_HTTP_FRAME_ERROR:
- return {false,
- {static_cast<uint64_t>(
- QuicHttp3ErrorCode::IETF_QUIC_HTTP3_FRAME_ERROR)}};
- case QUIC_HTTP_FRAME_UNEXPECTED_ON_SPDY_STREAM:
- return {false,
- {static_cast<uint64_t>(
- QuicHttp3ErrorCode::IETF_QUIC_HTTP3_FRAME_UNEXPECTED)}};
- case QUIC_HTTP_FRAME_UNEXPECTED_ON_CONTROL_STREAM:
- return {false,
- {static_cast<uint64_t>(
- QuicHttp3ErrorCode::IETF_QUIC_HTTP3_FRAME_UNEXPECTED)}};
- case QUIC_HTTP_INVALID_FRAME_SEQUENCE_ON_SPDY_STREAM:
- return {false,
- {static_cast<uint64_t>(
- QuicHttp3ErrorCode::IETF_QUIC_HTTP3_FRAME_UNEXPECTED)}};
- case QUIC_HTTP_INVALID_FRAME_SEQUENCE_ON_CONTROL_STREAM:
- return {false,
- {static_cast<uint64_t>(
- QuicHttp3ErrorCode::IETF_QUIC_HTTP3_FRAME_UNEXPECTED)}};
- case QUIC_HTTP_DUPLICATE_UNIDIRECTIONAL_STREAM:
- return {false,
- {static_cast<uint64_t>(
- QuicHttp3ErrorCode::IETF_QUIC_HTTP3_STREAM_CREATION_ERROR)}};
- case QUIC_HTTP_SERVER_INITIATED_BIDIRECTIONAL_STREAM:
- return {false,
- {static_cast<uint64_t>(
- QuicHttp3ErrorCode::IETF_QUIC_HTTP3_STREAM_CREATION_ERROR)}};
- case QUIC_HTTP_STREAM_WRONG_DIRECTION:
- return {true, {static_cast<uint64_t>(STREAM_STATE_ERROR)}};
- case QUIC_HTTP_CLOSED_CRITICAL_STREAM:
- return {false,
- {static_cast<uint64_t>(
- QuicHttp3ErrorCode::IETF_QUIC_HTTP3_CLOSED_CRITICAL_STREAM)}};
- case QUIC_HTTP_MISSING_SETTINGS_FRAME:
- return {false,
- {static_cast<uint64_t>(
- QuicHttp3ErrorCode::IETF_QUIC_HTTP3_MISSING_SETTINGS)}};
- case QUIC_HTTP_DUPLICATE_SETTING_IDENTIFIER:
- return {false,
- {static_cast<uint64_t>(
- QuicHttp3ErrorCode::IETF_QUIC_HTTP3_SETTINGS_ERROR)}};
- case QUIC_HPACK_INDEX_VARINT_ERROR:
- return {false, {static_cast<uint64_t>(QUIC_HPACK_INDEX_VARINT_ERROR)}};
- case QUIC_HPACK_NAME_LENGTH_VARINT_ERROR:
- return {false,
- {static_cast<uint64_t>(QUIC_HPACK_NAME_LENGTH_VARINT_ERROR)}};
- case QUIC_HPACK_VALUE_LENGTH_VARINT_ERROR:
- return {false,
- {static_cast<uint64_t>(QUIC_HPACK_VALUE_LENGTH_VARINT_ERROR)}};
- case QUIC_HPACK_NAME_TOO_LONG:
- return {false, {static_cast<uint64_t>(QUIC_HPACK_NAME_TOO_LONG)}};
- case QUIC_HPACK_VALUE_TOO_LONG:
- return {false, {static_cast<uint64_t>(QUIC_HPACK_VALUE_TOO_LONG)}};
- case QUIC_HPACK_NAME_HUFFMAN_ERROR:
- return {false, {static_cast<uint64_t>(QUIC_HPACK_NAME_HUFFMAN_ERROR)}};
- case QUIC_HPACK_VALUE_HUFFMAN_ERROR:
- return {false, {static_cast<uint64_t>(QUIC_HPACK_VALUE_HUFFMAN_ERROR)}};
- case QUIC_HPACK_MISSING_DYNAMIC_TABLE_SIZE_UPDATE:
- return {false,
- {static_cast<uint64_t>(
- QUIC_HPACK_MISSING_DYNAMIC_TABLE_SIZE_UPDATE)}};
- case QUIC_HPACK_INVALID_INDEX:
- return {false, {static_cast<uint64_t>(QUIC_HPACK_INVALID_INDEX)}};
- case QUIC_HPACK_INVALID_NAME_INDEX:
- return {false, {static_cast<uint64_t>(QUIC_HPACK_INVALID_NAME_INDEX)}};
- case QUIC_HPACK_DYNAMIC_TABLE_SIZE_UPDATE_NOT_ALLOWED:
- return {false,
- {static_cast<uint64_t>(
- QUIC_HPACK_DYNAMIC_TABLE_SIZE_UPDATE_NOT_ALLOWED)}};
- case QUIC_HPACK_INITIAL_TABLE_SIZE_UPDATE_IS_ABOVE_LOW_WATER_MARK:
- return {
- false,
- {static_cast<uint64_t>(
- QUIC_HPACK_INITIAL_TABLE_SIZE_UPDATE_IS_ABOVE_LOW_WATER_MARK)}};
- case QUIC_HPACK_TABLE_SIZE_UPDATE_IS_ABOVE_ACKNOWLEDGED_SETTING:
- return {false,
- {static_cast<uint64_t>(
- QUIC_HPACK_TABLE_SIZE_UPDATE_IS_ABOVE_ACKNOWLEDGED_SETTING)}};
- case QUIC_HPACK_TRUNCATED_BLOCK:
- return {false, {static_cast<uint64_t>(QUIC_HPACK_TRUNCATED_BLOCK)}};
- case QUIC_HPACK_FRAGMENT_TOO_LONG:
- return {false, {static_cast<uint64_t>(QUIC_HPACK_FRAGMENT_TOO_LONG)}};
- case QUIC_HPACK_COMPRESSED_HEADER_SIZE_EXCEEDS_LIMIT:
- return {false,
- {static_cast<uint64_t>(
- QUIC_HPACK_COMPRESSED_HEADER_SIZE_EXCEEDS_LIMIT)}};
- case QUIC_LAST_ERROR:
- return {false, {static_cast<uint64_t>(QUIC_LAST_ERROR)}};
- }
- // If it's an unknown code, indicate it's an application error code.
- return {false, {NO_IETF_QUIC_ERROR}};
-}
-
std::string QuicIetfFrameTypeString(QuicIetfFrameType t) {
if (IS_IETF_STREAM_FRAME(t)) {
return "IETF_STREAM";
@@ -730,4 +314,6 @@ std::ostream& operator<<(std::ostream& os, AddressChangeType type) {
return os;
}
+#undef RETURN_STRING_LITERAL // undef for jumbo builds
+
} // namespace quic
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 76d3bab90cc..f2919ef3766 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
@@ -21,39 +21,42 @@
namespace quic {
-typedef uint16_t QuicPacketLength;
-typedef uint32_t QuicControlFrameId;
-typedef uint32_t QuicHeaderId;
-typedef uint32_t QuicMessageId;
-typedef uint64_t QuicDatagramFlowId;
-
-typedef uint32_t QuicStreamId;
-
-// Count of stream IDs. Used in MAX_STREAMS and STREAMS_BLOCKED
-// frames.
-typedef uint32_t QuicStreamCount;
-
-typedef uint64_t QuicByteCount;
-typedef uint64_t QuicPacketCount;
-typedef uint64_t QuicPublicResetNonceProof;
-typedef uint64_t QuicStreamOffset;
-typedef std::array<char, 32> DiversificationNonce;
-typedef std::vector<std::pair<QuicPacketNumber, QuicTime>> PacketTimeVector;
-
-typedef uint64_t QuicIetfStreamDataLength;
-typedef uint64_t QuicIetfStreamId;
-typedef uint64_t QuicIetfStreamOffset;
-
-const size_t kQuicPathFrameBufferSize = 8;
-typedef std::array<uint8_t, kQuicPathFrameBufferSize> QuicPathFrameBuffer;
+using QuicPacketLength = uint16_t;
+using QuicControlFrameId = uint32_t;
+using QuicMessageId = uint32_t;
+using QuicDatagramFlowId = uint64_t;
+
+// IMPORTANT: IETF QUIC defines stream IDs and stream counts as being unsigned
+// 62-bit numbers. However, we have decided to only support up to 2^32-1 streams
+// in order to reduce the size of data structures such as QuicStreamFrame
+// and QuicTransmissionInfo, as that allows them to fit in cache lines and has
+// visible perfomance impact.
+using QuicStreamId = uint32_t;
+
+// Count of stream IDs. Used in MAX_STREAMS and STREAMS_BLOCKED frames.
+using QuicStreamCount = QuicStreamId;
+
+using QuicByteCount = uint64_t;
+using QuicPacketCount = uint64_t;
+using QuicPublicResetNonceProof = uint64_t;
+using QuicStreamOffset = uint64_t;
+using DiversificationNonce = std::array<char, 32>;
+using PacketTimeVector = std::vector<std::pair<QuicPacketNumber, QuicTime>>;
+
+enum : size_t { kQuicPathFrameBufferSize = 8 };
+using QuicPathFrameBuffer = std::array<uint8_t, kQuicPathFrameBufferSize>;
// Application error code used in the QUIC Stop Sending frame.
-typedef uint16_t QuicApplicationErrorCode;
+using QuicApplicationErrorCode = uint16_t;
// The connection id sequence number specifies the order that connection
// ids must be used in. This is also the sequence number carried in
// the IETF QUIC NEW_CONNECTION_ID and RETIRE_CONNECTION_ID frames.
-typedef uint64_t QuicConnectionIdSequenceNumber;
+using QuicConnectionIdSequenceNumber = uint64_t;
+
+// A custom data that represents application-specific settings.
+// In HTTP/3 for example, it includes the encoded SETTINGS.
+using ApplicationState = std::vector<uint8_t>;
// A struct for functions which consume data payloads and fins.
struct QUIC_EXPORT_PRIVATE QuicConsumedData {
@@ -183,18 +186,32 @@ enum HasRetransmittableData : uint8_t {
enum IsHandshake : uint8_t { NOT_HANDSHAKE, IS_HANDSHAKE };
enum class Perspective : uint8_t { IS_SERVER, IS_CLIENT };
+
+QUIC_EXPORT_PRIVATE std::string PerspectiveToString(Perspective perspective);
QUIC_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
- const Perspective& s);
+ const Perspective& perspective);
// Describes whether a ConnectionClose was originated by the peer.
enum class ConnectionCloseSource { FROM_PEER, FROM_SELF };
+QUIC_EXPORT_PRIVATE std::string ConnectionCloseSourceToString(
+ ConnectionCloseSource connection_close_source);
+QUIC_EXPORT_PRIVATE std::ostream& operator<<(
+ std::ostream& os,
+ const ConnectionCloseSource& connection_close_source);
+
// Should a connection be closed silently or not.
enum class ConnectionCloseBehavior {
SILENT_CLOSE,
SEND_CONNECTION_CLOSE_PACKET
};
+QUIC_EXPORT_PRIVATE std::string ConnectionCloseBehaviorToString(
+ ConnectionCloseBehavior connection_close_behavior);
+QUIC_EXPORT_PRIVATE std::ostream& operator<<(
+ std::ostream& os,
+ const ConnectionCloseBehavior& connection_close_behavior);
+
enum QuicFrameType : uint8_t {
// Regular frame types. The values set here cannot change without the
// introduction of a new QUIC version.
@@ -313,13 +330,12 @@ enum QuicVariableLengthIntegerLength : uint8_t {
VARIABLE_LENGTH_INTEGER_LENGTH_2 = 2,
VARIABLE_LENGTH_INTEGER_LENGTH_4 = 4,
VARIABLE_LENGTH_INTEGER_LENGTH_8 = 8,
-};
-// By default we write the IETF long header length using the 2-byte encoding
-// of variable length integers, even when the length is below 64, which allows
-// us to fill in the length before knowing what the length actually is.
-const QuicVariableLengthIntegerLength kQuicDefaultLongHeaderLengthLength =
- VARIABLE_LENGTH_INTEGER_LENGTH_2;
+ // By default we write the IETF long header length using the 2-byte encoding
+ // of variable length integers, even when the length is below 64, which allows
+ // us to fill in the length before knowing what the length actually is.
+ kQuicDefaultLongHeaderLengthLength = VARIABLE_LENGTH_INTEGER_LENGTH_2,
+};
enum QuicPacketNumberLength : uint8_t {
PACKET_1BYTE_PACKET_NUMBER = 1,
@@ -529,7 +545,7 @@ struct QUIC_EXPORT_PRIVATE AckedPacket {
};
// A vector of acked packets.
-typedef QuicInlinedVector<AckedPacket, 2> AckedPacketVector;
+using AckedPacketVector = QuicInlinedVector<AckedPacket, 2>;
// Information about a newly lost packet.
struct QUIC_EXPORT_PRIVATE LostPacket {
@@ -546,46 +562,7 @@ struct QUIC_EXPORT_PRIVATE LostPacket {
};
// A vector of lost packets.
-typedef QuicInlinedVector<LostPacket, 2> LostPacketVector;
-
-enum QuicIetfTransportErrorCodes : uint64_t {
- NO_IETF_QUIC_ERROR = 0x0,
- INTERNAL_ERROR = 0x1,
- SERVER_BUSY_ERROR = 0x2,
- FLOW_CONTROL_ERROR = 0x3,
- STREAM_LIMIT_ERROR = 0x4,
- STREAM_STATE_ERROR = 0x5,
- FINAL_SIZE_ERROR = 0x6,
- FRAME_ENCODING_ERROR = 0x7,
- TRANSPORT_PARAMETER_ERROR = 0x8,
- CONNECTION_ID_LIMIT_ERROR = 0x9,
- PROTOCOL_VIOLATION = 0xA,
- INVALID_TOKEN = 0xB,
- CRYPTO_BUFFER_EXCEEDED = 0xD,
- CRYPTO_ERROR_FIRST = 0x100,
- CRYPTO_ERROR_LAST = 0x1FF,
-};
-QUIC_EXPORT_PRIVATE std::string QuicIetfTransportErrorCodeString(
- QuicIetfTransportErrorCodes c);
-
-QUIC_EXPORT_PRIVATE std::ostream& operator<<(
- std::ostream& os,
- const QuicIetfTransportErrorCodes& c);
-
-// Returns the mapping of the QuicErrorCode to an IETF TransportErrorCode. If
-// first element of the pair is false, it means that an IETF Application Close
-// should be done instead.
-
-struct QUIC_EXPORT_PRIVATE QuicErrorCodeToIetfMapping {
- bool is_transport_close_;
- union {
- uint64_t application_error_code_;
- QuicIetfTransportErrorCodes transport_error_code_;
- };
-};
-
-QUIC_EXPORT_PRIVATE QuicErrorCodeToIetfMapping
-QuicErrorCodeToTransportErrorCode(QuicErrorCode error);
+using LostPacketVector = QuicInlinedVector<LostPacket, 2>;
// Please note, this value cannot used directly for packet serialization.
enum QuicLongHeaderType : uint8_t {
@@ -716,11 +693,11 @@ QUIC_EXPORT_PRIVATE std::string SerializedPacketFateToString(
SerializedPacketFate fate);
// There are three different forms of CONNECTION_CLOSE.
-typedef enum QuicConnectionCloseType {
+enum QuicConnectionCloseType {
GOOGLE_QUIC_CONNECTION_CLOSE = 0,
IETF_QUIC_TRANSPORT_CONNECTION_CLOSE = 1,
IETF_QUIC_APPLICATION_CONNECTION_CLOSE = 2
-} QuicConnectionCloseType;
+};
QUIC_EXPORT_PRIVATE std::ostream& operator<<(
std::ostream& os,
@@ -750,6 +727,13 @@ enum HandshakeState {
HANDSHAKE_CONFIRMED,
};
+struct QUIC_NO_EXPORT NextReleaseTimeResult {
+ // The ideal release time of the packet being sent.
+ QuicTime release_time;
+ // Whether it is allowed to send the packet before release_time.
+ bool allow_burst;
+};
+
} // namespace quic
#endif // QUICHE_QUIC_CORE_QUIC_TYPES_H_
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
deleted file mode 100644
index dc37c43e24e..00000000000
--- a/chromium/net/third_party/quiche/src/quic/core/quic_types_test.cc
+++ /dev/null
@@ -1,61 +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/core/quic_types.h"
-
-#include <cstdint>
-
-#include "third_party/boringssl/src/include/openssl/ssl.h"
-#include "net/third_party/quiche/src/quic/core/quic_error_codes.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
-
-namespace quic {
-namespace test {
-namespace {
-
-class QuicTypesTest : public QuicTest {};
-
-TEST_F(QuicTypesTest, QuicIetfTransportErrorCodeString) {
- EXPECT_EQ("Private(65280)",
- QuicIetfTransportErrorCodeString(
- static_cast<quic::QuicIetfTransportErrorCodes>(0xff00u)));
-
- EXPECT_EQ("CRYPTO_ERROR(missing extension)",
- QuicIetfTransportErrorCodeString(
- static_cast<quic::QuicIetfTransportErrorCodes>(
- CRYPTO_ERROR_FIRST + SSL_AD_MISSING_EXTENSION)));
-
- EXPECT_EQ("NO_IETF_QUIC_ERROR",
- QuicIetfTransportErrorCodeString(NO_IETF_QUIC_ERROR));
- EXPECT_EQ("INTERNAL_ERROR", QuicIetfTransportErrorCodeString(INTERNAL_ERROR));
- EXPECT_EQ("SERVER_BUSY_ERROR",
- QuicIetfTransportErrorCodeString(SERVER_BUSY_ERROR));
- EXPECT_EQ("FLOW_CONTROL_ERROR",
- QuicIetfTransportErrorCodeString(FLOW_CONTROL_ERROR));
- EXPECT_EQ("STREAM_LIMIT_ERROR",
- QuicIetfTransportErrorCodeString(STREAM_LIMIT_ERROR));
- EXPECT_EQ("STREAM_STATE_ERROR",
- QuicIetfTransportErrorCodeString(STREAM_STATE_ERROR));
- EXPECT_EQ("FINAL_SIZE_ERROR",
- QuicIetfTransportErrorCodeString(FINAL_SIZE_ERROR));
- EXPECT_EQ("FRAME_ENCODING_ERROR",
- QuicIetfTransportErrorCodeString(FRAME_ENCODING_ERROR));
- EXPECT_EQ("TRANSPORT_PARAMETER_ERROR",
- QuicIetfTransportErrorCodeString(TRANSPORT_PARAMETER_ERROR));
- EXPECT_EQ("CONNECTION_ID_LIMIT_ERROR",
- QuicIetfTransportErrorCodeString(CONNECTION_ID_LIMIT_ERROR));
- EXPECT_EQ("PROTOCOL_VIOLATION",
- QuicIetfTransportErrorCodeString(PROTOCOL_VIOLATION));
- EXPECT_EQ("INVALID_TOKEN", QuicIetfTransportErrorCodeString(INVALID_TOKEN));
- EXPECT_EQ("CRYPTO_BUFFER_EXCEEDED",
- QuicIetfTransportErrorCodeString(CRYPTO_BUFFER_EXCEEDED));
-
- EXPECT_EQ("Unknown(1024)",
- QuicIetfTransportErrorCodeString(
- static_cast<quic::QuicIetfTransportErrorCodes>(0x400)));
-}
-
-} // namespace
-} // namespace test
-} // namespace quic
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 1dda8881066..0a014bebe78 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
@@ -20,7 +20,7 @@ QuicVersionManager::QuicVersionManager(
enable_version_draft_25_(
GetQuicReloadableFlag(quic_enable_version_draft_25_v3)),
disable_version_q050_(GetQuicReloadableFlag(quic_disable_version_q050)),
- enable_version_t050_(GetQuicReloadableFlag(quic_enable_version_t050)),
+ enable_version_t050_(GetQuicReloadableFlag(quic_enable_version_t050_v2)),
disable_version_q049_(GetQuicReloadableFlag(quic_disable_version_q049)),
disable_version_q048_(GetQuicReloadableFlag(quic_disable_version_q048)),
disable_version_q046_(GetQuicReloadableFlag(quic_disable_version_q046)),
@@ -44,6 +44,17 @@ const ParsedQuicVersionVector& QuicVersionManager::GetSupportedVersions() {
return filtered_supported_versions_;
}
+const ParsedQuicVersionVector&
+QuicVersionManager::GetSupportedVersionsWithQuicCrypto() {
+ MaybeRefilterSupportedVersions();
+ return filtered_supported_versions_with_quic_crypto_;
+}
+
+const std::vector<std::string>& QuicVersionManager::GetSupportedAlpns() {
+ MaybeRefilterSupportedVersions();
+ return filtered_supported_alpns_;
+}
+
void QuicVersionManager::MaybeRefilterSupportedVersions() {
static_assert(SupportedVersions().size() == 8u,
"Supported versions out of sync");
@@ -53,7 +64,8 @@ void QuicVersionManager::MaybeRefilterSupportedVersions() {
GetQuicReloadableFlag(quic_enable_version_draft_25_v3) ||
disable_version_q050_ !=
GetQuicReloadableFlag(quic_disable_version_q050) ||
- enable_version_t050_ != GetQuicReloadableFlag(quic_enable_version_t050) ||
+ enable_version_t050_ !=
+ GetQuicReloadableFlag(quic_enable_version_t050_v2) ||
disable_version_q049_ !=
GetQuicReloadableFlag(quic_disable_version_q049) ||
disable_version_q048_ !=
@@ -67,7 +79,7 @@ void QuicVersionManager::MaybeRefilterSupportedVersions() {
enable_version_draft_25_ =
GetQuicReloadableFlag(quic_enable_version_draft_25_v3);
disable_version_q050_ = GetQuicReloadableFlag(quic_disable_version_q050);
- enable_version_t050_ = GetQuicReloadableFlag(quic_enable_version_t050);
+ enable_version_t050_ = GetQuicReloadableFlag(quic_enable_version_t050_v2);
disable_version_q049_ = GetQuicReloadableFlag(quic_disable_version_q049);
disable_version_q048_ = GetQuicReloadableFlag(quic_disable_version_q048);
disable_version_q046_ = GetQuicReloadableFlag(quic_disable_version_q046);
@@ -80,15 +92,25 @@ void QuicVersionManager::MaybeRefilterSupportedVersions() {
void QuicVersionManager::RefilterSupportedVersions() {
filtered_supported_versions_ =
FilterSupportedVersions(allowed_supported_versions_);
+ filtered_supported_versions_with_quic_crypto_.clear();
filtered_transport_versions_.clear();
- for (ParsedQuicVersion version : filtered_supported_versions_) {
+ filtered_supported_alpns_.clear();
+ for (const ParsedQuicVersion& version : filtered_supported_versions_) {
auto transport_version = version.transport_version;
if (std::find(filtered_transport_versions_.begin(),
filtered_transport_versions_.end(),
transport_version) == filtered_transport_versions_.end()) {
filtered_transport_versions_.push_back(transport_version);
}
+ if (version.handshake_protocol == PROTOCOL_QUIC_CRYPTO) {
+ filtered_supported_versions_with_quic_crypto_.push_back(version);
+ }
+ filtered_supported_alpns_.emplace_back(AlpnForVersion(version));
}
}
+void QuicVersionManager::AddCustomAlpn(const std::string& alpn) {
+ filtered_supported_alpns_.push_back(alpn);
+}
+
} // namespace quic
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 4d683745bdc..c5111edf260 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
@@ -26,6 +26,13 @@ class QUIC_EXPORT_PRIVATE QuicVersionManager {
// as the versions passed to the constructor.
const ParsedQuicVersionVector& GetSupportedVersions();
+ // Returns currently supported versions using QUIC crypto.
+ const ParsedQuicVersionVector& GetSupportedVersionsWithQuicCrypto();
+
+ // Returns the list of supported ALPNs, based on the current supported
+ // versions and any custom additions by subclasses.
+ const std::vector<std::string>& GetSupportedAlpns();
+
protected:
// If the value of any reloadable flag is different from the cached value,
// re-filter |filtered_supported_versions_| and update the cached flag values.
@@ -39,6 +46,10 @@ class QUIC_EXPORT_PRIVATE QuicVersionManager {
return filtered_transport_versions_;
}
+ // Mechanism for subclasses to add custom ALPNs to the supported list.
+ // Should be called in constructor and RefilterSupportedVersions.
+ void AddCustomAlpn(const std::string& alpn);
+
private:
// Cached value of reloadable flags.
// quic_enable_version_draft_27 flag
@@ -47,7 +58,7 @@ class QUIC_EXPORT_PRIVATE QuicVersionManager {
bool enable_version_draft_25_;
// quic_disable_version_q050 flag
bool disable_version_q050_;
- // quic_enable_version_t050 flag
+ // quic_enable_version_t050_v2 flag
bool enable_version_t050_;
// quic_disable_version_q049 flag
bool disable_version_q049_;
@@ -63,10 +74,15 @@ class QUIC_EXPORT_PRIVATE QuicVersionManager {
// This vector contains QUIC versions which are currently supported based on
// flags.
ParsedQuicVersionVector filtered_supported_versions_;
+ // Currently supported versions using QUIC crypto.
+ ParsedQuicVersionVector filtered_supported_versions_with_quic_crypto_;
// This vector contains the transport versions from
// |filtered_supported_versions_|. No guarantees are made that the same
// transport version isn't repeated.
QuicTransportVersionVector filtered_transport_versions_;
+ // Contains the list of ALPNs corresponding to filtered_supported_versions_
+ // with custom ALPNs added.
+ std::vector<std::string> filtered_supported_alpns_;
};
} // namespace quic
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 98dc4a348ec..3a8e98ff520 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
@@ -9,6 +9,8 @@
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_arraysize.h"
+using ::testing::ElementsAre;
+
namespace quic {
namespace test {
namespace {
@@ -20,7 +22,7 @@ TEST_F(QuicVersionManagerTest, QuicVersionManager) {
"Supported versions out of sync");
SetQuicReloadableFlag(quic_enable_version_draft_27, false);
SetQuicReloadableFlag(quic_enable_version_draft_25_v3, false);
- SetQuicReloadableFlag(quic_enable_version_t050, false);
+ SetQuicReloadableFlag(quic_enable_version_t050_v2, false);
SetQuicReloadableFlag(quic_disable_version_q050, false);
SetQuicReloadableFlag(quic_disable_version_q049, false);
SetQuicReloadableFlag(quic_disable_version_q048, false);
@@ -41,30 +43,59 @@ TEST_F(QuicVersionManagerTest, QuicVersionManager) {
ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43));
EXPECT_EQ(expected_parsed_versions, manager.GetSupportedVersions());
+ EXPECT_EQ(expected_parsed_versions,
+ manager.GetSupportedVersionsWithQuicCrypto());
EXPECT_EQ(FilterSupportedVersions(AllSupportedVersions()),
manager.GetSupportedVersions());
+ EXPECT_EQ(CurrentSupportedVersionsWithQuicCrypto(),
+ manager.GetSupportedVersionsWithQuicCrypto());
+ EXPECT_THAT(
+ manager.GetSupportedAlpns(),
+ ElementsAre("h3-Q050", "h3-Q049", "h3-Q048", "h3-Q046", "h3-Q043"));
SetQuicReloadableFlag(quic_enable_version_draft_27, true);
- expected_parsed_versions.push_back(
+ expected_parsed_versions.insert(
+ expected_parsed_versions.begin(),
ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27));
EXPECT_EQ(expected_parsed_versions, manager.GetSupportedVersions());
+ EXPECT_EQ(expected_parsed_versions.size() - 1,
+ manager.GetSupportedVersionsWithQuicCrypto().size());
EXPECT_EQ(FilterSupportedVersions(AllSupportedVersions()),
manager.GetSupportedVersions());
+ EXPECT_EQ(CurrentSupportedVersionsWithQuicCrypto(),
+ manager.GetSupportedVersionsWithQuicCrypto());
+ EXPECT_THAT(manager.GetSupportedAlpns(),
+ ElementsAre("h3-27", "h3-Q050", "h3-Q049", "h3-Q048", "h3-Q046",
+ "h3-Q043"));
SetQuicReloadableFlag(quic_enable_version_draft_25_v3, true);
- expected_parsed_versions.push_back(
+ expected_parsed_versions.insert(
+ expected_parsed_versions.begin() + 1,
ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_25));
EXPECT_EQ(expected_parsed_versions, manager.GetSupportedVersions());
- EXPECT_EQ(FilterSupportedVersions(AllSupportedVersions()),
- manager.GetSupportedVersions());
+ EXPECT_EQ(expected_parsed_versions.size() - 2,
+ manager.GetSupportedVersionsWithQuicCrypto().size());
+ EXPECT_EQ(CurrentSupportedVersionsWithQuicCrypto(),
+ manager.GetSupportedVersionsWithQuicCrypto());
+ EXPECT_THAT(manager.GetSupportedAlpns(),
+ ElementsAre("h3-27", "h3-25", "h3-Q050", "h3-Q049", "h3-Q048",
+ "h3-Q046", "h3-Q043"));
- SetQuicReloadableFlag(quic_enable_version_t050, true);
- expected_parsed_versions.push_back(
+ SetQuicReloadableFlag(quic_enable_version_t050_v2, true);
+ expected_parsed_versions.insert(
+ expected_parsed_versions.begin() + 2,
ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50));
EXPECT_EQ(expected_parsed_versions, manager.GetSupportedVersions());
+ EXPECT_EQ(expected_parsed_versions.size() - 3,
+ manager.GetSupportedVersionsWithQuicCrypto().size());
EXPECT_EQ(FilterSupportedVersions(AllSupportedVersions()),
manager.GetSupportedVersions());
+ EXPECT_EQ(CurrentSupportedVersionsWithQuicCrypto(),
+ manager.GetSupportedVersionsWithQuicCrypto());
+ EXPECT_THAT(manager.GetSupportedAlpns(),
+ ElementsAre("h3-27", "h3-25", "h3-T050", "h3-Q050", "h3-Q049",
+ "h3-Q048", "h3-Q046", "h3-Q043"));
}
} // namespace
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 6dc67d92078..bf93e8383d2 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
@@ -158,6 +158,16 @@ bool ParsedQuicVersion::HasVarIntTransportParams() const {
return transport_version >= QUIC_VERSION_IETF_DRAFT_27;
}
+bool ParsedQuicVersion::UsesTls() const {
+ DCHECK(IsKnown());
+ return handshake_protocol == PROTOCOL_TLS1_3;
+}
+
+bool ParsedQuicVersion::UsesQuicCrypto() const {
+ DCHECK(IsKnown());
+ return handshake_protocol == PROTOCOL_QUIC_CRYPTO;
+}
+
bool VersionHasLengthPrefixedConnectionIds(
QuicTransportVersion transport_version) {
DCHECK(transport_version != QUIC_VERSION_UNSUPPORTED);
@@ -169,6 +179,24 @@ std::ostream& operator<<(std::ostream& os, const ParsedQuicVersion& version) {
return os;
}
+std::ostream& operator<<(std::ostream& os,
+ const ParsedQuicVersionVector& versions) {
+ os << ParsedQuicVersionVectorToString(versions);
+ return os;
+}
+
+std::ostream& operator<<(std::ostream& os,
+ const QuicVersionLabelVector& version_labels) {
+ os << QuicVersionLabelVectorToString(version_labels);
+ return os;
+}
+
+std::ostream& operator<<(std::ostream& os,
+ const QuicTransportVersionVector& transport_versions) {
+ os << QuicTransportVersionVectorToString(transport_versions);
+ return os;
+}
+
QuicVersionLabel CreateQuicVersionLabel(ParsedQuicVersion parsed_version) {
char proto = 0;
switch (parsed_version.handshake_protocol) {
@@ -251,6 +279,17 @@ ParsedQuicVersionVector CurrentSupportedVersionsWithQuicCrypto() {
return versions;
}
+ParsedQuicVersionVector AllSupportedVersionsWithTls() {
+ ParsedQuicVersionVector versions;
+ for (const ParsedQuicVersion& version : AllSupportedVersions()) {
+ if (version.handshake_protocol == PROTOCOL_TLS1_3) {
+ versions.push_back(version);
+ }
+ }
+ QUIC_BUG_IF(versions.empty()) << "No version with TLS handshake found.";
+ return versions;
+}
+
ParsedQuicVersionVector CurrentSupportedVersionsWithTls() {
ParsedQuicVersionVector versions;
for (const ParsedQuicVersion& version : CurrentSupportedVersions()) {
@@ -369,7 +408,7 @@ ParsedQuicVersionVector FilterSupportedVersions(
filtered_versions.push_back(version);
}
} else {
- if (GetQuicReloadableFlag(quic_enable_version_t050)) {
+ if (GetQuicReloadableFlag(quic_enable_version_t050_v2)) {
filtered_versions.push_back(version);
}
}
@@ -619,7 +658,7 @@ void QuicEnableVersion(ParsedQuicVersion parsed_version) {
if (parsed_version.handshake_protocol == PROTOCOL_QUIC_CRYPTO) {
SetQuicReloadableFlag(quic_disable_version_q050, false);
} else {
- SetQuicReloadableFlag(quic_enable_version_t050, true);
+ SetQuicReloadableFlag(quic_enable_version_t050_v2, true);
}
} else if (parsed_version.transport_version == QUIC_VERSION_49) {
SetQuicReloadableFlag(quic_disable_version_q049, false);
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 7850b416fc9..5f3a9689198 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
@@ -330,6 +330,12 @@ struct QUIC_EXPORT_PRIVATE ParsedQuicVersion {
// Returns true if this version uses variable-length integers when
// encoding transport parameter types and lengths.
bool HasVarIntTransportParams() const;
+
+ // Returns whether this version uses PROTOCOL_TLS1_3.
+ bool UsesTls() const;
+
+ // Returns whether this version uses PROTOCOL_QUIC_CRYPTO.
+ bool UsesQuicCrypto() const;
};
QUIC_EXPORT_PRIVATE ParsedQuicVersion UnsupportedQuicVersion();
@@ -341,31 +347,43 @@ QUIC_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
using ParsedQuicVersionVector = std::vector<ParsedQuicVersion>;
+QUIC_EXPORT_PRIVATE std::ostream& operator<<(
+ std::ostream& os,
+ const ParsedQuicVersionVector& versions);
+
// Representation of the on-the-wire QUIC version number. Will be written/read
// to the wire in network-byte-order.
using QuicVersionLabel = uint32_t;
using QuicVersionLabelVector = std::vector<QuicVersionLabel>;
+QUIC_EXPORT_PRIVATE std::ostream& operator<<(
+ std::ostream& os,
+ const QuicVersionLabelVector& version_labels);
+
// This vector contains all crypto handshake protocols that are supported.
constexpr std::array<HandshakeProtocol, 2> SupportedHandshakeProtocols() {
- return {PROTOCOL_QUIC_CRYPTO, PROTOCOL_TLS1_3};
+ return {PROTOCOL_TLS1_3, PROTOCOL_QUIC_CRYPTO};
}
constexpr std::array<ParsedQuicVersion, 8> SupportedVersions() {
return {
+ ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27),
+ ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_25),
+ ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50),
ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50),
ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_49),
ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_48),
ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46),
ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43),
- ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27),
- ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_25),
- ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50),
};
}
using QuicTransportVersionVector = std::vector<QuicTransportVersion>;
+QUIC_EXPORT_PRIVATE std::ostream& operator<<(
+ std::ostream& os,
+ const QuicTransportVersionVector& transport_versions);
+
// Returns a vector of QUIC versions in kSupportedTransportVersions.
QUIC_EXPORT_PRIVATE QuicTransportVersionVector AllSupportedTransportVersions();
@@ -395,6 +413,10 @@ AllSupportedVersionsWithQuicCrypto();
QUIC_EXPORT_PRIVATE ParsedQuicVersionVector
CurrentSupportedVersionsWithQuicCrypto();
+// Returns a subset of AllSupportedVersions() with
+// handshake_protocol == PROTOCOL_TLS1_3, in the same order.
+QUIC_EXPORT_PRIVATE ParsedQuicVersionVector AllSupportedVersionsWithTls();
+
// Returns a subset of CurrentSupportedVersions() with handshake_protocol ==
// PROTOCOL_TLS1_3.
QUIC_EXPORT_PRIVATE ParsedQuicVersionVector CurrentSupportedVersionsWithTls();
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 216b0800bbe..3a07221ab94 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
@@ -83,6 +83,65 @@ TEST_F(QuicVersionsTest, KnownAndValid) {
static_cast<QuicTransportVersion>(99)));
}
+TEST_F(QuicVersionsTest, Features) {
+ ParsedQuicVersion parsed_version_q043 =
+ ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43);
+ ParsedQuicVersion parsed_version_draft_27 =
+ ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27);
+
+ EXPECT_TRUE(parsed_version_q043.IsKnown());
+ EXPECT_FALSE(parsed_version_q043.KnowsWhichDecrypterToUse());
+ EXPECT_FALSE(parsed_version_q043.UsesInitialObfuscators());
+ EXPECT_FALSE(parsed_version_q043.AllowsLowFlowControlLimits());
+ EXPECT_FALSE(parsed_version_q043.HasHeaderProtection());
+ EXPECT_FALSE(parsed_version_q043.SupportsRetry());
+ EXPECT_FALSE(parsed_version_q043.HasRetryIntegrityTag());
+ EXPECT_FALSE(
+ parsed_version_q043.SendsVariableLengthPacketNumberInLongHeader());
+ EXPECT_FALSE(parsed_version_q043.AllowsVariableLengthConnectionIds());
+ EXPECT_FALSE(parsed_version_q043.SupportsClientConnectionIds());
+ EXPECT_FALSE(parsed_version_q043.HasLengthPrefixedConnectionIds());
+ EXPECT_FALSE(parsed_version_q043.SupportsAntiAmplificationLimit());
+ EXPECT_FALSE(parsed_version_q043.CanSendCoalescedPackets());
+ EXPECT_TRUE(parsed_version_q043.SupportsGoogleAltSvcFormat());
+ EXPECT_FALSE(parsed_version_q043.HasIetfInvariantHeader());
+ EXPECT_FALSE(parsed_version_q043.SupportsMessageFrames());
+ EXPECT_FALSE(parsed_version_q043.UsesHttp3());
+ EXPECT_FALSE(parsed_version_q043.HasLongHeaderLengths());
+ EXPECT_FALSE(parsed_version_q043.UsesCryptoFrames());
+ EXPECT_FALSE(parsed_version_q043.HasIetfQuicFrames());
+ EXPECT_FALSE(parsed_version_q043.HasHandshakeDone());
+ EXPECT_FALSE(parsed_version_q043.HasVarIntTransportParams());
+ EXPECT_FALSE(parsed_version_q043.UsesTls());
+ EXPECT_TRUE(parsed_version_q043.UsesQuicCrypto());
+
+ EXPECT_TRUE(parsed_version_draft_27.IsKnown());
+ EXPECT_TRUE(parsed_version_draft_27.KnowsWhichDecrypterToUse());
+ EXPECT_TRUE(parsed_version_draft_27.UsesInitialObfuscators());
+ EXPECT_TRUE(parsed_version_draft_27.AllowsLowFlowControlLimits());
+ EXPECT_TRUE(parsed_version_draft_27.HasHeaderProtection());
+ EXPECT_TRUE(parsed_version_draft_27.SupportsRetry());
+ EXPECT_TRUE(parsed_version_draft_27.HasRetryIntegrityTag());
+ EXPECT_TRUE(
+ parsed_version_draft_27.SendsVariableLengthPacketNumberInLongHeader());
+ EXPECT_TRUE(parsed_version_draft_27.AllowsVariableLengthConnectionIds());
+ EXPECT_TRUE(parsed_version_draft_27.SupportsClientConnectionIds());
+ EXPECT_TRUE(parsed_version_draft_27.HasLengthPrefixedConnectionIds());
+ EXPECT_TRUE(parsed_version_draft_27.SupportsAntiAmplificationLimit());
+ EXPECT_TRUE(parsed_version_draft_27.CanSendCoalescedPackets());
+ EXPECT_FALSE(parsed_version_draft_27.SupportsGoogleAltSvcFormat());
+ EXPECT_TRUE(parsed_version_draft_27.HasIetfInvariantHeader());
+ EXPECT_TRUE(parsed_version_draft_27.SupportsMessageFrames());
+ EXPECT_TRUE(parsed_version_draft_27.UsesHttp3());
+ EXPECT_TRUE(parsed_version_draft_27.HasLongHeaderLengths());
+ EXPECT_TRUE(parsed_version_draft_27.UsesCryptoFrames());
+ EXPECT_TRUE(parsed_version_draft_27.HasIetfQuicFrames());
+ EXPECT_TRUE(parsed_version_draft_27.HasHandshakeDone());
+ EXPECT_TRUE(parsed_version_draft_27.HasVarIntTransportParams());
+ EXPECT_TRUE(parsed_version_draft_27.UsesTls());
+ EXPECT_FALSE(parsed_version_draft_27.UsesQuicCrypto());
+}
+
TEST_F(QuicVersionsTest, QuicVersionLabelToQuicTransportVersion) {
// If you add a new version to the QuicTransportVersion enum you will need to
// add a new case to QuicVersionLabelToQuicTransportVersion, otherwise this
@@ -318,6 +377,10 @@ TEST_F(QuicVersionsTest, QuicVersionLabelToString) {
QuicVersionLabelVectorToString(version_labels, ":", 2));
EXPECT_EQ("Q035|Q037|...",
QuicVersionLabelVectorToString(version_labels, "|", 1));
+
+ std::ostringstream os;
+ os << version_labels;
+ EXPECT_EQ("Q035,Q037,T038", os.str());
}
TEST_F(QuicVersionsTest, QuicVersionToString) {
@@ -346,6 +409,10 @@ TEST_F(QuicVersionsTest, QuicVersionToString) {
EXPECT_NE("QUIC_VERSION_UNSUPPORTED",
QuicVersionToString(transport_version));
}
+
+ std::ostringstream os;
+ os << versions_vector;
+ EXPECT_EQ("QUIC_VERSION_UNSUPPORTED,QUIC_VERSION_43", os.str());
}
TEST_F(QuicVersionsTest, ParsedQuicVersionToString) {
@@ -368,6 +435,10 @@ TEST_F(QuicVersionsTest, ParsedQuicVersionToString) {
for (const ParsedQuicVersion& version : AllSupportedVersions()) {
EXPECT_NE("0", ParsedQuicVersionToString(version));
}
+
+ std::ostringstream os;
+ os << versions_vector;
+ EXPECT_EQ("0,Q043", os.str());
}
TEST_F(QuicVersionsTest, FilterSupportedVersionsAllVersions) {
@@ -375,7 +446,7 @@ TEST_F(QuicVersionsTest, FilterSupportedVersionsAllVersions) {
"Supported versions out of sync");
SetQuicReloadableFlag(quic_enable_version_draft_27, true);
SetQuicReloadableFlag(quic_enable_version_draft_25_v3, true);
- SetQuicReloadableFlag(quic_enable_version_t050, true);
+ SetQuicReloadableFlag(quic_enable_version_t050_v2, true);
SetQuicReloadableFlag(quic_disable_version_q050, false);
SetQuicReloadableFlag(quic_disable_version_q049, false);
SetQuicReloadableFlag(quic_disable_version_q048, false);
@@ -384,6 +455,12 @@ TEST_F(QuicVersionsTest, FilterSupportedVersionsAllVersions) {
ParsedQuicVersionVector expected_parsed_versions;
expected_parsed_versions.push_back(
+ ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27));
+ expected_parsed_versions.push_back(
+ ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_25));
+ expected_parsed_versions.push_back(
+ ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50));
+ expected_parsed_versions.push_back(
ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50));
expected_parsed_versions.push_back(
ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_49));
@@ -393,12 +470,6 @@ TEST_F(QuicVersionsTest, FilterSupportedVersionsAllVersions) {
ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46));
expected_parsed_versions.push_back(
ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43));
- expected_parsed_versions.push_back(
- ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27));
- expected_parsed_versions.push_back(
- ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_25));
- expected_parsed_versions.push_back(
- ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50));
ASSERT_EQ(expected_parsed_versions,
FilterSupportedVersions(AllSupportedVersions()));
@@ -410,7 +481,7 @@ TEST_F(QuicVersionsTest, FilterSupportedVersionsNo99) {
"Supported versions out of sync");
SetQuicReloadableFlag(quic_enable_version_draft_27, false);
SetQuicReloadableFlag(quic_enable_version_draft_25_v3, true);
- SetQuicReloadableFlag(quic_enable_version_t050, true);
+ SetQuicReloadableFlag(quic_enable_version_t050_v2, true);
SetQuicReloadableFlag(quic_disable_version_q050, false);
SetQuicReloadableFlag(quic_disable_version_q049, false);
SetQuicReloadableFlag(quic_disable_version_q048, false);
@@ -419,6 +490,10 @@ TEST_F(QuicVersionsTest, FilterSupportedVersionsNo99) {
ParsedQuicVersionVector expected_parsed_versions;
expected_parsed_versions.push_back(
+ ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_25));
+ expected_parsed_versions.push_back(
+ ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50));
+ expected_parsed_versions.push_back(
ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50));
expected_parsed_versions.push_back(
ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_49));
@@ -428,10 +503,6 @@ TEST_F(QuicVersionsTest, FilterSupportedVersionsNo99) {
ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46));
expected_parsed_versions.push_back(
ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43));
- expected_parsed_versions.push_back(
- ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_25));
- expected_parsed_versions.push_back(
- ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50));
ASSERT_EQ(expected_parsed_versions,
FilterSupportedVersions(AllSupportedVersions()));
@@ -442,7 +513,7 @@ TEST_F(QuicVersionsTest, FilterSupportedVersionsNoFlags) {
"Supported versions out of sync");
SetQuicReloadableFlag(quic_enable_version_draft_27, false);
SetQuicReloadableFlag(quic_enable_version_draft_25_v3, false);
- SetQuicReloadableFlag(quic_enable_version_t050, false);
+ SetQuicReloadableFlag(quic_enable_version_t050_v2, false);
SetQuicReloadableFlag(quic_disable_version_q050, false);
SetQuicReloadableFlag(quic_disable_version_q049, false);
SetQuicReloadableFlag(quic_disable_version_q048, false);
@@ -574,9 +645,9 @@ TEST_F(QuicVersionsTest, QuicEnableVersion) {
{
QuicFlagSaver flag_saver;
- SetQuicReloadableFlag(quic_enable_version_t050, false);
+ SetQuicReloadableFlag(quic_enable_version_t050_v2, false);
QuicEnableVersion(parsed_version_t050);
- EXPECT_TRUE(GetQuicReloadableFlag(quic_enable_version_t050));
+ EXPECT_TRUE(GetQuicReloadableFlag(quic_enable_version_t050_v2));
}
{
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 c98711292f3..4100df0fc96 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
@@ -66,6 +66,10 @@ class QUIC_EXPORT_PRIVATE QuicWriteBlockedList {
return priority_write_scheduler_->ShouldYield(id);
}
+ spdy::SpdyPriority GetSpdyPriorityofStream(QuicStreamId id) const {
+ return priority_write_scheduler_->GetStreamPrecedence(id).spdy3_priority();
+ }
+
// Switches write scheduler. This can only be called before any stream is
// registered.
bool SwitchWriteScheduler(spdy::WriteSchedulerType type,
@@ -145,7 +149,8 @@ class QUIC_EXPORT_PRIVATE QuicWriteBlockedList {
void RegisterStream(QuicStreamId stream_id,
bool is_static_stream,
const spdy::SpdyStreamPrecedence& precedence) {
- DCHECK(!priority_write_scheduler_->StreamRegistered(stream_id));
+ DCHECK(!priority_write_scheduler_->StreamRegistered(stream_id))
+ << "stream " << stream_id << " already registered";
DCHECK(PrecedenceMatchesSchedulerType(precedence));
if (is_static_stream) {
static_stream_collection_.Register(stream_id);
diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_chlo_extractor.cc b/chromium/net/third_party/quiche/src/quic/core/tls_chlo_extractor.cc
new file mode 100644
index 00000000000..7c10d2c8e0b
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/tls_chlo_extractor.cc
@@ -0,0 +1,395 @@
+// Copyright (c) 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/core/tls_chlo_extractor.h"
+#include <cstring>
+#include <memory>
+
+#include "third_party/boringssl/src/include/openssl/ssl.h"
+#include "net/third_party/quiche/src/quic/core/frames/quic_crypto_frame.h"
+#include "net/third_party/quiche/src/quic/core/quic_data_reader.h"
+#include "net/third_party/quiche/src/quic/core/quic_error_codes.h"
+#include "net/third_party/quiche/src/quic/core/quic_framer.h"
+#include "net/third_party/quiche/src/quic/core/quic_time.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/core/quic_versions.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
+#include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h"
+#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
+#include "net/third_party/quiche/src/common/platform/api/quiche_text_utils.h"
+
+namespace quic {
+
+TlsChloExtractor::TlsChloExtractor()
+ : crypto_stream_sequencer_(this),
+ state_(State::kInitial),
+ parsed_crypto_frame_in_this_packet_(false) {}
+
+TlsChloExtractor::TlsChloExtractor(TlsChloExtractor&& other)
+ : TlsChloExtractor() {
+ *this = std::move(other);
+}
+
+TlsChloExtractor& TlsChloExtractor::operator=(TlsChloExtractor&& other) {
+ framer_ = std::move(other.framer_);
+ if (framer_) {
+ framer_->set_visitor(this);
+ }
+ crypto_stream_sequencer_ = std::move(other.crypto_stream_sequencer_);
+ crypto_stream_sequencer_.set_stream(this);
+ ssl_ = std::move(other.ssl_);
+ if (ssl_) {
+ std::pair<SSL_CTX*, int> shared_handles = GetSharedSslHandles();
+ int ex_data_index = shared_handles.second;
+ const int rv = SSL_set_ex_data(ssl_.get(), ex_data_index, this);
+ CHECK_EQ(rv, 1) << "Internal allocation failure in SSL_set_ex_data";
+ }
+ state_ = other.state_;
+ error_details_ = std::move(other.error_details_);
+ parsed_crypto_frame_in_this_packet_ =
+ other.parsed_crypto_frame_in_this_packet_;
+ alpns_ = std::move(other.alpns_);
+ server_name_ = std::move(other.server_name_);
+ return *this;
+}
+
+void TlsChloExtractor::IngestPacket(const ParsedQuicVersion& version,
+ const QuicReceivedPacket& packet) {
+ if (state_ == State::kUnrecoverableFailure) {
+ QUIC_DLOG(ERROR) << "Not ingesting packet after unrecoverable error";
+ return;
+ }
+ if (version == UnsupportedQuicVersion()) {
+ QUIC_DLOG(ERROR) << "Not ingesting packet with unsupported version";
+ return;
+ }
+ if (version.handshake_protocol != PROTOCOL_TLS1_3) {
+ QUIC_DLOG(ERROR) << "Not ingesting packet with non-TLS version " << version;
+ return;
+ }
+ if (framer_) {
+ // This is not the first packet we have ingested, check if version matches.
+ if (!framer_->IsSupportedVersion(version)) {
+ QUIC_DLOG(ERROR)
+ << "Not ingesting packet with version mismatch, expected "
+ << framer_->version() << ", got " << version;
+ return;
+ }
+ } else {
+ // This is the first packet we have ingested, setup parser.
+ framer_ = std::make_unique<QuicFramer>(
+ ParsedQuicVersionVector{version}, QuicTime::Zero(),
+ Perspective::IS_SERVER, /*expected_server_connection_id_length=*/0);
+ // Note that expected_server_connection_id_length only matters for short
+ // headers and we explicitly drop those so we can pass any value here.
+ framer_->set_visitor(this);
+ }
+
+ // When the framer parses |packet|, if it sees a CRYPTO frame it will call
+ // OnCryptoFrame below and that will set parsed_crypto_frame_in_this_packet_
+ // to true.
+ parsed_crypto_frame_in_this_packet_ = false;
+ const bool parse_success = framer_->ProcessPacket(packet);
+ if (state_ == State::kInitial && parsed_crypto_frame_in_this_packet_) {
+ // If we parsed a CRYPTO frame but didn't advance the state from initial,
+ // then it means that we will need more packets to reassemble the full CHLO,
+ // so we advance the state here. This can happen when the first packet
+ // received is not the first one in the crypto stream. This allows us to
+ // differentiate our state between single-packet CHLO and multi-packet CHLO.
+ state_ = State::kParsedPartialChloFragment;
+ }
+
+ if (!parse_success) {
+ // This could be due to the packet being non-initial for example.
+ QUIC_DLOG(ERROR) << "Failed to process packet";
+ return;
+ }
+}
+
+// This is called when the framer parsed the unencrypted parts of the header.
+bool TlsChloExtractor::OnUnauthenticatedPublicHeader(
+ const QuicPacketHeader& header) {
+ if (header.form != IETF_QUIC_LONG_HEADER_PACKET) {
+ QUIC_DLOG(ERROR) << "Not parsing non-long-header packet " << header;
+ return false;
+ }
+ if (header.long_packet_type != INITIAL) {
+ QUIC_DLOG(ERROR) << "Not parsing non-initial packet " << header;
+ return false;
+ }
+ // QuicFramer is constructed without knowledge of the server's connection ID
+ // so it needs to be set up here in order to decrypt the packet.
+ framer_->SetInitialObfuscators(header.destination_connection_id);
+ return true;
+}
+
+// This is called by the framer if it detects a change in version during
+// parsing.
+bool TlsChloExtractor::OnProtocolVersionMismatch(ParsedQuicVersion version) {
+ // This should never be called because we already check versions in
+ // IngestPacket.
+ QUIC_BUG << "Unexpected version mismatch, expected " << framer_->version()
+ << ", got " << version;
+ return false;
+}
+
+// This is called by the QuicStreamSequencer if it encounters an unrecoverable
+// error that will prevent it from reassembling the crypto stream data.
+void TlsChloExtractor::OnUnrecoverableError(QuicErrorCode error,
+ const std::string& details) {
+ HandleUnrecoverableError(quiche::QuicheStrCat(
+ "Crypto stream error ", QuicErrorCodeToString(error), ": ", details));
+}
+
+// This is called by the framer if it sees a CRYPTO frame during parsing.
+bool TlsChloExtractor::OnCryptoFrame(const QuicCryptoFrame& frame) {
+ if (frame.level != ENCRYPTION_INITIAL) {
+ // Since we drop non-INITIAL packets in OnUnauthenticatedPublicHeader,
+ // we should never receive any CRYPTO frames at other encryption levels.
+ QUIC_BUG << "Parsed bad-level CRYPTO frame " << frame;
+ return false;
+ }
+ // parsed_crypto_frame_in_this_packet_ is checked in IngestPacket to allow
+ // advancing our state to track the difference between single-packet CHLO
+ // and multi-packet CHLO.
+ parsed_crypto_frame_in_this_packet_ = true;
+ crypto_stream_sequencer_.OnCryptoFrame(frame);
+ return true;
+}
+
+// Called by the QuicStreamSequencer when it receives a CRYPTO frame that
+// advances the amount of contiguous data we now have starting from offset 0.
+void TlsChloExtractor::OnDataAvailable() {
+ // Lazily set up BoringSSL handle.
+ SetupSslHandle();
+
+ // Get data from the stream sequencer and pass it to BoringSSL.
+ struct iovec iov;
+ while (crypto_stream_sequencer_.GetReadableRegion(&iov)) {
+ const int rv = SSL_provide_quic_data(
+ ssl_.get(), ssl_encryption_initial,
+ reinterpret_cast<const uint8_t*>(iov.iov_base), iov.iov_len);
+ if (rv != 1) {
+ HandleUnrecoverableError("SSL_provide_quic_data failed");
+ return;
+ }
+ crypto_stream_sequencer_.MarkConsumed(iov.iov_len);
+ }
+
+ // Instruct BoringSSL to attempt parsing a full CHLO from the provided data.
+ // We ignore the return value since we know the handshake is going to fail
+ // because we explicitly cancel processing once we've parsed the CHLO.
+ (void)SSL_do_handshake(ssl_.get());
+}
+
+// static
+TlsChloExtractor* TlsChloExtractor::GetInstanceFromSSL(SSL* ssl) {
+ std::pair<SSL_CTX*, int> shared_handles = GetSharedSslHandles();
+ int ex_data_index = shared_handles.second;
+ return reinterpret_cast<TlsChloExtractor*>(
+ SSL_get_ex_data(ssl, ex_data_index));
+}
+
+// static
+int TlsChloExtractor::SetReadSecretCallback(
+ SSL* ssl,
+ enum ssl_encryption_level_t /*level*/,
+ const SSL_CIPHER* /*cipher*/,
+ const uint8_t* /*secret*/,
+ size_t /*secret_length*/) {
+ GetInstanceFromSSL(ssl)->HandleUnexpectedCallback("SetReadSecretCallback");
+ return 0;
+}
+
+// static
+int TlsChloExtractor::SetWriteSecretCallback(
+ SSL* ssl,
+ enum ssl_encryption_level_t /*level*/,
+ const SSL_CIPHER* /*cipher*/,
+ const uint8_t* /*secret*/,
+ size_t /*secret_length*/) {
+ GetInstanceFromSSL(ssl)->HandleUnexpectedCallback("SetWriteSecretCallback");
+ return 0;
+}
+
+// static
+int TlsChloExtractor::WriteMessageCallback(
+ SSL* ssl,
+ enum ssl_encryption_level_t /*level*/,
+ const uint8_t* /*data*/,
+ size_t /*len*/) {
+ GetInstanceFromSSL(ssl)->HandleUnexpectedCallback("WriteMessageCallback");
+ return 0;
+}
+
+// static
+int TlsChloExtractor::FlushFlightCallback(SSL* ssl) {
+ GetInstanceFromSSL(ssl)->HandleUnexpectedCallback("FlushFlightCallback");
+ return 0;
+}
+
+void TlsChloExtractor::HandleUnexpectedCallback(
+ const std::string& callback_name) {
+ std::string error_details =
+ quiche::QuicheStrCat("Unexpected callback ", callback_name);
+ QUIC_BUG << error_details;
+ HandleUnrecoverableError(error_details);
+}
+
+// static
+int TlsChloExtractor::SendAlertCallback(SSL* ssl,
+ enum ssl_encryption_level_t /*level*/,
+ uint8_t desc) {
+ GetInstanceFromSSL(ssl)->SendAlert(desc);
+ return 0;
+}
+
+void TlsChloExtractor::SendAlert(uint8_t tls_alert_value) {
+ if (tls_alert_value == SSL3_AD_HANDSHAKE_FAILURE && HasParsedFullChlo()) {
+ // This is the most common scenario. Since we return an error from
+ // SelectCertCallback in order to cancel further processing, BoringSSL will
+ // try to send this alert to tell the client that the handshake failed.
+ return;
+ }
+ HandleUnrecoverableError(quiche::QuicheStrCat(
+ "BoringSSL attempted to send alert ", static_cast<int>(tls_alert_value),
+ " ", SSL_alert_desc_string_long(tls_alert_value)));
+}
+
+// static
+enum ssl_select_cert_result_t TlsChloExtractor::SelectCertCallback(
+ const SSL_CLIENT_HELLO* client_hello) {
+ GetInstanceFromSSL(client_hello->ssl)->HandleParsedChlo(client_hello);
+ // Always return an error to cancel any further processing in BoringSSL.
+ return ssl_select_cert_error;
+}
+
+// Extracts the server name and ALPN from the parsed ClientHello.
+void TlsChloExtractor::HandleParsedChlo(const SSL_CLIENT_HELLO* client_hello) {
+ const char* server_name =
+ SSL_get_servername(client_hello->ssl, TLSEXT_NAMETYPE_host_name);
+ if (server_name) {
+ server_name_ = std::string(server_name);
+ }
+ const uint8_t* alpn_data;
+ size_t alpn_len;
+ int rv = SSL_early_callback_ctx_extension_get(
+ client_hello, TLSEXT_TYPE_application_layer_protocol_negotiation,
+ &alpn_data, &alpn_len);
+ if (rv == 1) {
+ QuicDataReader alpns_reader(reinterpret_cast<const char*>(alpn_data),
+ alpn_len);
+ quiche::QuicheStringPiece alpns_payload;
+ if (!alpns_reader.ReadStringPiece16(&alpns_payload)) {
+ HandleUnrecoverableError("Failed to read alpns_payload");
+ return;
+ }
+ QuicDataReader alpns_payload_reader(alpns_payload);
+ while (!alpns_payload_reader.IsDoneReading()) {
+ quiche::QuicheStringPiece alpn_payload;
+ if (!alpns_payload_reader.ReadStringPiece8(&alpn_payload)) {
+ HandleUnrecoverableError("Failed to read alpn_payload");
+ return;
+ }
+ alpns_.emplace_back(std::string(alpn_payload));
+ }
+ }
+
+ // Update our state now that we've parsed a full CHLO.
+ if (state_ == State::kInitial) {
+ state_ = State::kParsedFullSinglePacketChlo;
+ } else if (state_ == State::kParsedPartialChloFragment) {
+ state_ = State::kParsedFullMultiPacketChlo;
+ } else {
+ QUIC_BUG << "Unexpected state on successful parse "
+ << StateToString(state_);
+ }
+}
+
+// static
+std::pair<SSL_CTX*, int> TlsChloExtractor::GetSharedSslHandles() {
+ // Use a lambda to benefit from C++11 guarantee that static variables are
+ // initialized lazily in a thread-safe manner. |shared_handles| is therefore
+ // guaranteed to be initialized exactly once and never destructed.
+ static std::pair<SSL_CTX*, int>* shared_handles = []() {
+ CRYPTO_library_init();
+ SSL_CTX* ssl_ctx = SSL_CTX_new(TLS_with_buffers_method());
+ SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_3_VERSION);
+ SSL_CTX_set_max_proto_version(ssl_ctx, TLS1_3_VERSION);
+ static const SSL_QUIC_METHOD kQuicCallbacks{
+ TlsChloExtractor::SetReadSecretCallback,
+ TlsChloExtractor::SetWriteSecretCallback,
+ TlsChloExtractor::WriteMessageCallback,
+ TlsChloExtractor::FlushFlightCallback,
+ TlsChloExtractor::SendAlertCallback};
+ SSL_CTX_set_quic_method(ssl_ctx, &kQuicCallbacks);
+ SSL_CTX_set_select_certificate_cb(ssl_ctx,
+ TlsChloExtractor::SelectCertCallback);
+ int ex_data_index =
+ SSL_get_ex_new_index(0, nullptr, nullptr, nullptr, nullptr);
+ return new std::pair<SSL_CTX*, int>(ssl_ctx, ex_data_index);
+ }();
+ return *shared_handles;
+}
+
+// Sets up the per-instance SSL handle needed by BoringSSL.
+void TlsChloExtractor::SetupSslHandle() {
+ if (ssl_) {
+ // Handles have already been set up.
+ return;
+ }
+
+ std::pair<SSL_CTX*, int> shared_handles = GetSharedSslHandles();
+ SSL_CTX* ssl_ctx = shared_handles.first;
+ int ex_data_index = shared_handles.second;
+
+ ssl_ = bssl::UniquePtr<SSL>(SSL_new(ssl_ctx));
+ const int rv = SSL_set_ex_data(ssl_.get(), ex_data_index, this);
+ CHECK_EQ(rv, 1) << "Internal allocation failure in SSL_set_ex_data";
+ SSL_set_accept_state(ssl_.get());
+}
+
+// Called by other methods to record any unrecoverable failures they experience.
+void TlsChloExtractor::HandleUnrecoverableError(
+ const std::string& error_details) {
+ if (HasParsedFullChlo()) {
+ // Ignore errors if we've parsed everything successfully.
+ QUIC_DLOG(ERROR) << "Ignoring error: " << error_details;
+ return;
+ }
+ QUIC_DLOG(ERROR) << "Handling error: " << error_details;
+
+ state_ = State::kUnrecoverableFailure;
+
+ if (error_details_.empty()) {
+ error_details_ = error_details;
+ } else {
+ error_details_ = quiche::QuicheStrCat(error_details_, "; ", error_details);
+ }
+}
+
+// static
+std::string TlsChloExtractor::StateToString(State state) {
+ switch (state) {
+ case State::kInitial:
+ return "Initial";
+ case State::kParsedFullSinglePacketChlo:
+ return "ParsedFullSinglePacketChlo";
+ case State::kParsedFullMultiPacketChlo:
+ return "ParsedFullMultiPacketChlo";
+ case State::kParsedPartialChloFragment:
+ return "ParsedPartialChloFragment";
+ case State::kUnrecoverableFailure:
+ return "UnrecoverableFailure";
+ }
+ return quiche::QuicheStrCat("Unknown(", static_cast<int>(state), ")");
+}
+
+std::ostream& operator<<(std::ostream& os,
+ const TlsChloExtractor::State& state) {
+ os << TlsChloExtractor::StateToString(state);
+ return os;
+}
+
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_chlo_extractor.h b/chromium/net/third_party/quiche/src/quic/core/tls_chlo_extractor.h
new file mode 100644
index 00000000000..1762566d70a
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/tls_chlo_extractor.h
@@ -0,0 +1,238 @@
+// Copyright (c) 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_CORE_TLS_CHLO_EXTRACTOR_H_
+#define QUICHE_QUIC_CORE_TLS_CHLO_EXTRACTOR_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+#include "third_party/boringssl/src/include/openssl/ssl.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_stream_sequencer.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
+
+namespace quic {
+
+// Utility class that allows extracting information from a QUIC-TLS Client
+// Hello. This class creates a QuicFramer to parse the packet, and implements
+// QuicFramerVisitorInterface to access the frames parsed by the QuicFramer. It
+// then uses a QuicStreamSequencer to reassemble the contents of the crypto
+// stream, and implements QuicStreamSequencer::StreamInterface to access the
+// reassembled data.
+class QUIC_NO_EXPORT TlsChloExtractor
+ : public QuicFramerVisitorInterface,
+ public QuicStreamSequencer::StreamInterface {
+ public:
+ TlsChloExtractor();
+ TlsChloExtractor(const TlsChloExtractor&) = delete;
+ TlsChloExtractor(TlsChloExtractor&&);
+ TlsChloExtractor& operator=(const TlsChloExtractor&) = delete;
+ TlsChloExtractor& operator=(TlsChloExtractor&&);
+
+ enum class State : uint8_t {
+ kInitial = 0,
+ kParsedFullSinglePacketChlo = 1,
+ kParsedFullMultiPacketChlo = 2,
+ kParsedPartialChloFragment = 3,
+ kUnrecoverableFailure = 4,
+ };
+
+ State state() const { return state_; }
+ std::vector<std::string> alpns() const { return alpns_; }
+ std::string server_name() const { return server_name_; }
+
+ // Converts |state| to a human-readable string suitable for logging.
+ static std::string StateToString(State state);
+
+ // Ingests |packet| and attempts to parse out the CHLO.
+ void IngestPacket(const ParsedQuicVersion& version,
+ const QuicReceivedPacket& packet);
+
+ // Returns whether the ingested packets have allowed parsing a complete CHLO.
+ bool HasParsedFullChlo() const {
+ return state_ == State::kParsedFullSinglePacketChlo ||
+ state_ == State::kParsedFullMultiPacketChlo;
+ }
+
+ // Methods from QuicFramerVisitorInterface.
+ void OnError(QuicFramer* /*framer*/) override {}
+ bool OnProtocolVersionMismatch(ParsedQuicVersion version) override;
+ void OnPacket() override {}
+ void OnPublicResetPacket(const QuicPublicResetPacket& /*packet*/) override {}
+ void OnVersionNegotiationPacket(
+ const QuicVersionNegotiationPacket& /*packet*/) override {}
+ void OnRetryPacket(QuicConnectionId /*original_connection_id*/,
+ QuicConnectionId /*new_connection_id*/,
+ quiche::QuicheStringPiece /*retry_token*/,
+ quiche::QuicheStringPiece /*retry_integrity_tag*/,
+ quiche::QuicheStringPiece /*retry_without_tag*/) override {
+ }
+ bool OnUnauthenticatedPublicHeader(const QuicPacketHeader& header) override;
+ bool OnUnauthenticatedHeader(const QuicPacketHeader& /*header*/) override {
+ return true;
+ }
+ void OnDecryptedPacket(EncryptionLevel /*level*/) override {}
+ bool OnPacketHeader(const QuicPacketHeader& /*header*/) override {
+ return true;
+ }
+ void OnCoalescedPacket(const QuicEncryptedPacket& /*packet*/) override {}
+ void OnUndecryptablePacket(const QuicEncryptedPacket& /*packet*/,
+ EncryptionLevel /*decryption_level*/,
+ bool /*has_decryption_key*/) override {}
+ bool OnStreamFrame(const QuicStreamFrame& /*frame*/) override { return true; }
+ bool OnCryptoFrame(const QuicCryptoFrame& frame) override;
+ bool OnAckFrameStart(QuicPacketNumber /*largest_acked*/,
+ QuicTime::Delta /*ack_delay_time*/) override {
+ return true;
+ }
+ bool OnAckRange(QuicPacketNumber /*start*/,
+ QuicPacketNumber /*end*/) override {
+ return true;
+ }
+ bool OnAckTimestamp(QuicPacketNumber /*packet_number*/,
+ QuicTime /*timestamp*/) override {
+ return true;
+ }
+ bool OnAckFrameEnd(QuicPacketNumber /*start*/) override { return true; }
+ bool OnStopWaitingFrame(const QuicStopWaitingFrame& /*frame*/) override {
+ return true;
+ }
+ bool OnPingFrame(const QuicPingFrame& /*frame*/) override { return true; }
+ bool OnRstStreamFrame(const QuicRstStreamFrame& /*frame*/) override {
+ return true;
+ }
+ bool OnConnectionCloseFrame(
+ const QuicConnectionCloseFrame& /*frame*/) override {
+ return true;
+ }
+ bool OnNewConnectionIdFrame(
+ const QuicNewConnectionIdFrame& /*frame*/) override {
+ return true;
+ }
+ bool OnRetireConnectionIdFrame(
+ const QuicRetireConnectionIdFrame& /*frame*/) override {
+ return true;
+ }
+ bool OnNewTokenFrame(const QuicNewTokenFrame& /*frame*/) override {
+ return true;
+ }
+ bool OnStopSendingFrame(const QuicStopSendingFrame& /*frame*/) override {
+ return true;
+ }
+ bool OnPathChallengeFrame(const QuicPathChallengeFrame& /*frame*/) override {
+ return true;
+ }
+ bool OnPathResponseFrame(const QuicPathResponseFrame& /*frame*/) override {
+ return true;
+ }
+ bool OnGoAwayFrame(const QuicGoAwayFrame& /*frame*/) override { return true; }
+ bool OnMaxStreamsFrame(const QuicMaxStreamsFrame& /*frame*/) override {
+ return true;
+ }
+ bool OnStreamsBlockedFrame(
+ const QuicStreamsBlockedFrame& /*frame*/) override {
+ return true;
+ }
+ bool OnWindowUpdateFrame(const QuicWindowUpdateFrame& /*frame*/) override {
+ return true;
+ }
+ bool OnBlockedFrame(const QuicBlockedFrame& /*frame*/) override {
+ return true;
+ }
+ bool OnPaddingFrame(const QuicPaddingFrame& /*frame*/) override {
+ return true;
+ }
+ bool OnMessageFrame(const QuicMessageFrame& /*frame*/) override {
+ return true;
+ }
+ bool OnHandshakeDoneFrame(const QuicHandshakeDoneFrame& /*frame*/) override {
+ return true;
+ }
+ void OnPacketComplete() override {}
+ bool IsValidStatelessResetToken(QuicUint128 /*token*/) const override {
+ return true;
+ }
+ void OnAuthenticatedIetfStatelessResetPacket(
+ const QuicIetfStatelessResetPacket& /*packet*/) override {}
+
+ // Methods from QuicStreamSequencer::StreamInterface.
+ void OnDataAvailable() override;
+ void OnFinRead() override {}
+ void AddBytesConsumed(QuicByteCount /*bytes*/) override {}
+ void Reset(QuicRstStreamErrorCode /*error*/) override {}
+ void OnUnrecoverableError(QuicErrorCode error,
+ const std::string& details) override;
+ QuicStreamId id() const override { return 0; }
+
+ private:
+ // Parses the length of the CHLO message by looking at the first four bytes.
+ // Returns whether we have received enough data to parse the full CHLO now.
+ bool MaybeAttemptToParseChloLength();
+ // Parses the full CHLO message if enough data has been received.
+ void AttemptToParseFullChlo();
+ // Moves to the failed state and records the error details.
+ void HandleUnrecoverableError(const std::string& error_details);
+ // Lazily sets up shared SSL handles if needed.
+ static std::pair<SSL_CTX*, int> GetSharedSslHandles();
+ // Lazily sets up the per-instance SSL handle if needed.
+ void SetupSslHandle();
+ // Extract the TlsChloExtractor instance from |ssl|.
+ static TlsChloExtractor* GetInstanceFromSSL(SSL* ssl);
+
+ // BoringSSL static TLS callbacks.
+ static enum ssl_select_cert_result_t SelectCertCallback(
+ const SSL_CLIENT_HELLO* client_hello);
+ static int SetReadSecretCallback(SSL* ssl,
+ enum ssl_encryption_level_t level,
+ const SSL_CIPHER* cipher,
+ const uint8_t* secret,
+ size_t secret_length);
+ static int SetWriteSecretCallback(SSL* ssl,
+ enum ssl_encryption_level_t level,
+ const SSL_CIPHER* cipher,
+ const uint8_t* secret,
+ size_t secret_length);
+ static int WriteMessageCallback(SSL* ssl,
+ enum ssl_encryption_level_t level,
+ const uint8_t* data,
+ size_t len);
+ static int FlushFlightCallback(SSL* ssl);
+ static int SendAlertCallback(SSL* ssl,
+ enum ssl_encryption_level_t level,
+ uint8_t desc);
+
+ // Called by SelectCertCallback.
+ void HandleParsedChlo(const SSL_CLIENT_HELLO* client_hello);
+ // Called by callbacks that should never be called.
+ void HandleUnexpectedCallback(const std::string& callback_name);
+ // Called by SendAlertCallback.
+ void SendAlert(uint8_t tls_alert_value);
+
+ // Used to parse received packets to extract single frames.
+ std::unique_ptr<QuicFramer> framer_;
+ // Used to reassemble the crypto stream from received CRYPTO frames.
+ QuicStreamSequencer crypto_stream_sequencer_;
+ // BoringSSL handle required to parse the CHLO.
+ bssl::UniquePtr<SSL> ssl_;
+ // State of this TlsChloExtractor.
+ State state_;
+ // Detail string that can be logged in the presence of unrecoverable errors.
+ std::string error_details_;
+ // Whether a CRYPTO frame was parsed in this packet.
+ bool parsed_crypto_frame_in_this_packet_;
+ // Array of ALPNs parsed from the CHLO.
+ std::vector<std::string> alpns_;
+ // SNI parsed from the CHLO.
+ std::string server_name_;
+};
+
+// Convenience method to facilitate logging TlsChloExtractor::State.
+QUIC_NO_EXPORT std::ostream& operator<<(std::ostream& os,
+ const TlsChloExtractor::State& state);
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_CORE_TLS_CHLO_EXTRACTOR_H_
diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_chlo_extractor_test.cc b/chromium/net/third_party/quiche/src/quic/core/tls_chlo_extractor_test.cc
new file mode 100644
index 00000000000..ba57ad02bb9
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/tls_chlo_extractor_test.cc
@@ -0,0 +1,157 @@
+// Copyright (c) 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/core/tls_chlo_extractor.h"
+#include <memory>
+
+#include "net/third_party/quiche/src/quic/core/http/quic_spdy_client_session.h"
+#include "net/third_party/quiche/src/quic/core/quic_connection.h"
+#include "net/third_party/quiche/src/quic/core/quic_packet_writer_wrapper.h"
+#include "net/third_party/quiche/src/quic/core/quic_versions.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/first_flight.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
+
+namespace quic {
+namespace test {
+namespace {
+
+class TlsChloExtractorTest : public QuicTestWithParam<ParsedQuicVersion> {
+ protected:
+ TlsChloExtractorTest() : version_(GetParam()) {}
+
+ void Initialize() { packets_ = GetFirstFlightOfPackets(version_, config_); }
+
+ void IngestPackets() {
+ for (const std::unique_ptr<QuicReceivedPacket>& packet : packets_) {
+ ReceivedPacketInfo packet_info(
+ QuicSocketAddress(TestPeerIPAddress(), kTestPort),
+ QuicSocketAddress(TestPeerIPAddress(), kTestPort), *packet);
+ std::string detailed_error;
+ bool retry_token_present;
+ quiche::QuicheStringPiece retry_token;
+ const QuicErrorCode error = QuicFramer::ParsePublicHeaderDispatcher(
+ *packet, /*expected_destination_connection_id_length=*/0,
+ &packet_info.form, &packet_info.long_packet_type,
+ &packet_info.version_flag, &packet_info.use_length_prefix,
+ &packet_info.version_label, &packet_info.version,
+ &packet_info.destination_connection_id,
+ &packet_info.source_connection_id, &retry_token_present, &retry_token,
+ &detailed_error);
+ ASSERT_THAT(error, IsQuicNoError()) << detailed_error;
+ tls_chlo_extractor_.IngestPacket(packet_info.version, packet_info.packet);
+ }
+ packets_.clear();
+ }
+
+ void ValidateChloDetails() {
+ EXPECT_TRUE(tls_chlo_extractor_.HasParsedFullChlo());
+ ASSERT_EQ(tls_chlo_extractor_.alpns().size(), 1u);
+ EXPECT_EQ(tls_chlo_extractor_.alpns()[0], AlpnForVersion(version_));
+ EXPECT_EQ(tls_chlo_extractor_.server_name(), TestHostname());
+ }
+
+ void IncreaseSizeOfChlo() {
+ // Add a 2000-byte custom parameter to increase the length of the CHLO.
+ constexpr auto kCustomParameterId =
+ static_cast<TransportParameters::TransportParameterId>(0xff33);
+ std::string kCustomParameterValue(2000, '-');
+ config_.custom_transport_parameters_to_send()[kCustomParameterId] =
+ kCustomParameterValue;
+ }
+
+ ParsedQuicVersion version_;
+ TlsChloExtractor tls_chlo_extractor_;
+ QuicConfig config_;
+ std::vector<std::unique_ptr<QuicReceivedPacket>> packets_;
+};
+
+INSTANTIATE_TEST_SUITE_P(TlsChloExtractorTests,
+ TlsChloExtractorTest,
+ ::testing::ValuesIn(AllSupportedVersionsWithTls()),
+ ::testing::PrintToStringParamName());
+
+TEST_P(TlsChloExtractorTest, Simple) {
+ Initialize();
+ EXPECT_EQ(packets_.size(), 1u);
+ IngestPackets();
+ ValidateChloDetails();
+ EXPECT_EQ(tls_chlo_extractor_.state(),
+ TlsChloExtractor::State::kParsedFullSinglePacketChlo);
+}
+
+TEST_P(TlsChloExtractorTest, MultiPacket) {
+ IncreaseSizeOfChlo();
+ Initialize();
+ EXPECT_EQ(packets_.size(), 2u);
+ IngestPackets();
+ ValidateChloDetails();
+ EXPECT_EQ(tls_chlo_extractor_.state(),
+ TlsChloExtractor::State::kParsedFullMultiPacketChlo);
+}
+
+TEST_P(TlsChloExtractorTest, MultiPacketReordered) {
+ IncreaseSizeOfChlo();
+ Initialize();
+ ASSERT_EQ(packets_.size(), 2u);
+ // Artifically reorder both packets.
+ std::swap(packets_[0], packets_[1]);
+ IngestPackets();
+ ValidateChloDetails();
+ EXPECT_EQ(tls_chlo_extractor_.state(),
+ TlsChloExtractor::State::kParsedFullMultiPacketChlo);
+}
+
+TEST_P(TlsChloExtractorTest, MoveAssignment) {
+ Initialize();
+ EXPECT_EQ(packets_.size(), 1u);
+ TlsChloExtractor other_extractor;
+ tls_chlo_extractor_ = std::move(other_extractor);
+ IngestPackets();
+ ValidateChloDetails();
+ EXPECT_EQ(tls_chlo_extractor_.state(),
+ TlsChloExtractor::State::kParsedFullSinglePacketChlo);
+}
+
+TEST_P(TlsChloExtractorTest, MoveAssignmentBetweenPackets) {
+ IncreaseSizeOfChlo();
+ Initialize();
+ ASSERT_EQ(packets_.size(), 2u);
+ TlsChloExtractor other_extractor;
+
+ // Have |other_extractor| parse the first packet.
+ ReceivedPacketInfo packet_info(
+ QuicSocketAddress(TestPeerIPAddress(), kTestPort),
+ QuicSocketAddress(TestPeerIPAddress(), kTestPort), *packets_[0]);
+ std::string detailed_error;
+ bool retry_token_present;
+ quiche::QuicheStringPiece retry_token;
+ const QuicErrorCode error = QuicFramer::ParsePublicHeaderDispatcher(
+ *packets_[0], /*expected_destination_connection_id_length=*/0,
+ &packet_info.form, &packet_info.long_packet_type,
+ &packet_info.version_flag, &packet_info.use_length_prefix,
+ &packet_info.version_label, &packet_info.version,
+ &packet_info.destination_connection_id, &packet_info.source_connection_id,
+ &retry_token_present, &retry_token, &detailed_error);
+ ASSERT_THAT(error, IsQuicNoError()) << detailed_error;
+ other_extractor.IngestPacket(packet_info.version, packet_info.packet);
+ // Remove the first packet from the list.
+ packets_.erase(packets_.begin());
+ EXPECT_EQ(packets_.size(), 1u);
+
+ // Move the extractor.
+ tls_chlo_extractor_ = std::move(other_extractor);
+
+ // Have |tls_chlo_extractor_| parse the second packet.
+ IngestPackets();
+
+ ValidateChloDetails();
+ EXPECT_EQ(tls_chlo_extractor_.state(),
+ TlsChloExtractor::State::kParsedFullMultiPacketChlo);
+}
+
+} // namespace
+} // namespace test
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.cc b/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.cc
index 5148e71caf5..d4e8ed023b1 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
@@ -8,9 +8,12 @@
#include <string>
#include "third_party/boringssl/src/include/openssl/ssl.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_encrypter.h"
#include "net/third_party/quiche/src/quic/core/crypto/transport_parameters.h"
#include "net/third_party/quiche/src/quic/core/quic_session.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_hostname_utils.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_text_utils.h"
@@ -34,8 +37,10 @@ void TlsClientHandshaker::ProofVerifierCallbackImpl::Run(
parent_->verify_result_ = ok ? ssl_verify_ok : ssl_verify_invalid;
parent_->state_ = STATE_HANDSHAKE_RUNNING;
parent_->proof_verify_callback_ = nullptr;
- parent_->proof_handler_->OnProofVerifyDetailsAvailable(
- *parent_->verify_details_);
+ if (parent_->verify_details_) {
+ parent_->proof_handler_->OnProofVerifyDetailsAvailable(
+ *parent_->verify_details_);
+ }
parent_->AdvanceHandshake();
}
@@ -49,7 +54,8 @@ TlsClientHandshaker::TlsClientHandshaker(
QuicSession* session,
std::unique_ptr<ProofVerifyContext> verify_context,
QuicCryptoClientConfig* crypto_config,
- QuicCryptoClientStream::ProofHandler* proof_handler)
+ QuicCryptoClientStream::ProofHandler* proof_handler,
+ bool has_application_state)
: TlsHandshaker(stream, session),
session_(session),
server_id_(server_id),
@@ -58,7 +64,9 @@ TlsClientHandshaker::TlsClientHandshaker(
proof_handler_(proof_handler),
session_cache_(crypto_config->session_cache()),
user_agent_id_(crypto_config->user_agent_id()),
+ pre_shared_key_(crypto_config->pre_shared_key()),
crypto_negotiated_params_(new QuicCryptoNegotiatedParameters),
+ has_application_state_(has_application_state),
tls_connection_(crypto_config->ssl_ctx(), this) {}
TlsClientHandshaker::~TlsClientHandshaker() {
@@ -70,9 +78,25 @@ TlsClientHandshaker::~TlsClientHandshaker() {
bool TlsClientHandshaker::CryptoConnect() {
state_ = STATE_HANDSHAKE_RUNNING;
+ if (!pre_shared_key_.empty()) {
+ // TODO(b/154162689) add PSK support to QUIC+TLS.
+ std::string error_details =
+ "QUIC client pre-shared keys not yet supported with TLS";
+ QUIC_BUG << error_details;
+ CloseConnection(QUIC_HANDSHAKE_FAILED, error_details);
+ return false;
+ }
+
// Set the SNI to send, if any.
SSL_set_connect_state(ssl());
+ if (QUIC_DLOG_INFO_IS_ON() &&
+ !QuicHostnameUtils::IsValidSNI(server_id_.host())) {
+ QUIC_DLOG(INFO) << "Client configured with invalid hostname \""
+ << server_id_.host() << "\", not sending as SNI";
+ }
if (!server_id_.host().empty() &&
+ (QuicHostnameUtils::IsValidSNI(server_id_.host()) ||
+ allow_invalid_sni_for_tests_) &&
SSL_set_tlsext_host_name(ssl(), server_id_.host().c_str()) != 1) {
return false;
}
@@ -95,6 +119,13 @@ bool TlsClientHandshaker::CryptoConnect() {
session_cache_->Lookup(server_id_, SSL_get_SSL_CTX(ssl()));
if (cached_state) {
SSL_set_session(ssl(), cached_state->tls_session.get());
+ if (GetQuicReloadableFlag(quic_enable_zero_rtt_for_tls) &&
+ VersionHasIetfQuicFrames(session()->transport_version()) &&
+ SSL_SESSION_early_data_capable(cached_state->tls_session.get())) {
+ if (!PrepareZeroRttConfig(cached_state.get())) {
+ return false;
+ }
+ }
}
}
@@ -103,6 +134,30 @@ bool TlsClientHandshaker::CryptoConnect() {
return session()->connection()->connected();
}
+bool TlsClientHandshaker::PrepareZeroRttConfig(
+ QuicResumptionState* cached_state) {
+ std::string error_details;
+ if (session()->config()->ProcessTransportParameters(
+ *(cached_state->transport_params), SERVER,
+ /*is_resumption = */ true, &error_details) != QUIC_NO_ERROR) {
+ QUIC_BUG << "Unable to parse cached transport parameters.";
+ CloseConnection(QUIC_HANDSHAKE_FAILED,
+ "Client failed to parse cached Transport Parameters.");
+ return false;
+ }
+ session()->OnConfigNegotiated();
+
+ if (has_application_state_) {
+ if (!session()->SetApplicationState(cached_state->application_state)) {
+ QUIC_BUG << "Unable to parse cached application state.";
+ CloseConnection(QUIC_HANDSHAKE_FAILED,
+ "Client failed to parse cached application state.");
+ return false;
+ }
+ }
+ return true;
+}
+
static bool IsValidAlpn(const std::string& alpn_string) {
return alpn_string.length() <= std::numeric_limits<uint8_t>::max();
}
@@ -152,7 +207,14 @@ bool TlsClientHandshaker::SetTransportParameters() {
if (!session()->config()->FillTransportParameters(&params)) {
return false;
}
- params.google_quic_params->SetStringPiece(kUAID, user_agent_id_);
+ if (GetQuicRestartFlag(quic_google_transport_param_send_new)) {
+ if (!user_agent_id_.empty()) {
+ params.user_agent_id = user_agent_id_;
+ }
+ }
+ if (!GetQuicRestartFlag(quic_google_transport_param_omit_old)) {
+ params.google_quic_params->SetStringPiece(kUAID, user_agent_id_);
+ }
std::vector<uint8_t> param_bytes;
return SerializeTransportParameters(session()->connection()->version(),
@@ -163,7 +225,7 @@ bool TlsClientHandshaker::SetTransportParameters() {
bool TlsClientHandshaker::ProcessTransportParameters(
std::string* error_details) {
- TransportParameters params;
+ received_transport_params_ = std::make_unique<TransportParameters>();
const uint8_t* param_bytes;
size_t param_bytes_len;
SSL_get_peer_quic_transport_params(ssl(), &param_bytes, &param_bytes_len);
@@ -174,7 +236,8 @@ bool TlsClientHandshaker::ProcessTransportParameters(
std::string parse_error_details;
if (!ParseTransportParameters(
session()->connection()->version(), Perspective::IS_SERVER,
- param_bytes, param_bytes_len, &params, &parse_error_details)) {
+ param_bytes, param_bytes_len, received_transport_params_.get(),
+ &parse_error_details)) {
DCHECK(!parse_error_details.empty());
*error_details =
"Unable to parse server's transport parameters: " + parse_error_details;
@@ -183,29 +246,37 @@ bool TlsClientHandshaker::ProcessTransportParameters(
// When interoperating with non-Google implementations that do not send
// the version extension, set it to what we expect.
- if (params.version == 0) {
- params.version = CreateQuicVersionLabel(session()->connection()->version());
+ if (received_transport_params_->version == 0) {
+ received_transport_params_->version =
+ CreateQuicVersionLabel(session()->connection()->version());
}
- if (params.supported_versions.empty()) {
- params.supported_versions.push_back(params.version);
+ if (received_transport_params_->supported_versions.empty()) {
+ received_transport_params_->supported_versions.push_back(
+ received_transport_params_->version);
}
- if (params.version !=
+ if (received_transport_params_->version !=
CreateQuicVersionLabel(session()->connection()->version())) {
*error_details = "Version mismatch detected";
return false;
}
if (CryptoUtils::ValidateServerHelloVersions(
- params.supported_versions,
+ received_transport_params_->supported_versions,
session()->connection()->server_supported_versions(),
error_details) != QUIC_NO_ERROR ||
session()->config()->ProcessTransportParameters(
- params, SERVER, error_details) != QUIC_NO_ERROR) {
+ *received_transport_params_, SERVER, /* is_resumption = */ false,
+ error_details) != QUIC_NO_ERROR) {
DCHECK(!error_details->empty());
return false;
}
session()->OnConfigNegotiated();
+ if (state_ == STATE_CONNECTION_CLOSED) {
+ *error_details =
+ "Session closed the connection when parsing negotiated config.";
+ return false;
+ }
return true;
}
@@ -277,6 +348,20 @@ void TlsClientHandshaker::OnOneRttPacketAcknowledged() {
OnHandshakeConfirmed();
}
+void TlsClientHandshaker::OnHandshakePacketSent() {
+ if (initial_keys_dropped_) {
+ return;
+ }
+ initial_keys_dropped_ = true;
+ handshaker_delegate()->DiscardOldEncryptionKey(ENCRYPTION_INITIAL);
+ handshaker_delegate()->DiscardOldDecryptionKey(ENCRYPTION_INITIAL);
+}
+
+void TlsClientHandshaker::OnConnectionClosed(QuicErrorCode /*error*/,
+ ConnectionCloseSource /*source*/) {
+ state_ = STATE_CONNECTION_CLOSED;
+}
+
void TlsClientHandshaker::OnHandshakeDoneReceived() {
if (!one_rtt_keys_available_) {
CloseConnection(QUIC_HANDSHAKE_FAILED,
@@ -290,8 +375,10 @@ void TlsClientHandshaker::SetWriteSecret(
EncryptionLevel level,
const SSL_CIPHER* cipher,
const std::vector<uint8_t>& write_secret) {
- if (GetQuicRestartFlag(quic_send_settings_on_write_key_available) &&
- level == ENCRYPTION_FORWARD_SECURE) {
+ if (state_ == STATE_CONNECTION_CLOSED) {
+ return;
+ }
+ if (level == ENCRYPTION_FORWARD_SECURE) {
encryption_established_ = true;
}
TlsHandshaker::SetWriteSecret(level, cipher, write_secret);
@@ -335,6 +422,7 @@ void TlsClientHandshaker::AdvanceHandshake() {
int ssl_error = SSL_get_error(ssl(), rv);
bool should_close = true;
switch (state_) {
+ // TODO(b/153726130): handle the case where the server rejects early data.
case STATE_HANDSHAKE_RUNNING:
should_close = ssl_error != SSL_ERROR_WANT_READ;
break;
@@ -363,16 +451,14 @@ void TlsClientHandshaker::CloseConnection(QuicErrorCode error,
void TlsClientHandshaker::FinishHandshake() {
QUIC_LOG(INFO) << "Client: handshake finished";
state_ = STATE_HANDSHAKE_COMPLETE;
- if (GetQuicRestartFlag(quic_send_settings_on_write_key_available)) {
- // Fill crypto_negotiated_params_:
- const SSL_CIPHER* cipher = SSL_get_current_cipher(ssl());
- if (cipher) {
- crypto_negotiated_params_->cipher_suite = SSL_CIPHER_get_value(cipher);
- }
- crypto_negotiated_params_->key_exchange_group = SSL_get_curve_id(ssl());
- crypto_negotiated_params_->peer_signature_algorithm =
- SSL_get_peer_signature_algorithm(ssl());
+ // Fill crypto_negotiated_params_:
+ const SSL_CIPHER* cipher = SSL_get_current_cipher(ssl());
+ if (cipher) {
+ crypto_negotiated_params_->cipher_suite = SSL_CIPHER_get_value(cipher);
}
+ crypto_negotiated_params_->key_exchange_group = SSL_get_curve_id(ssl());
+ crypto_negotiated_params_->peer_signature_algorithm =
+ SSL_get_peer_signature_algorithm(ssl());
std::string error_details;
if (!ProcessTransportParameters(&error_details)) {
@@ -408,23 +494,7 @@ void TlsClientHandshaker::FinishHandshake() {
session()->OnAlpnSelected(received_alpn_string);
QUIC_DLOG(INFO) << "Client: server selected ALPN: '" << received_alpn_string
<< "'";
-
- if (!GetQuicRestartFlag(quic_send_settings_on_write_key_available)) {
- encryption_established_ = true;
- }
one_rtt_keys_available_ = true;
-
- if (!GetQuicRestartFlag(quic_send_settings_on_write_key_available)) {
- // Fill crypto_negotiated_params_:
- const SSL_CIPHER* cipher = SSL_get_current_cipher(ssl());
- if (cipher) {
- crypto_negotiated_params_->cipher_suite = SSL_CIPHER_get_value(cipher);
- }
- crypto_negotiated_params_->key_exchange_group = SSL_get_curve_id(ssl());
- crypto_negotiated_params_->peer_signature_algorithm =
- SSL_get_peer_signature_algorithm(ssl());
- }
-
handshaker_delegate()->OnOneRttKeysAvailable();
}
@@ -462,12 +532,14 @@ enum ssl_verify_result_t TlsClientHandshaker::VerifyCert(uint8_t* out_alert) {
new ProofVerifierCallbackImpl(this);
QuicAsyncStatus verify_result = proof_verifier_->VerifyCertChain(
- server_id_.host(), certs, ocsp_response, sct_list, verify_context_.get(),
- &cert_verify_error_details_, &verify_details_,
+ server_id_.host(), server_id_.port(), certs, ocsp_response, sct_list,
+ verify_context_.get(), &cert_verify_error_details_, &verify_details_,
std::unique_ptr<ProofVerifierCallback>(proof_verify_callback));
switch (verify_result) {
case QUIC_SUCCESS:
- proof_handler_->OnProofVerifyDetailsAvailable(*verify_details_);
+ if (verify_details_) {
+ proof_handler_->OnProofVerifyDetailsAvailable(*verify_details_);
+ }
return ssl_verify_ok;
case QUIC_PENDING:
proof_verify_callback_ = proof_verify_callback;
@@ -482,13 +554,25 @@ enum ssl_verify_result_t TlsClientHandshaker::VerifyCert(uint8_t* out_alert) {
}
void TlsClientHandshaker::InsertSession(bssl::UniquePtr<SSL_SESSION> session) {
+ if (!received_transport_params_) {
+ QUIC_BUG << "Transport parameters isn't received";
+ return;
+ }
if (session_cache_ == nullptr) {
QUIC_DVLOG(1) << "No session cache, not inserting a session";
return;
}
- auto cache_state = std::make_unique<QuicResumptionState>();
- cache_state->tls_session = std::move(session);
- session_cache_->Insert(server_id_, std::move(cache_state));
+ if (has_application_state_ && !received_application_state_) {
+ // Application state is not received yet. cache the sessions.
+ if (cached_tls_sessions_[0] != nullptr) {
+ cached_tls_sessions_[1] = std::move(cached_tls_sessions_[0]);
+ }
+ cached_tls_sessions_[0] = std::move(session);
+ return;
+ }
+ session_cache_->Insert(server_id_, std::move(session),
+ *received_transport_params_,
+ received_application_state_.get());
}
void TlsClientHandshaker::WriteMessage(EncryptionLevel level,
@@ -496,10 +580,27 @@ void TlsClientHandshaker::WriteMessage(EncryptionLevel level,
if (level == ENCRYPTION_HANDSHAKE &&
state_ < STATE_ENCRYPTION_HANDSHAKE_DATA_SENT) {
state_ = STATE_ENCRYPTION_HANDSHAKE_DATA_SENT;
- handshaker_delegate()->DiscardOldEncryptionKey(ENCRYPTION_INITIAL);
- handshaker_delegate()->DiscardOldDecryptionKey(ENCRYPTION_INITIAL);
}
TlsHandshaker::WriteMessage(level, data);
}
+void TlsClientHandshaker::OnApplicationState(
+ std::unique_ptr<ApplicationState> application_state) {
+ DCHECK_EQ(STATE_HANDSHAKE_COMPLETE, state_);
+ received_application_state_ = std::move(application_state);
+ // At least one tls session is cached before application state is received. So
+ // insert now.
+ if (session_cache_ != nullptr && cached_tls_sessions_[0] != nullptr) {
+ if (cached_tls_sessions_[1] != nullptr) {
+ // Insert the older session first.
+ session_cache_->Insert(server_id_, std::move(cached_tls_sessions_[1]),
+ *received_transport_params_,
+ received_application_state_.get());
+ }
+ session_cache_->Insert(server_id_, std::move(cached_tls_sessions_[0]),
+ *received_transport_params_,
+ received_application_state_.get());
+ }
+}
+
} // 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 d9ee7608f6f..cc601219dfa 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
@@ -5,11 +5,15 @@
#ifndef QUICHE_QUIC_CORE_TLS_CLIENT_HANDSHAKER_H_
#define QUICHE_QUIC_CORE_TLS_CLIENT_HANDSHAKER_H_
+#include <cstdint>
+#include <memory>
#include <string>
#include "third_party/boringssl/src/include/openssl/ssl.h"
#include "net/third_party/quiche/src/quic/core/crypto/proof_verifier.h"
+#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.h"
#include "net/third_party/quiche/src/quic/core/crypto/tls_client_connection.h"
+#include "net/third_party/quiche/src/quic/core/crypto/transport_parameters.h"
#include "net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h"
#include "net/third_party/quiche/src/quic/core/quic_crypto_stream.h"
#include "net/third_party/quiche/src/quic/core/tls_handshaker.h"
@@ -30,7 +34,8 @@ class QUIC_EXPORT_PRIVATE TlsClientHandshaker
QuicSession* session,
std::unique_ptr<ProofVerifyContext> verify_context,
QuicCryptoClientConfig* crypto_config,
- QuicCryptoClientStream::ProofHandler* proof_handler);
+ QuicCryptoClientStream::ProofHandler* proof_handler,
+ bool has_application_state);
TlsClientHandshaker(const TlsClientHandshaker&) = delete;
TlsClientHandshaker& operator=(const TlsClientHandshaker&) = delete;
@@ -54,6 +59,9 @@ class QUIC_EXPORT_PRIVATE TlsClientHandshaker
HandshakeState GetHandshakeState() const override;
size_t BufferSizeLimitForLevel(EncryptionLevel level) const override;
void OnOneRttPacketAcknowledged() override;
+ void OnHandshakePacketSent() override;
+ void OnConnectionClosed(QuicErrorCode error,
+ ConnectionCloseSource source) override;
void OnHandshakeDoneReceived() override;
void SetWriteSecret(EncryptionLevel level,
const SSL_CIPHER* cipher,
@@ -63,7 +71,11 @@ class QUIC_EXPORT_PRIVATE TlsClientHandshaker
void WriteMessage(EncryptionLevel level,
quiche::QuicheStringPiece data) override;
+ void OnApplicationState(
+ std::unique_ptr<ApplicationState> application_state) override;
+
void AllowEmptyAlpnForTests() { allow_empty_alpn_for_tests_ = true; }
+ void AllowInvalidSNIForTests() { allow_invalid_sni_for_tests_ = true; }
protected:
const TlsConnection* tls_connection() const override {
@@ -119,6 +131,8 @@ class QUIC_EXPORT_PRIVATE TlsClientHandshaker
void InsertSession(bssl::UniquePtr<SSL_SESSION> session) override;
+ bool PrepareZeroRttConfig(QuicResumptionState* cached_state);
+
QuicSession* session() { return session_; }
QuicSession* session_;
@@ -140,6 +154,9 @@ class QUIC_EXPORT_PRIVATE TlsClientHandshaker
std::string user_agent_id_;
+ // Pre-shared key used during the handshake.
+ std::string pre_shared_key_;
+
// ProofVerifierCallback used for async certificate verification. This object
// is owned by |proof_verifier_|.
ProofVerifierCallbackImpl* proof_verify_callback_ = nullptr;
@@ -148,14 +165,25 @@ class QUIC_EXPORT_PRIVATE TlsClientHandshaker
std::string cert_verify_error_details_;
bool encryption_established_ = false;
+ bool initial_keys_dropped_ = false;
bool one_rtt_keys_available_ = false;
bool handshake_confirmed_ = false;
QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters>
crypto_negotiated_params_;
bool allow_empty_alpn_for_tests_ = false;
+ bool allow_invalid_sni_for_tests_ = false;
+
+ const bool has_application_state_;
TlsClientConnection tls_connection_;
+
+ // If |has_application_state_|, stores the tls session tickets before
+ // application state is received. The latest one is put in the front.
+ bssl::UniquePtr<SSL_SESSION> cached_tls_sessions_[2] = {};
+
+ std::unique_ptr<TransportParameters> received_transport_params_ = nullptr;
+ std::unique_ptr<ApplicationState> received_application_state_ = nullptr;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker_test.cc b/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker_test.cc
new file mode 100644
index 00000000000..68c413fbb63
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker_test.cc
@@ -0,0 +1,455 @@
+// 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 <memory>
+#include <string>
+#include <utility>
+
+#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_packets.h"
+#include "net/third_party/quiche/src/quic/core/quic_server_id.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_flags.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/quic_session_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_session_cache.h"
+#include "net/third_party/quiche/src/quic/tools/fake_proof_verifier.h"
+#include "net/third_party/quiche/src/common/platform/api/quiche_arraysize.h"
+#include "net/third_party/quiche/src/common/test_tools/quiche_test_utils.h"
+
+using testing::_;
+
+namespace quic {
+namespace test {
+namespace {
+
+constexpr char kServerHostname[] = "test.example.com";
+constexpr uint16_t kServerPort = 443;
+
+// TestProofVerifier wraps ProofVerifierForTesting, except for VerifyCertChain
+// which, if TestProofVerifier is active, always returns QUIC_PENDING. (If this
+// test proof verifier is not active, it delegates VerifyCertChain to the
+// ProofVerifierForTesting.) The pending VerifyCertChain operation can be
+// completed by calling InvokePendingCallback. This allows for testing
+// asynchronous VerifyCertChain operations.
+class TestProofVerifier : public ProofVerifier {
+ public:
+ TestProofVerifier()
+ : verifier_(crypto_test_utils::ProofVerifierForTesting()) {}
+
+ QuicAsyncStatus VerifyProof(
+ const std::string& hostname,
+ const uint16_t port,
+ const std::string& server_config,
+ QuicTransportVersion quic_version,
+ quiche::QuicheStringPiece chlo_hash,
+ const std::vector<std::string>& certs,
+ const std::string& cert_sct,
+ const std::string& signature,
+ const ProofVerifyContext* context,
+ std::string* error_details,
+ std::unique_ptr<ProofVerifyDetails>* details,
+ std::unique_ptr<ProofVerifierCallback> callback) override {
+ return verifier_->VerifyProof(
+ hostname, port, server_config, quic_version, chlo_hash, certs, cert_sct,
+ signature, context, error_details, details, std::move(callback));
+ }
+
+ QuicAsyncStatus VerifyCertChain(
+ const std::string& hostname,
+ const uint16_t port,
+ const std::vector<std::string>& certs,
+ const std::string& ocsp_response,
+ const std::string& cert_sct,
+ const ProofVerifyContext* context,
+ std::string* error_details,
+ std::unique_ptr<ProofVerifyDetails>* details,
+ std::unique_ptr<ProofVerifierCallback> callback) override {
+ if (!active_) {
+ return verifier_->VerifyCertChain(hostname, port, certs, ocsp_response,
+ cert_sct, context, error_details,
+ details, std::move(callback));
+ }
+ pending_ops_.push_back(std::make_unique<VerifyChainPendingOp>(
+ hostname, port, certs, ocsp_response, cert_sct, context, error_details,
+ details, std::move(callback), verifier_.get()));
+ return QUIC_PENDING;
+ }
+
+ std::unique_ptr<ProofVerifyContext> CreateDefaultContext() override {
+ return nullptr;
+ }
+
+ void Activate() { active_ = true; }
+
+ size_t NumPendingCallbacks() const { return pending_ops_.size(); }
+
+ void InvokePendingCallback(size_t n) {
+ ASSERT_GT(NumPendingCallbacks(), n);
+ pending_ops_[n]->Run();
+ auto it = pending_ops_.begin() + n;
+ pending_ops_.erase(it);
+ }
+
+ private:
+ // Implementation of ProofVerifierCallback that fails if the callback is ever
+ // run.
+ class FailingProofVerifierCallback : public ProofVerifierCallback {
+ public:
+ void Run(bool /*ok*/,
+ const std::string& /*error_details*/,
+ std::unique_ptr<ProofVerifyDetails>* /*details*/) override {
+ FAIL();
+ }
+ };
+
+ class VerifyChainPendingOp {
+ public:
+ VerifyChainPendingOp(const std::string& hostname,
+ const uint16_t port,
+ const std::vector<std::string>& certs,
+ const std::string& ocsp_response,
+ const std::string& cert_sct,
+ const ProofVerifyContext* context,
+ std::string* error_details,
+ std::unique_ptr<ProofVerifyDetails>* details,
+ std::unique_ptr<ProofVerifierCallback> callback,
+ ProofVerifier* delegate)
+ : hostname_(hostname),
+ port_(port),
+ certs_(certs),
+ ocsp_response_(ocsp_response),
+ cert_sct_(cert_sct),
+ context_(context),
+ error_details_(error_details),
+ details_(details),
+ callback_(std::move(callback)),
+ delegate_(delegate) {}
+
+ void Run() {
+ // TestProofVerifier depends on crypto_test_utils::ProofVerifierForTesting
+ // running synchronously. It passes a FailingProofVerifierCallback and
+ // runs the original callback after asserting that the verification ran
+ // synchronously.
+ QuicAsyncStatus status = delegate_->VerifyCertChain(
+ hostname_, port_, certs_, ocsp_response_, cert_sct_, context_,
+ error_details_, details_,
+ std::make_unique<FailingProofVerifierCallback>());
+ ASSERT_NE(status, QUIC_PENDING);
+ callback_->Run(status == QUIC_SUCCESS, *error_details_, details_);
+ }
+
+ private:
+ std::string hostname_;
+ const uint16_t port_;
+ std::vector<std::string> certs_;
+ std::string ocsp_response_;
+ std::string cert_sct_;
+ const ProofVerifyContext* context_;
+ std::string* error_details_;
+ std::unique_ptr<ProofVerifyDetails>* details_;
+ std::unique_ptr<ProofVerifierCallback> callback_;
+ ProofVerifier* delegate_;
+ };
+
+ std::unique_ptr<ProofVerifier> verifier_;
+ bool active_ = false;
+ std::vector<std::unique_ptr<VerifyChainPendingOp>> pending_ops_;
+};
+
+class TlsClientHandshakerTest : public QuicTestWithParam<ParsedQuicVersion> {
+ public:
+ TlsClientHandshakerTest()
+ : supported_versions_({GetParam()}),
+ server_id_(kServerHostname, kServerPort, false),
+ crypto_config_(std::make_unique<QuicCryptoClientConfig>(
+ std::make_unique<TestProofVerifier>(),
+ std::make_unique<test::SimpleSessionCache>())),
+ server_compressed_certs_cache_(
+ QuicCompressedCertsCache::kQuicCompressedCertsCacheSize) {
+ SetQuicReloadableFlag(quic_enable_tls_resumption, true);
+ SetQuicReloadableFlag(quic_enable_zero_rtt_for_tls, true);
+ server_crypto_config_ = crypto_test_utils::CryptoServerConfigForTesting();
+ CreateConnection();
+ }
+
+ void CreateSession() {
+ session_ = std::make_unique<TestQuicSpdyClientSession>(
+ connection_, DefaultQuicConfig(), supported_versions_, server_id_,
+ crypto_config_.get());
+ EXPECT_CALL(*session_, GetAlpnsToOffer())
+ .WillRepeatedly(testing::Return(std::vector<std::string>(
+ {AlpnForVersion(connection_->version())})));
+ }
+
+ void CreateConnection() {
+ connection_ =
+ new PacketSavingConnection(&client_helper_, &alarm_factory_,
+ Perspective::IS_CLIENT, supported_versions_);
+ // Advance the time, because timers do not like uninitialized times.
+ connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
+ CreateSession();
+ }
+
+ void CompleteCryptoHandshake() {
+ EXPECT_CALL(*connection_, SendCryptoData(_, _, _))
+ .Times(testing::AnyNumber());
+ stream()->CryptoConnect();
+ QuicConfig config;
+ crypto_test_utils::HandshakeWithFakeServer(
+ &config, server_crypto_config_.get(), &server_helper_, &alarm_factory_,
+ connection_, stream(), AlpnForVersion(connection_->version()));
+ }
+
+ QuicCryptoClientStream* stream() {
+ return session_->GetMutableCryptoStream();
+ }
+
+ QuicCryptoServerStreamBase* server_stream() {
+ return server_session_->GetMutableCryptoStream();
+ }
+
+ // Initializes a fake server, and all its associated state, for testing.
+ void InitializeFakeServer() {
+ TestQuicSpdyServerSession* server_session = nullptr;
+ CreateServerSessionForTest(
+ server_id_, QuicTime::Delta::FromSeconds(100000), supported_versions_,
+ &server_helper_, &alarm_factory_, server_crypto_config_.get(),
+ &server_compressed_certs_cache_, &server_connection_, &server_session);
+ server_session_.reset(server_session);
+ std::string alpn = AlpnForVersion(connection_->version());
+ EXPECT_CALL(*server_session_, SelectAlpn(_))
+ .WillRepeatedly(
+ [alpn](const std::vector<quiche::QuicheStringPiece>& alpns) {
+ return std::find(alpns.cbegin(), alpns.cend(), alpn);
+ });
+ }
+
+ MockQuicConnectionHelper server_helper_;
+ MockQuicConnectionHelper client_helper_;
+ MockAlarmFactory alarm_factory_;
+ PacketSavingConnection* connection_;
+ ParsedQuicVersionVector supported_versions_;
+ std::unique_ptr<TestQuicSpdyClientSession> session_;
+ QuicServerId server_id_;
+ CryptoHandshakeMessage message_;
+ std::unique_ptr<QuicCryptoClientConfig> crypto_config_;
+
+ // Server state.
+ std::unique_ptr<QuicCryptoServerConfig> server_crypto_config_;
+ PacketSavingConnection* server_connection_;
+ std::unique_ptr<TestQuicSpdyServerSession> server_session_;
+ QuicCompressedCertsCache server_compressed_certs_cache_;
+};
+
+INSTANTIATE_TEST_SUITE_P(TlsHandshakerTests,
+ TlsClientHandshakerTest,
+ ::testing::ValuesIn(AllSupportedVersionsWithTls()),
+ ::testing::PrintToStringParamName());
+
+TEST_P(TlsClientHandshakerTest, NotInitiallyConnected) {
+ EXPECT_FALSE(stream()->encryption_established());
+ EXPECT_FALSE(stream()->one_rtt_keys_available());
+}
+
+TEST_P(TlsClientHandshakerTest, ConnectedAfterHandshake) {
+ CompleteCryptoHandshake();
+ EXPECT_EQ(PROTOCOL_TLS1_3, stream()->handshake_protocol());
+ EXPECT_TRUE(stream()->encryption_established());
+ EXPECT_TRUE(stream()->one_rtt_keys_available());
+ EXPECT_FALSE(stream()->IsResumption());
+}
+
+TEST_P(TlsClientHandshakerTest, ConnectionClosedOnTlsError) {
+ // Have client send ClientHello.
+ stream()->CryptoConnect();
+ EXPECT_CALL(*connection_, CloseConnection(QUIC_HANDSHAKE_FAILED, _, _));
+
+ // Send a zero-length ServerHello from server to client.
+ char bogus_handshake_message[] = {
+ // Handshake struct (RFC 8446 appendix B.3)
+ 2, // HandshakeType server_hello
+ 0, 0, 0, // uint24 length
+ };
+ stream()->crypto_message_parser()->ProcessInput(
+ quiche::QuicheStringPiece(bogus_handshake_message,
+ QUICHE_ARRAYSIZE(bogus_handshake_message)),
+ ENCRYPTION_INITIAL);
+
+ EXPECT_FALSE(stream()->one_rtt_keys_available());
+}
+
+TEST_P(TlsClientHandshakerTest, ProofVerifyDetailsAvailableAfterHandshake) {
+ EXPECT_CALL(*session_, OnProofVerifyDetailsAvailable(testing::_));
+ stream()->CryptoConnect();
+ QuicConfig config;
+ crypto_test_utils::HandshakeWithFakeServer(
+ &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()->one_rtt_keys_available());
+}
+
+TEST_P(TlsClientHandshakerTest, HandshakeWithAsyncProofVerifier) {
+ InitializeFakeServer();
+
+ // Enable TestProofVerifier to capture call to VerifyCertChain and run it
+ // asynchronously.
+ TestProofVerifier* proof_verifier =
+ static_cast<TestProofVerifier*>(crypto_config_->proof_verifier());
+ proof_verifier->Activate();
+
+ stream()->CryptoConnect();
+ // Exchange handshake messages.
+ std::pair<size_t, size_t> moved_message_counts =
+ crypto_test_utils::AdvanceHandshake(
+ connection_, stream(), 0, server_connection_, server_stream(), 0);
+
+ ASSERT_EQ(proof_verifier->NumPendingCallbacks(), 1u);
+ proof_verifier->InvokePendingCallback(0);
+
+ // Exchange more handshake messages.
+ crypto_test_utils::AdvanceHandshake(
+ connection_, stream(), moved_message_counts.first, server_connection_,
+ server_stream(), moved_message_counts.second);
+
+ EXPECT_TRUE(stream()->encryption_established());
+ EXPECT_TRUE(stream()->one_rtt_keys_available());
+}
+
+TEST_P(TlsClientHandshakerTest, Resumption) {
+ // Finish establishing the first connection:
+ CompleteCryptoHandshake();
+
+ EXPECT_EQ(PROTOCOL_TLS1_3, stream()->handshake_protocol());
+ EXPECT_TRUE(stream()->encryption_established());
+ EXPECT_TRUE(stream()->one_rtt_keys_available());
+ 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()->one_rtt_keys_available());
+ EXPECT_TRUE(stream()->IsResumption());
+}
+
+TEST_P(TlsClientHandshakerTest, ClientSendsNoSNI) {
+ // Reconfigure client to sent an empty server hostname. The crypto config also
+ // needs to be recreated to use a FakeProofVerifier since the server's cert
+ // won't match the empty hostname.
+ server_id_ = QuicServerId("", 443);
+ crypto_config_.reset(new QuicCryptoClientConfig(
+ std::make_unique<FakeProofVerifier>(), nullptr));
+ CreateConnection();
+ InitializeFakeServer();
+
+ stream()->CryptoConnect();
+ crypto_test_utils::CommunicateHandshakeMessages(
+ connection_, stream(), server_connection_, server_stream());
+
+ EXPECT_EQ(PROTOCOL_TLS1_3, stream()->handshake_protocol());
+ EXPECT_TRUE(stream()->encryption_established());
+ EXPECT_TRUE(stream()->one_rtt_keys_available());
+
+ EXPECT_EQ(server_stream()->crypto_negotiated_params().sni, "");
+}
+
+TEST_P(TlsClientHandshakerTest, ClientSendingTooManyALPNs) {
+ std::string long_alpn(250, 'A');
+ EXPECT_CALL(*session_, GetAlpnsToOffer())
+ .WillOnce(testing::Return(std::vector<std::string>({
+ long_alpn + "1",
+ long_alpn + "2",
+ long_alpn + "3",
+ long_alpn + "4",
+ long_alpn + "5",
+ long_alpn + "6",
+ long_alpn + "7",
+ long_alpn + "8",
+ })));
+ EXPECT_QUIC_BUG(stream()->CryptoConnect(), "Failed to set ALPN");
+}
+
+TEST_P(TlsClientHandshakerTest, ServerRequiresCustomALPN) {
+ InitializeFakeServer();
+ const std::string kTestAlpn = "An ALPN That Client Did Not Offer";
+ EXPECT_CALL(*server_session_, SelectAlpn(_))
+ .WillOnce(
+ [kTestAlpn](const std::vector<quiche::QuicheStringPiece>& alpns) {
+ return std::find(alpns.cbegin(), alpns.cend(), kTestAlpn);
+ });
+ EXPECT_CALL(*connection_, CloseConnection(QUIC_HANDSHAKE_FAILED,
+ "Server did not select ALPN", _));
+ stream()->CryptoConnect();
+ crypto_test_utils::AdvanceHandshake(connection_, stream(), 0,
+ server_connection_, server_stream(), 0);
+
+ EXPECT_FALSE(stream()->one_rtt_keys_available());
+ EXPECT_TRUE(stream()->encryption_established());
+ EXPECT_FALSE(server_stream()->one_rtt_keys_available());
+ EXPECT_TRUE(server_stream()->encryption_established());
+}
+
+TEST_P(TlsClientHandshakerTest, InvalidSNI) {
+ // Test that a client will skip sending SNI if configured to send an invalid
+ // hostname. In this case, the inclusion of '!' is invalid.
+ server_id_ = QuicServerId("invalid!.example.com", 443);
+ crypto_config_.reset(new QuicCryptoClientConfig(
+ std::make_unique<FakeProofVerifier>(), nullptr));
+ CreateConnection();
+ InitializeFakeServer();
+
+ stream()->CryptoConnect();
+ crypto_test_utils::CommunicateHandshakeMessages(
+ connection_, stream(), server_connection_, server_stream());
+
+ EXPECT_EQ(PROTOCOL_TLS1_3, stream()->handshake_protocol());
+ EXPECT_TRUE(stream()->encryption_established());
+ EXPECT_TRUE(stream()->one_rtt_keys_available());
+
+ EXPECT_EQ(server_stream()->crypto_negotiated_params().sni, "");
+}
+
+TEST_P(TlsClientHandshakerTest, BadTransportParams) {
+ if (!connection_->version().UsesHttp3()) {
+ return;
+ }
+ SetQuicReloadableFlag(quic_notify_handshaker_on_connection_close, true);
+ // Finish establishing the first connection:
+ CompleteCryptoHandshake();
+
+ // Create a second connection
+ CreateConnection();
+
+ stream()->CryptoConnect();
+ auto* id_manager = QuicSessionPeer::v99_streamid_manager(session_.get());
+ EXPECT_EQ(kDefaultMaxStreamsPerConnection,
+ id_manager->max_outgoing_bidirectional_streams());
+ QuicConfig config;
+ config.SetMaxBidirectionalStreamsToSend(
+ config.GetMaxBidirectionalStreamsToSend() - 1);
+
+ EXPECT_CALL(*connection_, CloseConnection(QUIC_MAX_STREAMS_ERROR, _, _))
+ .WillOnce(testing::Invoke(connection_,
+ &MockQuicConnection::ReallyCloseConnection));
+ // Close connection will be called again in the handshaker, but this will be
+ // no-op as the connection is already closed.
+ EXPECT_CALL(*connection_, CloseConnection(QUIC_HANDSHAKE_FAILED, _, _));
+
+ crypto_test_utils::HandshakeWithFakeServer(
+ &config, server_crypto_config_.get(), &server_helper_, &alarm_factory_,
+ connection_, stream(), AlpnForVersion(connection_->version()));
+}
+
+} // namespace
+} // namespace test
+} // namespace quic
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 2d332a385bd..5a2bd6400aa 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
@@ -2,15 +2,16 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <memory>
#include <string>
#include <utility>
+#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h"
#include "net/third_party/quiche/src/quic/core/crypto/tls_client_connection.h"
#include "net/third_party/quiche/src/quic/core/crypto/tls_server_connection.h"
#include "net/third_party/quiche/src/quic/core/quic_utils.h"
#include "net/third_party/quiche/src/quic/core/tls_client_handshaker.h"
#include "net/third_party/quiche/src/quic/core/tls_server_handshaker.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h"
#include "net/third_party/quiche/src/quic/test_tools/fake_proof_source.h"
@@ -53,6 +54,7 @@ class TestProofVerifier : public ProofVerifier {
QuicAsyncStatus VerifyCertChain(
const std::string& hostname,
+ const uint16_t port,
const std::vector<std::string>& certs,
const std::string& ocsp_response,
const std::string& cert_sct,
@@ -61,12 +63,12 @@ class TestProofVerifier : public ProofVerifier {
std::unique_ptr<ProofVerifyDetails>* details,
std::unique_ptr<ProofVerifierCallback> callback) override {
if (!active_) {
- return verifier_->VerifyCertChain(hostname, certs, ocsp_response,
+ return verifier_->VerifyCertChain(hostname, port, certs, ocsp_response,
cert_sct, context, error_details,
details, std::move(callback));
}
pending_ops_.push_back(std::make_unique<VerifyChainPendingOp>(
- hostname, certs, ocsp_response, cert_sct, context, error_details,
+ hostname, port, certs, ocsp_response, cert_sct, context, error_details,
details, std::move(callback), verifier_.get()));
return QUIC_PENDING;
}
@@ -101,6 +103,7 @@ class TestProofVerifier : public ProofVerifier {
class VerifyChainPendingOp {
public:
VerifyChainPendingOp(const std::string& hostname,
+ const uint16_t port,
const std::vector<std::string>& certs,
const std::string& ocsp_response,
const std::string& cert_sct,
@@ -110,6 +113,7 @@ class TestProofVerifier : public ProofVerifier {
std::unique_ptr<ProofVerifierCallback> callback,
ProofVerifier* delegate)
: hostname_(hostname),
+ port_(port),
certs_(certs),
ocsp_response_(ocsp_response),
cert_sct_(cert_sct),
@@ -125,7 +129,7 @@ class TestProofVerifier : public ProofVerifier {
// runs the original callback after asserting that the verification ran
// synchronously.
QuicAsyncStatus status = delegate_->VerifyCertChain(
- hostname_, certs_, ocsp_response_, cert_sct_, context_,
+ hostname_, port_, certs_, ocsp_response_, cert_sct_, context_,
error_details_, details_,
std::make_unique<FailingProofVerifierCallback>());
ASSERT_NE(status, QUIC_PENDING);
@@ -134,6 +138,7 @@ class TestProofVerifier : public ProofVerifier {
private:
std::string hostname_;
+ const uint16_t port_;
std::vector<std::string> certs_;
std::string ocsp_response_;
std::string cert_sct_;
@@ -182,6 +187,7 @@ class TestQuicCryptoStream : public QuicCryptoStream {
void OnPacketDecrypted(EncryptionLevel /*level*/) override {}
void OnOneRttPacketAcknowledged() override {}
+ void OnHandshakePacketSent() override {}
HandshakeState GetHandshakeState() const override {
return handshaker()->GetHandshakeState();
@@ -224,8 +230,16 @@ class MockProofHandler : public QuicCryptoClientStream::ProofHandler {
MockProofHandler() = default;
~MockProofHandler() override {}
- MOCK_METHOD1(OnProofValid, void(const QuicCryptoClientConfig::CachedState&));
- MOCK_METHOD1(OnProofVerifyDetailsAvailable, void(const ProofVerifyDetails&));
+ MOCK_METHOD( // NOLINT(build/deprecated)
+ void,
+ OnProofValid,
+ (const QuicCryptoClientConfig::CachedState&),
+ (override));
+ MOCK_METHOD( // NOLINT(build/deprecated)
+ void,
+ OnProofVerifyDetailsAvailable,
+ (const ProofVerifyDetails&),
+ (override));
};
class TestQuicCryptoClientStream : public TestQuicCryptoStream {
@@ -247,7 +261,8 @@ class TestQuicCryptoClientStream : public TestQuicCryptoStream {
session,
crypto_test_utils::ProofVerifyContextForTesting(),
&crypto_config_,
- &proof_handler_)) {}
+ &proof_handler_,
+ /*has_application_state = */ false)) {}
~TestQuicCryptoClientStream() override = default;
@@ -271,10 +286,9 @@ class TestQuicCryptoClientStream : public TestQuicCryptoStream {
class TestTlsServerHandshaker : public TlsServerHandshaker {
public:
TestTlsServerHandshaker(QuicSession* session,
- SSL_CTX* ssl_ctx,
- ProofSource* proof_source,
+ const QuicCryptoServerConfig& crypto_config,
TestQuicCryptoStream* test_stream)
- : TlsServerHandshaker(session, ssl_ctx, proof_source),
+ : TlsServerHandshaker(session, crypto_config),
test_stream_(test_stream) {}
void WriteCryptoData(EncryptionLevel level,
@@ -288,15 +302,14 @@ class TestTlsServerHandshaker : public TlsServerHandshaker {
class TestQuicCryptoServerStream : public TestQuicCryptoStream {
public:
- TestQuicCryptoServerStream(QuicSession* session,
- FakeProofSource* proof_source)
+ TestQuicCryptoServerStream(QuicSession* session)
: TestQuicCryptoStream(session),
- proof_source_(proof_source),
- ssl_ctx_(TlsServerConnection::CreateSslCtx()),
- handshaker_(new TestTlsServerHandshaker(session,
- ssl_ctx_.get(),
- proof_source_,
- this)) {}
+ crypto_config_(QuicCryptoServerConfig::TESTING,
+ QuicRandom::GetInstance(),
+ std::make_unique<FakeProofSource>(),
+ KeyExchangeSource::Default()),
+ handshaker_(
+ new TestTlsServerHandshaker(session, crypto_config_, this)) {}
~TestQuicCryptoServerStream() override = default;
@@ -311,11 +324,12 @@ class TestQuicCryptoServerStream : public TestQuicCryptoStream {
TlsHandshaker* handshaker() const override { return handshaker_.get(); }
- FakeProofSource* GetFakeProofSource() const { return proof_source_; }
+ FakeProofSource* GetFakeProofSource() const {
+ return static_cast<FakeProofSource*>(crypto_config_.proof_source());
+ }
private:
- FakeProofSource* proof_source_;
- bssl::UniquePtr<SSL_CTX> ssl_ctx_;
+ QuicCryptoServerConfig crypto_config_;
std::unique_ptr<TlsServerHandshaker> handshaker_;
};
@@ -344,8 +358,7 @@ class TlsHandshakerTest : public QuicTestWithParam<ParsedQuicVersion> {
server_session_(server_conn_, /*create_mock_crypto_stream=*/false) {
client_stream_ = new TestQuicCryptoClientStream(&client_session_);
client_session_.SetCryptoStream(client_stream_);
- server_stream_ =
- new TestQuicCryptoServerStream(&server_session_, &proof_source_);
+ server_stream_ = new TestQuicCryptoServerStream(&server_session_);
server_session_.SetCryptoStream(server_stream_);
client_session_.Initialize();
server_session_.Initialize();
@@ -401,7 +414,6 @@ class TlsHandshakerTest : public QuicTestWithParam<ParsedQuicVersion> {
MockQuicSession client_session_;
MockQuicSession server_session_;
- FakeProofSource proof_source_;
TestQuicCryptoClientStream* client_stream_;
TestQuicCryptoServerStream* server_stream_;
};
@@ -434,236 +446,6 @@ TEST_P(TlsHandshakerTest, CryptoHandshake) {
ExpectHandshakeSuccessful();
}
-TEST_P(TlsHandshakerTest, HandshakeWithAsyncProofSource) {
- EXPECT_CALL(*client_conn_, CloseConnection(_, _, _)).Times(0);
- EXPECT_CALL(*server_conn_, CloseConnection(_, _, _)).Times(0);
- // Enable FakeProofSource to capture call to ComputeTlsSignature and run it
- // asynchronously.
- FakeProofSource* proof_source = server_stream_->GetFakeProofSource();
- proof_source->Activate();
-
- // Start handshake.
- client_stream_->CryptoConnect();
- ExchangeHandshakeMessages(client_stream_, server_stream_);
-
- ASSERT_EQ(proof_source->NumPendingCallbacks(), 1);
- proof_source->InvokePendingCallback(0);
-
- ExchangeHandshakeMessages(client_stream_, server_stream_);
-
- ExpectHandshakeSuccessful();
-}
-
-TEST_P(TlsHandshakerTest, CancelPendingProofSource) {
- EXPECT_CALL(*client_conn_, CloseConnection(_, _, _)).Times(0);
- EXPECT_CALL(*server_conn_, CloseConnection(_, _, _)).Times(0);
- // Enable FakeProofSource to capture call to ComputeTlsSignature and run it
- // asynchronously.
- FakeProofSource* proof_source = server_stream_->GetFakeProofSource();
- proof_source->Activate();
-
- // Start handshake.
- client_stream_->CryptoConnect();
- ExchangeHandshakeMessages(client_stream_, server_stream_);
-
- ASSERT_EQ(proof_source->NumPendingCallbacks(), 1);
- server_stream_ = nullptr;
-
- proof_source->InvokePendingCallback(0);
-}
-
-TEST_P(TlsHandshakerTest, HandshakeWithAsyncProofVerifier) {
- EXPECT_CALL(*client_conn_, CloseConnection(_, _, _)).Times(0);
- EXPECT_CALL(*server_conn_, CloseConnection(_, _, _)).Times(0);
- // Enable TestProofVerifier to capture call to VerifyCertChain and run it
- // asynchronously.
- TestProofVerifier* proof_verifier = client_stream_->GetTestProofVerifier();
- proof_verifier->Activate();
-
- EXPECT_CALL(client_stream_->proof_handler(), OnProofVerifyDetailsAvailable);
-
- // Start handshake.
- client_stream_->CryptoConnect();
- ExchangeHandshakeMessages(client_stream_, server_stream_);
-
- ASSERT_EQ(proof_verifier->NumPendingCallbacks(), 1u);
- proof_verifier->InvokePendingCallback(0);
-
- ExchangeHandshakeMessages(client_stream_, server_stream_);
-
- ExpectHandshakeSuccessful();
-}
-
-TEST_P(TlsHandshakerTest, ClientSendsNoSNI) {
- // Create a new client stream (and handshaker) with an empty server hostname.
- client_stream_ =
- new TestQuicCryptoClientStream(&client_session_, QuicServerId("", 443),
- std::make_unique<FakeProofVerifier>());
- client_session_.SetCryptoStream(client_stream_);
-
- EXPECT_CALL(*client_conn_, CloseConnection(_, _, _)).Times(0);
- EXPECT_CALL(*server_conn_, CloseConnection(_, _, _)).Times(0);
- EXPECT_CALL(client_stream_->proof_handler(), OnProofVerifyDetailsAvailable);
- client_stream_->CryptoConnect();
- ExchangeHandshakeMessages(client_stream_, server_stream_);
-
- ExpectHandshakeSuccessful();
- EXPECT_EQ(server_stream_->crypto_negotiated_params().sni, "");
-}
-
-TEST_P(TlsHandshakerTest, ServerExtractSNI) {
- EXPECT_CALL(*client_conn_, CloseConnection(_, _, _)).Times(0);
- EXPECT_CALL(*server_conn_, CloseConnection(_, _, _)).Times(0);
- EXPECT_CALL(client_stream_->proof_handler(), OnProofVerifyDetailsAvailable);
- client_stream_->CryptoConnect();
- ExchangeHandshakeMessages(client_stream_, server_stream_);
- ExpectHandshakeSuccessful();
-
- EXPECT_EQ(server_stream_->crypto_negotiated_params().sni, "test.example.com");
-}
-
-TEST_P(TlsHandshakerTest, ClientConnectionClosedOnTlsError) {
- // Have client send ClientHello.
- client_stream_->CryptoConnect();
- EXPECT_CALL(*client_conn_, CloseConnection(QUIC_HANDSHAKE_FAILED, _, _));
-
- // Send a zero-length ServerHello from server to client.
- char bogus_handshake_message[] = {
- // Handshake struct (RFC 8446 appendix B.3)
- 2, // HandshakeType server_hello
- 0, 0, 0, // uint24 length
- };
- server_stream_->WriteCryptoData(
- ENCRYPTION_INITIAL,
- quiche::QuicheStringPiece(bogus_handshake_message,
- QUICHE_ARRAYSIZE(bogus_handshake_message)));
- server_stream_->SendCryptoMessagesToPeer(client_stream_);
-
- EXPECT_FALSE(client_stream_->one_rtt_keys_available());
-}
-
-TEST_P(TlsHandshakerTest, ServerConnectionClosedOnTlsError) {
- EXPECT_CALL(*server_conn_, CloseConnection(QUIC_HANDSHAKE_FAILED, _, _));
-
- // Send a zero-length ClientHello from client to server.
- char bogus_handshake_message[] = {
- // Handshake struct (RFC 8446 appendix B.3)
- 1, // HandshakeType client_hello
- 0, 0, 0, // uint24 length
- };
- client_stream_->WriteCryptoData(
- ENCRYPTION_INITIAL,
- quiche::QuicheStringPiece(bogus_handshake_message,
- QUICHE_ARRAYSIZE(bogus_handshake_message)));
- client_stream_->SendCryptoMessagesToPeer(server_stream_);
-
- EXPECT_FALSE(server_stream_->one_rtt_keys_available());
-}
-
-TEST_P(TlsHandshakerTest, ClientNotSendingALPN) {
- client_stream_->client_handshaker()->AllowEmptyAlpnForTests();
- EXPECT_CALL(client_session_, GetAlpnsToOffer())
- .WillOnce(Return(std::vector<std::string>()));
- EXPECT_CALL(*client_conn_, CloseConnection(QUIC_HANDSHAKE_FAILED,
- "Server did not select ALPN", _));
- EXPECT_CALL(*server_conn_,
- CloseConnection(QUIC_HANDSHAKE_FAILED,
- "Server did not receive a known ALPN", _));
- client_stream_->CryptoConnect();
- ExchangeHandshakeMessages(client_stream_, server_stream_);
-
- EXPECT_FALSE(client_stream_->one_rtt_keys_available());
- EXPECT_EQ(GetQuicRestartFlag(quic_send_settings_on_write_key_available),
- client_stream_->encryption_established());
- EXPECT_FALSE(server_stream_->one_rtt_keys_available());
- EXPECT_EQ(GetQuicRestartFlag(quic_send_settings_on_write_key_available),
- server_stream_->encryption_established());
-}
-
-TEST_P(TlsHandshakerTest, ClientSendingBadALPN) {
- const std::string kTestBadClientAlpn = "bad-client-alpn";
- EXPECT_CALL(client_session_, GetAlpnsToOffer())
- .WillOnce(Return(std::vector<std::string>({kTestBadClientAlpn})));
- EXPECT_CALL(*client_conn_, CloseConnection(QUIC_HANDSHAKE_FAILED,
- "Server did not select ALPN", _));
- EXPECT_CALL(*server_conn_,
- CloseConnection(QUIC_HANDSHAKE_FAILED,
- "Server did not receive a known ALPN", _));
- client_stream_->CryptoConnect();
- ExchangeHandshakeMessages(client_stream_, server_stream_);
-
- EXPECT_FALSE(client_stream_->one_rtt_keys_available());
- EXPECT_EQ(GetQuicRestartFlag(quic_send_settings_on_write_key_available),
- client_stream_->encryption_established());
- EXPECT_FALSE(server_stream_->one_rtt_keys_available());
- EXPECT_EQ(GetQuicRestartFlag(quic_send_settings_on_write_key_available),
- server_stream_->encryption_established());
-}
-
-TEST_P(TlsHandshakerTest, ClientSendingTooManyALPNs) {
- std::string long_alpn(250, 'A');
- EXPECT_CALL(client_session_, GetAlpnsToOffer())
- .WillOnce(Return(std::vector<std::string>({
- long_alpn + "1",
- long_alpn + "2",
- long_alpn + "3",
- long_alpn + "4",
- long_alpn + "5",
- long_alpn + "6",
- long_alpn + "7",
- long_alpn + "8",
- })));
- EXPECT_QUIC_BUG(client_stream_->CryptoConnect(), "Failed to set ALPN");
-}
-
-TEST_P(TlsHandshakerTest, ServerRequiresCustomALPN) {
- const std::string kTestAlpn = "An ALPN That Client Did Not Offer";
- EXPECT_CALL(server_session_, SelectAlpn(_))
- .WillOnce(
- [kTestAlpn](const std::vector<quiche::QuicheStringPiece>& alpns) {
- return std::find(alpns.cbegin(), alpns.cend(), kTestAlpn);
- });
- EXPECT_CALL(*client_conn_, CloseConnection(QUIC_HANDSHAKE_FAILED,
- "Server did not select ALPN", _));
- EXPECT_CALL(*server_conn_,
- CloseConnection(QUIC_HANDSHAKE_FAILED,
- "Server did not receive a known ALPN", _));
- client_stream_->CryptoConnect();
- ExchangeHandshakeMessages(client_stream_, server_stream_);
-
- EXPECT_FALSE(client_stream_->one_rtt_keys_available());
- EXPECT_EQ(GetQuicRestartFlag(quic_send_settings_on_write_key_available),
- client_stream_->encryption_established());
- EXPECT_FALSE(server_stream_->one_rtt_keys_available());
- EXPECT_EQ(GetQuicRestartFlag(quic_send_settings_on_write_key_available),
- server_stream_->encryption_established());
-}
-
-TEST_P(TlsHandshakerTest, CustomALPNNegotiation) {
- EXPECT_CALL(*client_conn_, CloseConnection(_, _, _)).Times(0);
- EXPECT_CALL(*server_conn_, CloseConnection(_, _, _)).Times(0);
-
- const std::string kTestAlpn = "A Custom ALPN Value";
- const std::vector<std::string> kTestAlpns(
- {"foo", "bar", kTestAlpn, "something else"});
- EXPECT_CALL(client_session_, GetAlpnsToOffer())
- .WillRepeatedly(Return(kTestAlpns));
- EXPECT_CALL(server_session_, SelectAlpn(_))
- .WillOnce([kTestAlpn, kTestAlpns](
- const std::vector<quiche::QuicheStringPiece>& alpns) {
- EXPECT_THAT(alpns, ElementsAreArray(kTestAlpns));
- return std::find(alpns.cbegin(), alpns.cend(), kTestAlpn);
- });
- EXPECT_CALL(client_session_,
- OnAlpnSelected(quiche::QuicheStringPiece(kTestAlpn)));
- EXPECT_CALL(server_session_,
- OnAlpnSelected(quiche::QuicheStringPiece(kTestAlpn)));
- client_stream_->CryptoConnect();
- ExchangeHandshakeMessages(client_stream_, server_stream_);
-
- ExpectHandshakeSuccessful();
-}
-
} // namespace
} // namespace test
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.cc b/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.cc
index ced2bd4a51c..5bd5b3d642d 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
@@ -44,14 +44,51 @@ void TlsServerHandshaker::SignatureCallback::Cancel() {
handshaker_ = nullptr;
}
-TlsServerHandshaker::TlsServerHandshaker(QuicSession* session,
- SSL_CTX* ssl_ctx,
- ProofSource* proof_source)
+TlsServerHandshaker::DecryptCallback::DecryptCallback(
+ TlsServerHandshaker* handshaker)
+ : handshaker_(handshaker) {}
+
+void TlsServerHandshaker::DecryptCallback::Run(std::vector<uint8_t> plaintext) {
+ if (handshaker_ == nullptr) {
+ // The callback was cancelled before we could run.
+ return;
+ }
+ handshaker_->decrypted_session_ticket_ = std::move(plaintext);
+ // DecryptCallback::Run could be called synchronously. When that happens, we
+ // are currently in the middle of a call to AdvanceHandshake.
+ // (AdvanceHandshake called SSL_do_handshake, which through some layers called
+ // SessionTicketOpen, which called TicketCrypter::Decrypt, which synchronously
+ // called this function.) In that case, the handshake will continue to be
+ // processed when this function returns.
+ //
+ // When this callback is called asynchronously (i.e. the ticket decryption is
+ // pending), TlsServerHandshaker is not actively processing handshake
+ // messages. We need to have it resume processing handshake messages by
+ // calling AdvanceHandshake.
+ if (handshaker_->state_ == STATE_TICKET_DECRYPTION_PENDING) {
+ handshaker_->AdvanceHandshake();
+ }
+ // The TicketDecrypter took ownership of this callback when Decrypt was
+ // called. Once the callback returns, it will be deleted. Remove the
+ // (non-owning) pointer to the callback from the handshaker so the handshaker
+ // doesn't have an invalid pointer hanging around.
+ handshaker_->ticket_decryption_callback_ = nullptr;
+}
+
+void TlsServerHandshaker::DecryptCallback::Cancel() {
+ DCHECK(handshaker_);
+ handshaker_ = nullptr;
+}
+
+TlsServerHandshaker::TlsServerHandshaker(
+ QuicSession* session,
+ const QuicCryptoServerConfig& crypto_config)
: TlsHandshaker(this, session),
QuicCryptoServerStreamBase(session),
- proof_source_(proof_source),
+ proof_source_(crypto_config.proof_source()),
+ pre_shared_key_(crypto_config.pre_shared_key()),
crypto_negotiated_params_(new QuicCryptoNegotiatedParameters),
- tls_connection_(ssl_ctx, this) {
+ tls_connection_(crypto_config.ssl_ctx(), this) {
DCHECK_EQ(PROTOCOL_TLS1_3,
session->connection()->version().handshake_protocol);
@@ -68,6 +105,10 @@ void TlsServerHandshaker::CancelOutstandingCallbacks() {
signature_callback_->Cancel();
signature_callback_ = nullptr;
}
+ if (ticket_decryption_callback_) {
+ ticket_decryption_callback_->Cancel();
+ ticket_decryption_callback_ = nullptr;
+ }
}
bool TlsServerHandshaker::GetBase64SHA256ClientChannelID(
@@ -121,6 +162,11 @@ bool TlsServerHandshaker::ShouldSendExpectCTHeader() const {
return false;
}
+void TlsServerHandshaker::OnConnectionClosed(QuicErrorCode /*error*/,
+ ConnectionCloseSource /*source*/) {
+ state_ = STATE_CONNECTION_CLOSED;
+}
+
bool TlsServerHandshaker::encryption_established() const {
return encryption_established_;
}
@@ -195,6 +241,9 @@ void TlsServerHandshaker::AdvanceHandshake() {
case STATE_SIGNATURE_PENDING:
should_close = ssl_error != SSL_ERROR_WANT_PRIVATE_KEY_OPERATION;
break;
+ case STATE_TICKET_DECRYPTION_PENDING:
+ should_close = ssl_error != SSL_ERROR_PENDING_TICKET;
+ break;
default:
should_close = true;
}
@@ -246,12 +295,12 @@ bool TlsServerHandshaker::ProcessTransportParameters(
client_params.version, session()->connection()->version(),
session()->supported_versions(), error_details) != QUIC_NO_ERROR ||
session()->config()->ProcessTransportParameters(
- client_params, CLIENT, error_details) != QUIC_NO_ERROR) {
+ client_params, CLIENT, /* is_resumption = */ false, error_details) !=
+ QUIC_NO_ERROR) {
return false;
}
ProcessAdditionalTransportParameters(client_params);
- session()->OnConfigNegotiated();
return true;
}
@@ -283,8 +332,11 @@ void TlsServerHandshaker::SetWriteSecret(
EncryptionLevel level,
const SSL_CIPHER* cipher,
const std::vector<uint8_t>& write_secret) {
- if (GetQuicRestartFlag(quic_send_settings_on_write_key_available) &&
- level == ENCRYPTION_FORWARD_SECURE) {
+ if (GetQuicReloadableFlag(quic_notify_handshaker_on_connection_close) &&
+ state_ == STATE_CONNECTION_CLOSED) {
+ return;
+ }
+ if (level == ENCRYPTION_FORWARD_SECURE) {
encryption_established_ = true;
// Fill crypto_negotiated_params_:
const SSL_CIPHER* cipher = SSL_get_current_cipher(ssl());
@@ -309,20 +361,9 @@ void TlsServerHandshaker::FinishHandshake() {
QUIC_LOG(INFO) << "Server: handshake finished";
state_ = STATE_HANDSHAKE_COMPLETE;
-
- if (!GetQuicRestartFlag(quic_send_settings_on_write_key_available)) {
- encryption_established_ = true;
- }
one_rtt_keys_available_ = true;
const SSL_CIPHER* cipher = SSL_get_current_cipher(ssl());
- if (!GetQuicRestartFlag(quic_send_settings_on_write_key_available)) {
- // Fill crypto_negotiated_params_:
- if (cipher) {
- crypto_negotiated_params_->cipher_suite = SSL_CIPHER_get_value(cipher);
- }
- crypto_negotiated_params_->key_exchange_group = SSL_get_curve_id(ssl());
- }
if (!app_data_read_secret_.empty()) {
if (!SetReadSecret(ENCRYPTION_FORWARD_SECURE, cipher,
@@ -347,7 +388,8 @@ ssl_private_key_result_t TlsServerHandshaker::PrivateKeySign(
quiche::QuicheStringPiece in) {
signature_callback_ = new SignatureCallback(this);
proof_source_->ComputeTlsSignature(
- session()->connection()->self_address(), hostname_, sig_alg, in,
+ session()->connection()->self_address(),
+ session()->connection()->peer_address(), hostname_, sig_alg, in,
std::unique_ptr<SignatureCallback>(signature_callback_));
if (state_ == STATE_SIGNATURE_COMPLETE) {
return PrivateKeyComplete(out, out_len, max_out);
@@ -373,24 +415,105 @@ ssl_private_key_result_t TlsServerHandshaker::PrivateKeyComplete(
return ssl_private_key_success;
}
+size_t TlsServerHandshaker::SessionTicketMaxOverhead() {
+ DCHECK(proof_source_->GetTicketCrypter());
+ return proof_source_->GetTicketCrypter()->MaxOverhead();
+}
+
+int TlsServerHandshaker::SessionTicketSeal(uint8_t* out,
+ size_t* out_len,
+ size_t max_out_len,
+ quiche::QuicheStringPiece in) {
+ DCHECK(proof_source_->GetTicketCrypter());
+ std::vector<uint8_t> ticket = proof_source_->GetTicketCrypter()->Encrypt(in);
+ if (max_out_len < ticket.size()) {
+ QUIC_BUG
+ << "TicketCrypter returned " << ticket.size()
+ << " bytes of ciphertext, which is larger than its max overhead of "
+ << max_out_len;
+ return 0; // failure
+ }
+ *out_len = ticket.size();
+ memcpy(out, ticket.data(), ticket.size());
+ return 1; // success
+}
+
+ssl_ticket_aead_result_t TlsServerHandshaker::SessionTicketOpen(
+ uint8_t* out,
+ size_t* out_len,
+ size_t max_out_len,
+ quiche::QuicheStringPiece in) {
+ DCHECK(proof_source_->GetTicketCrypter());
+
+ if (!ticket_decryption_callback_) {
+ ticket_decryption_callback_ = new DecryptCallback(this);
+ proof_source_->GetTicketCrypter()->Decrypt(
+ in, std::unique_ptr<DecryptCallback>(ticket_decryption_callback_));
+ // Decrypt can run the callback synchronously. In that case, the callback
+ // will clear the ticket_decryption_callback_ pointer, and instead of
+ // returning ssl_ticket_aead_retry, we should continue processing to return
+ // the decrypted ticket.
+ //
+ // If the callback is not run asynchronously, return ssl_ticket_aead_retry
+ // and when the callback is complete this function will be run again to
+ // return the result.
+ if (ticket_decryption_callback_) {
+ state_ = STATE_TICKET_DECRYPTION_PENDING;
+ return ssl_ticket_aead_retry;
+ }
+ }
+ ticket_decryption_callback_ = nullptr;
+ state_ = STATE_LISTENING;
+ if (decrypted_session_ticket_.empty()) {
+ QUIC_DLOG(ERROR) << "Session ticket decryption failed; ignoring ticket";
+ // Ticket decryption failed. Ignore the ticket.
+ return ssl_ticket_aead_ignore_ticket;
+ }
+ if (max_out_len < decrypted_session_ticket_.size()) {
+ return ssl_ticket_aead_error;
+ }
+ memcpy(out, decrypted_session_ticket_.data(),
+ decrypted_session_ticket_.size());
+ *out_len = decrypted_session_ticket_.size();
+ QUIC_RELOADABLE_FLAG_COUNT(quic_enable_tls_resumption);
+
+ return ssl_ticket_aead_success;
+}
+
int TlsServerHandshaker::SelectCertificate(int* out_alert) {
const char* hostname = SSL_get_servername(ssl(), TLSEXT_NAMETYPE_host_name);
if (hostname) {
hostname_ = hostname;
crypto_negotiated_params_->sni =
QuicHostnameUtils::NormalizeHostname(hostname_);
+ if (GetQuicReloadableFlag(quic_tls_enforce_valid_sni)) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_tls_enforce_valid_sni);
+ if (!QuicHostnameUtils::IsValidSNI(hostname_)) {
+ // TODO(b/151676147): Include this error string in the CONNECTION_CLOSE
+ // frame.
+ QUIC_LOG(ERROR) << "Invalid SNI provided: \"" << hostname_ << "\"";
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
+ }
+ }
} else {
QUIC_LOG(INFO) << "No hostname indicated in SNI";
}
QuicReferenceCountedPointer<ProofSource::Chain> chain =
proof_source_->GetCertChain(session()->connection()->self_address(),
+ session()->connection()->peer_address(),
hostname_);
- if (chain->certs.empty()) {
+ if (!chain || chain->certs.empty()) {
QUIC_LOG(ERROR) << "No certs provided for host '" << hostname_ << "'";
return SSL_TLSEXT_ERR_ALERT_FATAL;
}
+ if (!pre_shared_key_.empty()) {
+ // TODO(b/154162689) add PSK support to QUIC+TLS.
+ QUIC_BUG << "QUIC server pre-shared keys not yet supported with TLS";
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
+ }
+
std::vector<CRYPTO_BUFFER*> certs;
certs.resize(chain->certs.size());
for (size_t i = 0; i < certs.size(); i++) {
@@ -412,6 +535,8 @@ int TlsServerHandshaker::SelectCertificate(int* out_alert) {
return SSL_TLSEXT_ERR_ALERT_FATAL;
}
OverrideQuicConfigDefaults(session()->config());
+ session()->OnConfigNegotiated();
+
if (!SetTransportParameters()) {
QUIC_LOG(ERROR) << "Failed to set transport parameters";
return SSL_TLSEXT_ERR_ALERT_FATAL;
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 22ae45df9ed..c62dbbbe47c 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
@@ -9,6 +9,7 @@
#include "third_party/boringssl/src/include/openssl/pool.h"
#include "third_party/boringssl/src/include/openssl/ssl.h"
+#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h"
#include "net/third_party/quiche/src/quic/core/crypto/tls_server_connection.h"
#include "net/third_party/quiche/src/quic/core/proto/cached_network_parameters_proto.h"
#include "net/third_party/quiche/src/quic/core/quic_crypto_server_stream_base.h"
@@ -27,8 +28,7 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker
public QuicCryptoServerStreamBase {
public:
TlsServerHandshaker(QuicSession* session,
- SSL_CTX* ssl_ctx,
- ProofSource* proof_source);
+ const QuicCryptoServerConfig& crypto_config);
TlsServerHandshaker(const TlsServerHandshaker&) = delete;
TlsServerHandshaker& operator=(const TlsServerHandshaker&) = delete;
@@ -47,6 +47,9 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker
CachedNetworkParameters cached_network_params) override;
void OnPacketDecrypted(EncryptionLevel level) override;
void OnOneRttPacketAcknowledged() override {}
+ void OnHandshakePacketSent() override {}
+ void OnConnectionClosed(QuicErrorCode error,
+ ConnectionCloseSource source) override;
void OnHandshakeDoneReceived() override;
bool ShouldSendExpectCTHeader() const override;
@@ -106,6 +109,16 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker
ssl_private_key_result_t PrivateKeyComplete(uint8_t* out,
size_t* out_len,
size_t max_out) override;
+ size_t SessionTicketMaxOverhead() override;
+ int SessionTicketSeal(uint8_t* out,
+ size_t* out_len,
+ size_t max_out_len,
+ quiche::QuicheStringPiece in) override;
+ ssl_ticket_aead_result_t SessionTicketOpen(
+ uint8_t* out,
+ size_t* out_len,
+ size_t max_out_len,
+ quiche::QuicheStringPiece in) override;
TlsConnection::Delegate* ConnectionDelegate() override { return this; }
private:
@@ -124,8 +137,22 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker
TlsServerHandshaker* handshaker_;
};
+ class QUIC_EXPORT_PRIVATE DecryptCallback
+ : public ProofSource::DecryptCallback {
+ public:
+ explicit DecryptCallback(TlsServerHandshaker* handshaker);
+ void Run(std::vector<uint8_t> plaintext) override;
+
+ // If called, Cancel causes the pending callback to be a no-op.
+ void Cancel();
+
+ private:
+ TlsServerHandshaker* handshaker_;
+ };
+
enum State {
STATE_LISTENING,
+ STATE_TICKET_DECRYPTION_PENDING,
STATE_SIGNATURE_PENDING,
STATE_SIGNATURE_COMPLETE,
STATE_ENCRYPTION_HANDSHAKE_DATA_PROCESSED,
@@ -146,10 +173,22 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker
ProofSource* proof_source_;
SignatureCallback* signature_callback_ = nullptr;
+ // State to handle potentially asynchronous session ticket decryption.
+ // |ticket_decryption_callback_| points to the non-owned callback that was
+ // passed to ProofSource::TicketCrypter::Decrypt but hasn't finished running
+ // yet.
+ DecryptCallback* ticket_decryption_callback_ = nullptr;
+ // |decrypted_session_ticket_| contains the decrypted session ticket after the
+ // callback has run but before it is passed to BoringSSL.
+ std::vector<uint8_t> decrypted_session_ticket_;
+
std::string hostname_;
std::string cert_verify_sig_;
std::unique_ptr<ProofSource::Details> proof_source_details_;
+ // Pre-shared key used during the handshake.
+ std::string pre_shared_key_;
+
// Used to hold the ENCRYPTION_FORWARD_SECURE read secret until the handshake
// is complete. This is temporary until
// https://bugs.chromium.org/p/boringssl/issues/detail?id=303 is resolved.
diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker_test.cc b/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker_test.cc
new file mode 100644
index 00000000000..a71338c5f5b
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker_test.cc
@@ -0,0 +1,467 @@
+// 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 <memory>
+#include <utility>
+#include <vector>
+
+#include "net/third_party/quiche/src/quic/core/crypto/proof_source.h"
+#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h"
+#include "net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h"
+#include "net/third_party/quiche/src/quic/core/quic_session.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/core/tls_client_handshaker.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_test.h"
+#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h"
+#include "net/third_party/quiche/src/quic/test_tools/failing_proof_source.h"
+#include "net/third_party/quiche/src/quic/test_tools/fake_proof_source.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
+#include "net/third_party/quiche/src/quic/test_tools/simple_session_cache.h"
+#include "net/third_party/quiche/src/quic/test_tools/test_ticket_crypter.h"
+#include "net/third_party/quiche/src/common/platform/api/quiche_arraysize.h"
+#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
+
+namespace quic {
+class QuicConnection;
+class QuicStream;
+} // namespace quic
+
+using testing::_;
+using testing::NiceMock;
+using testing::Return;
+
+namespace quic {
+namespace test {
+
+namespace {
+
+const char kServerHostname[] = "test.example.com";
+const uint16_t kServerPort = 443;
+
+class TlsServerHandshakerTest : public QuicTest {
+ public:
+ TlsServerHandshakerTest()
+ : server_compressed_certs_cache_(
+ QuicCompressedCertsCache::kQuicCompressedCertsCacheSize),
+ server_id_(kServerHostname, kServerPort, false),
+ client_crypto_config_(crypto_test_utils::ProofVerifierForTesting(),
+ std::make_unique<test::SimpleSessionCache>()) {
+ InitializeServerConfig();
+ InitializeServer();
+ InitializeFakeClient();
+ }
+
+ ~TlsServerHandshakerTest() override {
+ // Ensure that anything that might reference |helpers_| is destroyed before
+ // |helpers_| is destroyed.
+ server_session_.reset();
+ client_session_.reset();
+ helpers_.clear();
+ alarm_factories_.clear();
+ }
+
+ void InitializeServerConfig() {
+ SetQuicReloadableFlag(quic_enable_tls_resumption, true);
+ auto ticket_crypter = std::make_unique<TestTicketCrypter>();
+ ticket_crypter_ = ticket_crypter.get();
+ auto proof_source = std::make_unique<FakeProofSource>();
+ proof_source_ = proof_source.get();
+ proof_source_->SetTicketCrypter(std::move(ticket_crypter));
+ server_crypto_config_ = std::make_unique<QuicCryptoServerConfig>(
+ QuicCryptoServerConfig::TESTING, QuicRandom::GetInstance(),
+ std::move(proof_source), KeyExchangeSource::Default());
+ }
+
+ void InitializeServerConfigWithFailingProofSource() {
+ server_crypto_config_ = std::make_unique<QuicCryptoServerConfig>(
+ QuicCryptoServerConfig::TESTING, QuicRandom::GetInstance(),
+ std::make_unique<FailingProofSource>(), KeyExchangeSource::Default());
+ }
+
+ // Initializes the crypto server stream state for testing. May be
+ // called multiple times.
+ void InitializeServer() {
+ TestQuicSpdyServerSession* server_session = nullptr;
+ helpers_.push_back(std::make_unique<NiceMock<MockQuicConnectionHelper>>());
+ alarm_factories_.push_back(std::make_unique<MockAlarmFactory>());
+ CreateServerSessionForTest(
+ server_id_, QuicTime::Delta::FromSeconds(100000), supported_versions_,
+ helpers_.back().get(), alarm_factories_.back().get(),
+ server_crypto_config_.get(), &server_compressed_certs_cache_,
+ &server_connection_, &server_session);
+ CHECK(server_session);
+ server_session_.reset(server_session);
+ EXPECT_CALL(*server_session_->helper(), CanAcceptClientHello(_, _, _, _, _))
+ .Times(testing::AnyNumber());
+ EXPECT_CALL(*server_session_, SelectAlpn(_))
+ .WillRepeatedly(
+ [this](const std::vector<quiche::QuicheStringPiece>& alpns) {
+ return std::find(
+ alpns.cbegin(), alpns.cend(),
+ AlpnForVersion(server_session_->connection()->version()));
+ });
+ crypto_test_utils::SetupCryptoServerConfigForTest(
+ server_connection_->clock(), server_connection_->random_generator(),
+ server_crypto_config_.get());
+ }
+
+ QuicCryptoServerStreamBase* server_stream() {
+ return server_session_->GetMutableCryptoStream();
+ }
+
+ QuicCryptoClientStream* client_stream() {
+ return client_session_->GetMutableCryptoStream();
+ }
+
+ // Initializes a fake client, and all its associated state, for
+ // testing. May be called multiple times.
+ void InitializeFakeClient() {
+ TestQuicSpdyClientSession* client_session = nullptr;
+ helpers_.push_back(std::make_unique<NiceMock<MockQuicConnectionHelper>>());
+ alarm_factories_.push_back(std::make_unique<MockAlarmFactory>());
+ CreateClientSessionForTest(
+ server_id_, QuicTime::Delta::FromSeconds(100000), supported_versions_,
+ helpers_.back().get(), alarm_factories_.back().get(),
+ &client_crypto_config_, &client_connection_, &client_session);
+ const std::string default_alpn =
+ AlpnForVersion(client_connection_->version());
+ ON_CALL(*client_session, GetAlpnsToOffer())
+ .WillByDefault(Return(std::vector<std::string>({default_alpn})));
+ CHECK(client_session);
+ client_session_.reset(client_session);
+ moved_messages_counts_ = {0, 0};
+ }
+
+ void CompleteCryptoHandshake() {
+ while (!client_stream()->one_rtt_keys_available() ||
+ !server_stream()->one_rtt_keys_available()) {
+ auto previous_moved_messages_counts = moved_messages_counts_;
+ AdvanceHandshakeWithFakeClient();
+ // Check that the handshake has made forward progress
+ ASSERT_NE(previous_moved_messages_counts, moved_messages_counts_);
+ }
+ }
+
+ // Performs a single round of handshake message-exchange between the
+ // client and server.
+ void AdvanceHandshakeWithFakeClient() {
+ CHECK(server_connection_);
+ CHECK(client_session_ != nullptr);
+
+ EXPECT_CALL(*client_session_, OnProofValid(_)).Times(testing::AnyNumber());
+ EXPECT_CALL(*client_session_, OnProofVerifyDetailsAvailable(_))
+ .Times(testing::AnyNumber());
+ EXPECT_CALL(*client_connection_, OnCanWrite()).Times(testing::AnyNumber());
+ EXPECT_CALL(*server_connection_, OnCanWrite()).Times(testing::AnyNumber());
+ // Call CryptoConnect if we haven't moved any client messages yet.
+ if (moved_messages_counts_.first == 0) {
+ client_stream()->CryptoConnect();
+ }
+ moved_messages_counts_ = crypto_test_utils::AdvanceHandshake(
+ client_connection_, client_stream(), moved_messages_counts_.first,
+ server_connection_, server_stream(), moved_messages_counts_.second);
+ }
+
+ void ExpectHandshakeSuccessful() {
+ EXPECT_TRUE(client_stream()->one_rtt_keys_available());
+ EXPECT_TRUE(client_stream()->encryption_established());
+ EXPECT_TRUE(server_stream()->one_rtt_keys_available());
+ EXPECT_TRUE(server_stream()->encryption_established());
+ EXPECT_EQ(HANDSHAKE_COMPLETE, client_stream()->GetHandshakeState());
+ EXPECT_EQ(HANDSHAKE_CONFIRMED, server_stream()->GetHandshakeState());
+
+ const auto& client_crypto_params =
+ client_stream()->crypto_negotiated_params();
+ const auto& server_crypto_params =
+ server_stream()->crypto_negotiated_params();
+ // The TLS params should be filled in on the client.
+ EXPECT_NE(0, client_crypto_params.cipher_suite);
+ EXPECT_NE(0, client_crypto_params.key_exchange_group);
+ EXPECT_NE(0, client_crypto_params.peer_signature_algorithm);
+
+ // The cipher suite and key exchange group should match on the client and
+ // server.
+ EXPECT_EQ(client_crypto_params.cipher_suite,
+ server_crypto_params.cipher_suite);
+ EXPECT_EQ(client_crypto_params.key_exchange_group,
+ server_crypto_params.key_exchange_group);
+ // We don't support client certs on the server (yet), so the server
+ // shouldn't have a peer signature algorithm to report.
+ EXPECT_EQ(0, server_crypto_params.peer_signature_algorithm);
+ }
+
+ protected:
+ // Every connection gets its own MockQuicConnectionHelper and
+ // MockAlarmFactory, tracked separately from the server and client state so
+ // their lifetimes persist through the whole test.
+ std::vector<std::unique_ptr<MockQuicConnectionHelper>> helpers_;
+ std::vector<std::unique_ptr<MockAlarmFactory>> alarm_factories_;
+
+ // Server state.
+ PacketSavingConnection* server_connection_;
+ std::unique_ptr<TestQuicSpdyServerSession> server_session_;
+ TestTicketCrypter* ticket_crypter_; // owned by proof_source_
+ FakeProofSource* proof_source_; // owned by server_crypto_config_
+ std::unique_ptr<QuicCryptoServerConfig> server_crypto_config_;
+ QuicCompressedCertsCache server_compressed_certs_cache_;
+ QuicServerId server_id_;
+
+ // Client state.
+ PacketSavingConnection* client_connection_;
+ QuicCryptoClientConfig client_crypto_config_;
+ std::unique_ptr<TestQuicSpdyClientSession> client_session_;
+
+ crypto_test_utils::FakeClientOptions client_options_;
+ // How many handshake messages have been moved from client to server and
+ // server to client.
+ std::pair<size_t, size_t> moved_messages_counts_ = {0, 0};
+
+ // Which QUIC versions the client and server support.
+ ParsedQuicVersionVector supported_versions_ = AllSupportedVersionsWithTls();
+};
+
+TEST_F(TlsServerHandshakerTest, NotInitiallyConected) {
+ EXPECT_FALSE(server_stream()->encryption_established());
+ EXPECT_FALSE(server_stream()->one_rtt_keys_available());
+}
+
+TEST_F(TlsServerHandshakerTest, ConnectedAfterTlsHandshake) {
+ CompleteCryptoHandshake();
+ EXPECT_EQ(PROTOCOL_TLS1_3, server_stream()->handshake_protocol());
+ ExpectHandshakeSuccessful();
+}
+
+TEST_F(TlsServerHandshakerTest, HandshakeWithAsyncProofSource) {
+ EXPECT_CALL(*client_connection_, CloseConnection(_, _, _)).Times(0);
+ EXPECT_CALL(*server_connection_, CloseConnection(_, _, _)).Times(0);
+ // Enable FakeProofSource to capture call to ComputeTlsSignature and run it
+ // asynchronously.
+ proof_source_->Activate();
+
+ // Start handshake.
+ AdvanceHandshakeWithFakeClient();
+
+ ASSERT_EQ(proof_source_->NumPendingCallbacks(), 1);
+ proof_source_->InvokePendingCallback(0);
+
+ CompleteCryptoHandshake();
+
+ ExpectHandshakeSuccessful();
+}
+
+TEST_F(TlsServerHandshakerTest, CancelPendingProofSource) {
+ EXPECT_CALL(*client_connection_, CloseConnection(_, _, _)).Times(0);
+ EXPECT_CALL(*server_connection_, CloseConnection(_, _, _)).Times(0);
+ // Enable FakeProofSource to capture call to ComputeTlsSignature and run it
+ // asynchronously.
+ proof_source_->Activate();
+
+ // Start handshake.
+ AdvanceHandshakeWithFakeClient();
+
+ ASSERT_EQ(proof_source_->NumPendingCallbacks(), 1);
+ server_session_ = nullptr;
+
+ proof_source_->InvokePendingCallback(0);
+}
+
+TEST_F(TlsServerHandshakerTest, ExtractSNI) {
+ CompleteCryptoHandshake();
+ ExpectHandshakeSuccessful();
+
+ EXPECT_EQ(server_stream()->crypto_negotiated_params().sni,
+ "test.example.com");
+}
+
+TEST_F(TlsServerHandshakerTest, ConnectionClosedOnTlsError) {
+ EXPECT_CALL(*server_connection_,
+ CloseConnection(QUIC_HANDSHAKE_FAILED, _, _));
+
+ // Send a zero-length ClientHello from client to server.
+ char bogus_handshake_message[] = {
+ // Handshake struct (RFC 8446 appendix B.3)
+ 1, // HandshakeType client_hello
+ 0, 0, 0, // uint24 length
+ };
+ server_stream()->crypto_message_parser()->ProcessInput(
+ quiche::QuicheStringPiece(bogus_handshake_message,
+ QUICHE_ARRAYSIZE(bogus_handshake_message)),
+ ENCRYPTION_INITIAL);
+
+ EXPECT_FALSE(server_stream()->one_rtt_keys_available());
+}
+
+TEST_F(TlsServerHandshakerTest, ClientNotSendingALPN) {
+ static_cast<TlsClientHandshaker*>(
+ QuicCryptoClientStreamPeer::GetHandshaker(client_stream()))
+ ->AllowEmptyAlpnForTests();
+ EXPECT_CALL(*client_session_, GetAlpnsToOffer())
+ .WillOnce(Return(std::vector<std::string>()));
+ EXPECT_CALL(
+ *client_connection_,
+ CloseConnection(QUIC_HANDSHAKE_FAILED, "Server did not select ALPN", _));
+ EXPECT_CALL(*server_connection_,
+ CloseConnection(QUIC_HANDSHAKE_FAILED,
+ "Server did not receive a known ALPN", _));
+
+ // Process two flights of handshake messages.
+ AdvanceHandshakeWithFakeClient();
+ AdvanceHandshakeWithFakeClient();
+
+ EXPECT_FALSE(client_stream()->one_rtt_keys_available());
+ EXPECT_TRUE(client_stream()->encryption_established());
+ EXPECT_FALSE(server_stream()->one_rtt_keys_available());
+ EXPECT_TRUE(server_stream()->encryption_established());
+}
+
+TEST_F(TlsServerHandshakerTest, ClientSendingBadALPN) {
+ const std::string kTestBadClientAlpn = "bad-client-alpn";
+ EXPECT_CALL(*client_session_, GetAlpnsToOffer())
+ .WillOnce(Return(std::vector<std::string>({kTestBadClientAlpn})));
+ EXPECT_CALL(
+ *client_connection_,
+ CloseConnection(QUIC_HANDSHAKE_FAILED, "Server did not select ALPN", _));
+ EXPECT_CALL(*server_connection_,
+ CloseConnection(QUIC_HANDSHAKE_FAILED,
+ "Server did not receive a known ALPN", _));
+
+ // Process two flights of handshake messages.
+ AdvanceHandshakeWithFakeClient();
+ AdvanceHandshakeWithFakeClient();
+
+ EXPECT_FALSE(client_stream()->one_rtt_keys_available());
+ EXPECT_TRUE(client_stream()->encryption_established());
+ EXPECT_FALSE(server_stream()->one_rtt_keys_available());
+ EXPECT_TRUE(server_stream()->encryption_established());
+}
+
+TEST_F(TlsServerHandshakerTest, CustomALPNNegotiation) {
+ EXPECT_CALL(*client_connection_, CloseConnection(_, _, _)).Times(0);
+ EXPECT_CALL(*server_connection_, CloseConnection(_, _, _)).Times(0);
+
+ const std::string kTestAlpn = "A Custom ALPN Value";
+ const std::vector<std::string> kTestAlpns(
+ {"foo", "bar", kTestAlpn, "something else"});
+ EXPECT_CALL(*client_session_, GetAlpnsToOffer())
+ .WillRepeatedly(Return(kTestAlpns));
+ EXPECT_CALL(*server_session_, SelectAlpn(_))
+ .WillOnce([kTestAlpn, kTestAlpns](
+ const std::vector<quiche::QuicheStringPiece>& alpns) {
+ EXPECT_THAT(alpns, testing::ElementsAreArray(kTestAlpns));
+ return std::find(alpns.cbegin(), alpns.cend(), kTestAlpn);
+ });
+ EXPECT_CALL(*client_session_,
+ OnAlpnSelected(quiche::QuicheStringPiece(kTestAlpn)));
+ EXPECT_CALL(*server_session_,
+ OnAlpnSelected(quiche::QuicheStringPiece(kTestAlpn)));
+
+ CompleteCryptoHandshake();
+ ExpectHandshakeSuccessful();
+}
+
+TEST_F(TlsServerHandshakerTest, RejectInvalidSNI) {
+ SetQuicReloadableFlag(quic_tls_enforce_valid_sni, true);
+ server_id_ = QuicServerId("invalid!.example.com", kServerPort, false);
+ InitializeFakeClient();
+ static_cast<TlsClientHandshaker*>(
+ QuicCryptoClientStreamPeer::GetHandshaker(client_stream()))
+ ->AllowInvalidSNIForTests();
+
+ // Run the handshake and expect it to fail.
+ AdvanceHandshakeWithFakeClient();
+ EXPECT_FALSE(server_stream()->encryption_established());
+ EXPECT_FALSE(server_stream()->one_rtt_keys_available());
+}
+
+TEST_F(TlsServerHandshakerTest, Resumption) {
+ // Do the first handshake
+ InitializeFakeClient();
+ CompleteCryptoHandshake();
+ ExpectHandshakeSuccessful();
+ EXPECT_FALSE(client_stream()->IsResumption());
+
+ // Now do another handshake
+ InitializeServer();
+ InitializeFakeClient();
+ CompleteCryptoHandshake();
+ ExpectHandshakeSuccessful();
+ EXPECT_TRUE(client_stream()->IsResumption());
+}
+
+TEST_F(TlsServerHandshakerTest, ResumptionWithAsyncDecryptCallback) {
+ // Do the first handshake
+ InitializeFakeClient();
+ CompleteCryptoHandshake();
+ ExpectHandshakeSuccessful();
+
+ ticket_crypter_->SetRunCallbacksAsync(true);
+ // Now do another handshake
+ InitializeServer();
+ InitializeFakeClient();
+
+ AdvanceHandshakeWithFakeClient();
+ // Test that the DecryptCallback will be run asynchronously, and then run it.
+ ASSERT_EQ(ticket_crypter_->NumPendingCallbacks(), 1u);
+ ticket_crypter_->RunPendingCallback(0);
+
+ CompleteCryptoHandshake();
+ ExpectHandshakeSuccessful();
+ EXPECT_TRUE(client_stream()->IsResumption());
+}
+
+TEST_F(TlsServerHandshakerTest, ResumptionWithFailingDecryptCallback) {
+ // Do the first handshake
+ InitializeFakeClient();
+ CompleteCryptoHandshake();
+ ExpectHandshakeSuccessful();
+
+ ticket_crypter_->set_fail_decrypt(true);
+ // Now do another handshake
+ InitializeServer();
+ InitializeFakeClient();
+ CompleteCryptoHandshake();
+ ExpectHandshakeSuccessful();
+ EXPECT_FALSE(client_stream()->IsResumption());
+}
+
+TEST_F(TlsServerHandshakerTest, ResumptionWithFailingAsyncDecryptCallback) {
+ // Do the first handshake
+ InitializeFakeClient();
+ CompleteCryptoHandshake();
+ ExpectHandshakeSuccessful();
+
+ ticket_crypter_->set_fail_decrypt(true);
+ ticket_crypter_->SetRunCallbacksAsync(true);
+ // Now do another handshake
+ InitializeServer();
+ InitializeFakeClient();
+
+ AdvanceHandshakeWithFakeClient();
+ // Test that the DecryptCallback will be run asynchronously, and then run it.
+ ASSERT_EQ(ticket_crypter_->NumPendingCallbacks(), 1u);
+ ticket_crypter_->RunPendingCallback(0);
+
+ CompleteCryptoHandshake();
+ ExpectHandshakeSuccessful();
+ EXPECT_FALSE(client_stream()->IsResumption());
+}
+
+TEST_F(TlsServerHandshakerTest, HandshakeFailsWithFailingProofSource) {
+ InitializeServerConfigWithFailingProofSource();
+ InitializeServer();
+ InitializeFakeClient();
+
+ // Attempt handshake.
+ AdvanceHandshakeWithFakeClient();
+ // Check that the server didn't send any handshake messages, because it failed
+ // to handshake.
+ EXPECT_EQ(moved_messages_counts_.second, 0u);
+}
+
+} // namespace
+} // namespace test
+} // namespace quic
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 daa56302145..6951b2cea3f 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
@@ -20,14 +20,14 @@ UberQuicStreamIdManager::UberQuicStreamIdManager(
: bidirectional_stream_id_manager_(delegate,
/*unidirectional=*/false,
perspective,
- version.transport_version,
+ version,
max_open_outgoing_bidirectional_streams,
max_open_incoming_bidirectional_streams),
unidirectional_stream_id_manager_(
delegate,
/*unidirectional=*/true,
perspective,
- version.transport_version,
+ version,
max_open_outgoing_unidirectional_streams,
max_open_incoming_unidirectional_streams) {}
@@ -96,13 +96,6 @@ bool UberQuicStreamIdManager::OnStreamsBlockedFrame(
error_details);
}
-bool UberQuicStreamIdManager::IsIncomingStream(QuicStreamId id) const {
- if (QuicUtils::IsBidirectionalStreamId(id)) {
- return bidirectional_stream_id_manager_.IsIncomingStream(id);
- }
- return unidirectional_stream_id_manager_.IsIncomingStream(id);
-}
-
bool UberQuicStreamIdManager::IsAvailableStream(QuicStreamId id) const {
if (QuicUtils::IsBidirectionalStreamId(id)) {
return bidirectional_stream_id_manager_.IsAvailableStream(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 d3f374a83a5..b1fc1260987 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
@@ -66,9 +66,6 @@ class QUIC_EXPORT_PRIVATE UberQuicStreamIdManager {
bool OnStreamsBlockedFrame(const QuicStreamsBlockedFrame& frame,
std::string* error_details);
- // Return true if |id| is peer initiated.
- bool IsIncomingStream(QuicStreamId id) const;
-
// Returns true if |id| is still available.
bool IsAvailableStream(QuicStreamId id) const;
diff --git a/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager_test.cc
index 4fc1ccab333..7cae0a6e1de 100644
--- a/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager_test.cc
@@ -46,8 +46,10 @@ std::vector<TestParams> GetTestParams() {
class MockDelegate : public QuicStreamIdManager::DelegateInterface {
public:
- MOCK_METHOD2(SendMaxStreams,
- void(QuicStreamCount stream_count, bool unidirectional));
+ MOCK_METHOD(void,
+ SendMaxStreams,
+ (QuicStreamCount stream_count, bool unidirectional),
+ (override));
};
class UberQuicStreamIdManagerTest : public QuicTestWithParam<TestParams> {
@@ -64,25 +66,25 @@ class UberQuicStreamIdManagerTest : public QuicTestWithParam<TestParams> {
QuicStreamId GetNthClientInitiatedBidirectionalId(int n) {
return QuicUtils::GetFirstBidirectionalStreamId(transport_version(),
Perspective::IS_CLIENT) +
- kV99StreamIdIncrement * n;
+ QuicUtils::StreamIdDelta(transport_version()) * n;
}
QuicStreamId GetNthClientInitiatedUnidirectionalId(int n) {
return QuicUtils::GetFirstUnidirectionalStreamId(transport_version(),
Perspective::IS_CLIENT) +
- kV99StreamIdIncrement * n;
+ QuicUtils::StreamIdDelta(transport_version()) * n;
}
QuicStreamId GetNthServerInitiatedBidirectionalId(int n) {
return QuicUtils::GetFirstBidirectionalStreamId(transport_version(),
Perspective::IS_SERVER) +
- kV99StreamIdIncrement * n;
+ QuicUtils::StreamIdDelta(transport_version()) * n;
}
QuicStreamId GetNthServerInitiatedUnidirectionalId(int n) {
return QuicUtils::GetFirstUnidirectionalStreamId(transport_version(),
Perspective::IS_SERVER) +
- kV99StreamIdIncrement * n;
+ QuicUtils::StreamIdDelta(transport_version()) * n;
}
QuicStreamId GetNthPeerInitiatedBidirectionalStreamId(int n) {
@@ -300,17 +302,6 @@ TEST_P(UberQuicStreamIdManagerTest, OnStreamsBlockedFrame) {
EXPECT_TRUE(manager_.OnStreamsBlockedFrame(frame, nullptr));
}
-TEST_P(UberQuicStreamIdManagerTest, IsIncomingStream) {
- EXPECT_TRUE(
- manager_.IsIncomingStream(GetNthPeerInitiatedBidirectionalStreamId(0)));
- EXPECT_TRUE(
- manager_.IsIncomingStream(GetNthPeerInitiatedUnidirectionalStreamId(0)));
- EXPECT_FALSE(
- manager_.IsIncomingStream(GetNthSelfInitiatedBidirectionalStreamId(0)));
- EXPECT_FALSE(
- manager_.IsIncomingStream(GetNthSelfInitiatedUnidirectionalStreamId(0)));
-}
-
TEST_P(UberQuicStreamIdManagerTest, SetMaxOpenOutgoingStreamsPlusFrame) {
const size_t kNumMaxOutgoingStream = 123;
// Set the uni- and bi- directional limits to different values to ensure