summaryrefslogtreecommitdiff
path: root/chromium/net/third_party/quiche
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2022-02-02 12:21:57 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2022-02-12 08:13:00 +0000
commit606d85f2a5386472314d39923da28c70c60dc8e7 (patch)
treea8f4d7bf997f349f45605e6058259fba0630e4d7 /chromium/net/third_party/quiche
parent5786336dda477d04fb98483dca1a5426eebde2d7 (diff)
downloadqtwebengine-chromium-606d85f2a5386472314d39923da28c70c60dc8e7.tar.gz
BASELINE: Update Chromium to 96.0.4664.181
Change-Id: I762cd1da89d73aa6313b4a753fe126c34833f046 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/net/third_party/quiche')
-rw-r--r--chromium/net/third_party/quiche/BUILD.gn41
-rw-r--r--chromium/net/third_party/quiche/overrides/quiche_platform_impl/quic_mutex_impl.h5
-rw-r--r--chromium/net/third_party/quiche/src/README.md3
-rw-r--r--chromium/net/third_party/quiche/src/common/platform/default/quiche_platform_impl/quiche_containers_impl.h22
-rw-r--r--chromium/net/third_party/quiche/src/common/print_elements.h10
-rw-r--r--chromium/net/third_party/quiche/src/http2/adapter/callback_visitor.cc138
-rw-r--r--chromium/net/third_party/quiche/src/http2/adapter/callback_visitor.h26
-rw-r--r--chromium/net/third_party/quiche/src/http2/adapter/callback_visitor_test.cc44
-rw-r--r--chromium/net/third_party/quiche/src/http2/adapter/data_source.h12
-rw-r--r--chromium/net/third_party/quiche/src/http2/adapter/header_validator.cc99
-rw-r--r--chromium/net/third_party/quiche/src/http2/adapter/header_validator.h49
-rw-r--r--chromium/net/third_party/quiche/src/http2/adapter/header_validator_test.cc213
-rw-r--r--chromium/net/third_party/quiche/src/http2/adapter/http2_adapter.h12
-rw-r--r--chromium/net/third_party/quiche/src/http2/adapter/http2_session.h2
-rw-r--r--chromium/net/third_party/quiche/src/http2/adapter/http2_visitor_interface.h46
-rw-r--r--chromium/net/third_party/quiche/src/http2/adapter/mock_http2_visitor.h61
-rw-r--r--chromium/net/third_party/quiche/src/http2/adapter/mock_nghttp2_callbacks.h2
-rw-r--r--chromium/net/third_party/quiche/src/http2/adapter/nghttp2_adapter.cc53
-rw-r--r--chromium/net/third_party/quiche/src/http2/adapter/nghttp2_adapter.h12
-rw-r--r--chromium/net/third_party/quiche/src/http2/adapter/nghttp2_adapter_test.cc711
-rw-r--r--chromium/net/third_party/quiche/src/http2/adapter/nghttp2_callbacks.cc62
-rw-r--r--chromium/net/third_party/quiche/src/http2/adapter/nghttp2_callbacks.h2
-rw-r--r--chromium/net/third_party/quiche/src/http2/adapter/nghttp2_data_provider.h3
-rw-r--r--chromium/net/third_party/quiche/src/http2/adapter/nghttp2_session.cc4
-rw-r--r--chromium/net/third_party/quiche/src/http2/adapter/nghttp2_session.h4
-rw-r--r--chromium/net/third_party/quiche/src/http2/adapter/nghttp2_session_test.cc24
-rw-r--r--chromium/net/third_party/quiche/src/http2/adapter/nghttp2_test_utils.h1
-rw-r--r--chromium/net/third_party/quiche/src/http2/adapter/nghttp2_util.cc5
-rw-r--r--chromium/net/third_party/quiche/src/http2/adapter/oghttp2_adapter.cc9
-rw-r--r--chromium/net/third_party/quiche/src/http2/adapter/oghttp2_adapter.h11
-rw-r--r--chromium/net/third_party/quiche/src/http2/adapter/oghttp2_adapter_test.cc650
-rw-r--r--chromium/net/third_party/quiche/src/http2/adapter/oghttp2_session.cc303
-rw-r--r--chromium/net/third_party/quiche/src/http2/adapter/oghttp2_session.h84
-rw-r--r--chromium/net/third_party/quiche/src/http2/adapter/oghttp2_session_test.cc35
-rw-r--r--chromium/net/third_party/quiche/src/http2/adapter/recording_http2_visitor.cc41
-rw-r--r--chromium/net/third_party/quiche/src/http2/adapter/recording_http2_visitor.h26
-rw-r--r--chromium/net/third_party/quiche/src/http2/adapter/recording_http2_visitor_test.cc5
-rw-r--r--chromium/net/third_party/quiche/src/http2/adapter/test_frame_sequence.cc29
-rw-r--r--chromium/net/third_party/quiche/src/http2/adapter/test_frame_sequence.h9
-rw-r--r--chromium/net/third_party/quiche/src/http2/adapter/test_utils.cc12
-rw-r--r--chromium/net/third_party/quiche/src/http2/adapter/test_utils.h32
-rw-r--r--chromium/net/third_party/quiche/src/http2/adapter/window_manager.h2
-rw-r--r--chromium/net/third_party/quiche/src/http2/core/http2_trace_logging.cc454
-rw-r--r--chromium/net/third_party/quiche/src/http2/core/http2_trace_logging.h140
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder.h5
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_state.h5
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_state_test.cc3
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_test.cc5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.cc107
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.h85
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler_test.cc46
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.cc18
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.h51
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_bw.cc118
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_bw.h1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_sender.cc60
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_simulator_test.cc513
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_startup.cc12
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.cc11
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.h6
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender_test.cc40
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/pacing_sender.cc3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_test.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/windowed_filter.h4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h39
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils.cc29
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils.h10
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils_test.cc57
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/proof_source.h18
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/proof_source_x509.cc18
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/proof_source_x509.h7
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/proof_source_x509_test.cc22
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_proof.cc3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_proof.h3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.cc29
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h9
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/tls_client_connection.cc4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/tls_connection.cc10
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/tls_connection.h11
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/tls_server_connection.cc8
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.cc676
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters_test.cc46
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_frames_test.cc3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_rst_stream_frame.cc13
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_rst_stream_frame.h14
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_stop_sending_frame.cc11
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_stop_sending_frame.h7
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/capsule.cc629
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/capsule.h254
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/capsule_test.cc330
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/end_to_end_test.cc363
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/http_constants.cc3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/http_constants.h6
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/http_decoder.cc155
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/http_decoder.h11
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/http_decoder_test.cc34
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_client_promised_info.h3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream.cc1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream_test.cc47
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base.cc10
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base_test.cc5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session.cc3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream.cc14
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream.h3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_server_stream_base.cc5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_server_stream_base.h4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_server_stream_base_test.cc22
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.cc255
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.h92
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session_test.cc278
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.cc518
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.h80
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_test.cc298
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/web_transport_http3.cc218
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/web_transport_http3.h64
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/web_transport_http3_test.cc52
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/web_transport_stream_adapter.cc (renamed from chromium/net/third_party/quiche/src/quic/core/web_transport_stream_adapter.cc)20
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/web_transport_stream_adapter.h (renamed from chromium/net/third_party/quiche/src/quic/core/web_transport_stream_adapter.h)6
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator.cc4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator.h7
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator_test.cc20
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test.cc109
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.cc158
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.h22
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_receive_stream.cc3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_send_stream.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_send_stream.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_send_stream_test.cc3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_alarm.cc25
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_alarm.h30
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_alarm_test.cc114
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_buffered_packet_store.cc5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_connection.cc245
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_connection.h20
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_connection_id_manager.cc41
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_connection_id_manager.h14
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_connection_id_manager_test.cc16
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_connection_test.cc348
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_constants.h6
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager.cc17
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager.h9
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager_test.cc16
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.h7
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker_test.cc8
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.cc18
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h25
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.cc6
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_base.h11
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.cc14
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.h16
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream_test.cc7
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_datagram_queue.cc1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.cc149
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.h14
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_dispatcher_test.cc187
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_epoll_alarm_factory_test.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_error_codes.cc17
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_error_codes.h48
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_flags_list.h82
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_framer.cc189
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_framer.h9
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_framer_test.cc1029
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_idle_network_detector.cc23
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_idle_network_detector.h9
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_idle_network_detector_test.cc23
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_mtu_discovery.h6
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_network_blackhole_detector.cc16
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_network_blackhole_detector.h6
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_network_blackhole_detector_test.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_one_block_arena.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.cc13
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_packet_creator_test.cc6
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_path_validator.cc16
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_path_validator.h8
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_path_validator_test.cc9
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_protocol_flags_list.h31
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_received_packet_manager_test.cc1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.cc4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_session.cc215
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_session.h82
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_session_test.cc230
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_stream.cc170
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_stream.h131
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_stream_send_buffer.cc5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_stream_send_buffer.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_stream_send_buffer_test.cc20
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer.cc3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_buffer.cc34
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_buffer.h7
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_buffer_test.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_test.cc5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_stream_test.cc210
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_time.cc4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_time_test.cc3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.cc47
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.h20
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager_test.cc54
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_types.h37
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map.cc8
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_version_manager.cc34
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_version_manager.h30
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_version_manager_test.cc7
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_chlo_extractor.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.cc18
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.h7
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_handshaker.cc17
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_handshaker.h3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.cc146
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.h50
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker_test.cc38
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager_test.cc1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/web_transport_interface.h27
-rw-r--r--chromium/net/third_party/quiche/src/quic/masque/masque_client_session.cc98
-rw-r--r--chromium/net/third_party/quiche/src/quic/masque/masque_client_session.h20
-rw-r--r--chromium/net/third_party/quiche/src/quic/masque/masque_epoll_client.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/masque/masque_server_session.cc110
-rw-r--r--chromium/net/third_party/quiche/src/quic/masque/masque_server_session.h22
-rw-r--r--chromium/net/third_party/quiche/src/quic/masque/masque_utils.h5
-rw-r--r--chromium/net/third_party/quiche/src/quic/platform/api/quic_containers.h4
-rw-r--r--chromium/net/third_party/quiche/src/quic/platform/api/quic_mem_slice_span.h59
-rw-r--r--chromium/net/third_party/quiche/src/quic/platform/api/quic_mem_slice_span_test.cc47
-rw-r--r--chromium/net/third_party/quiche/src/quic/platform/api/quic_mem_slice_storage.cc35
-rw-r--r--chromium/net/third_party/quiche/src/quic/platform/api/quic_mem_slice_storage.h20
-rw-r--r--chromium/net/third_party/quiche/src/quic/platform/api/quic_mem_slice_storage_test.cc29
-rw-r--r--chromium/net/third_party/quiche/src/quic/platform/api/quic_socket_address.cc24
-rw-r--r--chromium/net/third_party/quiche/src/quic/platform/api/quic_socket_address.h10
-rw-r--r--chromium/net/third_party/quiche/src/quic/platform/api/quic_test.h1
-rw-r--r--chromium/net/third_party/quiche/src/quic/platform/api/quic_test_mem_slice_vector.h35
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device.cc38
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device.h14
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_interface.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger.cc178
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger.h21
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger_test.cc8
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_test.cc20
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/platform/icmp_packet.cc5
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/platform/icmp_packet_test.cc4
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/platform/netlink.cc15
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/platform/netlink_test.cc22
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/qbone_constants.cc11
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/qbone_constants.h3
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/qbone_session_test.cc12
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/qbone_stream_test.cc35
-rw-r--r--chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_client_session.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_client_session.h12
-rw-r--r--chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_client_session_test.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_integration_test.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_stream.h9
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/crypto_test_utils.cc16
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/failing_proof_source.cc4
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/failing_proof_source.h4
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/fake_proof_source.cc7
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/fake_proof_source.h4
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/fake_proof_source_handle.cc19
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_time_wait_list_manager.cc4
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_time_wait_list_manager.h10
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/packet_dropping_test_writer.cc4
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_decoder_test_utils.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_decoder_test_utils.h12
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.cc7
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h3
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/quic_dispatcher_peer.cc6
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/quic_dispatcher_peer.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/quic_spdy_session_peer.cc28
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/quic_spdy_session_peer.h17
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/quic_stream_sequencer_buffer_peer.cc3
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/quic_test_backend.cc75
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.cc14
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.h961
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/quic_time_wait_list_manager_peer.cc6
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/quic_time_wait_list_manager_peer.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/quic_transport_test_tools.h10
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier.cc38
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier.h6
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/simulator/queue.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/simulator/simulator.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/simulator/simulator_test.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/web_transport_resets_backend.cc113
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/web_transport_resets_backend.h23
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend_test.cc44
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_simple_client_session.cc5
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_simple_client_session.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session.cc32
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session.h8
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream.cc6
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream.h1
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream_test.cc110
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/web_transport_test_visitors.h37
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_decoder_adapter.cc10
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_decoder_adapter.h8
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_decoder_adapter_test.cc65
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_encoder.cc25
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_encoder.h12
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_encoder_test.cc39
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_output_stream.cc17
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_output_stream.h8
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_output_stream_test.cc22
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_round_trip_test.cc5
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/http2_frame_decoder_adapter.cc2
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/metadata_extension.cc4
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/metadata_extension_test.cc10
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/spdy_alt_svc_wire_format.cc21
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/spdy_alt_svc_wire_format.h10
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/spdy_alt_svc_wire_format_test.cc37
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/spdy_framer.cc11
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/spdy_framer_test.cc6
310 files changed, 12454 insertions, 4805 deletions
diff --git a/chromium/net/third_party/quiche/BUILD.gn b/chromium/net/third_party/quiche/BUILD.gn
index eb544f93d1c..a67f5d549cd 100644
--- a/chromium/net/third_party/quiche/BUILD.gn
+++ b/chromium/net/third_party/quiche/BUILD.gn
@@ -56,7 +56,27 @@ source_set("quiche") {
"src/common/quiche_linked_hash_map.h",
"src/common/quiche_text_utils.cc",
"src/common/quiche_text_utils.h",
+ "src/http2/adapter/data_source.h",
+ "src/http2/adapter/header_validator.cc",
+ "src/http2/adapter/header_validator.h",
+ "src/http2/adapter/http2_adapter.h",
+ "src/http2/adapter/http2_protocol.cc",
+ "src/http2/adapter/http2_protocol.h",
+ "src/http2/adapter/http2_session.h",
+ "src/http2/adapter/http2_util.cc",
+ "src/http2/adapter/http2_util.h",
+ "src/http2/adapter/http2_visitor_interface.h",
+ "src/http2/adapter/oghttp2_adapter.cc",
+ "src/http2/adapter/oghttp2_adapter.h",
+ "src/http2/adapter/oghttp2_session.cc",
+ "src/http2/adapter/oghttp2_session.h",
+ "src/http2/adapter/oghttp2_util.cc",
+ "src/http2/adapter/oghttp2_util.h",
+ "src/http2/adapter/window_manager.cc",
+ "src/http2/adapter/window_manager.h",
"src/http2/core/http2_priority_write_scheduler.h",
+ "src/http2/core/http2_trace_logging.cc",
+ "src/http2/core/http2_trace_logging.h",
"src/http2/core/priority_write_scheduler.h",
"src/http2/core/write_scheduler.h",
"src/http2/decoder/decode_buffer.cc",
@@ -327,6 +347,8 @@ source_set("quiche") {
"src/quic/core/frames/quic_window_update_frame.cc",
"src/quic/core/frames/quic_window_update_frame.h",
"src/quic/core/handshaker_delegate_interface.h",
+ "src/quic/core/http/capsule.cc",
+ "src/quic/core/http/capsule.h",
"src/quic/core/http/http_constants.cc",
"src/quic/core/http/http_constants.h",
"src/quic/core/http/http_decoder.cc",
@@ -368,6 +390,8 @@ source_set("quiche") {
"src/quic/core/http/spdy_utils.h",
"src/quic/core/http/web_transport_http3.cc",
"src/quic/core/http/web_transport_http3.h",
+ "src/quic/core/http/web_transport_stream_adapter.cc",
+ "src/quic/core/http/web_transport_stream_adapter.h",
"src/quic/core/legacy_quic_stream_id_manager.cc",
"src/quic/core/legacy_quic_stream_id_manager.h",
"src/quic/core/packet_number_indexed_queue.h",
@@ -551,8 +575,6 @@ source_set("quiche") {
"src/quic/core/uber_quic_stream_id_manager.h",
"src/quic/core/uber_received_packet_manager.cc",
"src/quic/core/uber_received_packet_manager.h",
- "src/quic/core/web_transport_stream_adapter.cc",
- "src/quic/core/web_transport_stream_adapter.h",
"src/quic/platform/api/quic_bug_tracker.h",
"src/quic/platform/api/quic_client_stats.h",
"src/quic/platform/api/quic_containers.h",
@@ -569,7 +591,7 @@ source_set("quiche") {
"src/quic/platform/api/quic_ip_address_family.h",
"src/quic/platform/api/quic_logging.h",
"src/quic/platform/api/quic_mem_slice.h",
- "src/quic/platform/api/quic_mem_slice_span.h",
+ "src/quic/platform/api/quic_mem_slice_storage.cc",
"src/quic/platform/api/quic_mem_slice_storage.h",
"src/quic/platform/api/quic_mutex.cc",
"src/quic/platform/api/quic_mutex.h",
@@ -892,7 +914,6 @@ source_set("quic_test_tools_core") {
"src/quic/platform/api/quic_test.h",
"src/quic/platform/api/quic_test_loopback.cc",
"src/quic/platform/api/quic_test_loopback.h",
- "src/quic/platform/api/quic_test_mem_slice_vector.h",
"src/quic/platform/api/quic_test_output.h",
"src/quic/test_tools/crypto_test_utils.cc",
"src/quic/test_tools/crypto_test_utils.h",
@@ -1011,6 +1032,8 @@ source_set("quic_test_tools_core") {
"src/quic/test_tools/simulator/traffic_policer.h",
"src/quic/test_tools/test_certificates.cc",
"src/quic/test_tools/test_certificates.h",
+ "src/quic/test_tools/web_transport_resets_backend.cc",
+ "src/quic/test_tools/web_transport_resets_backend.h",
"src/quic/tools/quic_tcp_like_trace_converter.cc",
"src/quic/tools/quic_tcp_like_trace_converter.h",
]
@@ -1207,6 +1230,14 @@ source_set("quiche_tests") {
"src/common/quiche_endian_test.cc",
"src/common/quiche_linked_hash_map_test.cc",
"src/common/quiche_text_utils_test.cc",
+ "src/http2/adapter/header_validator_test.cc",
+ "src/http2/adapter/oghttp2_adapter_test.cc",
+ "src/http2/adapter/oghttp2_session_test.cc",
+ "src/http2/adapter/test_frame_sequence.cc",
+ "src/http2/adapter/test_frame_sequence.h",
+ "src/http2/adapter/test_utils.cc",
+ "src/http2/adapter/test_utils.h",
+ "src/http2/adapter/window_manager_test.cc",
"src/http2/core/http2_priority_write_scheduler_test.cc",
"src/http2/core/priority_write_scheduler_test.cc",
"src/http2/decoder/decode_buffer_test.cc",
@@ -1326,6 +1357,7 @@ source_set("quiche_tests") {
"src/quic/core/crypto/quic_random_test.cc",
"src/quic/core/crypto/transport_parameters_test.cc",
"src/quic/core/frames/quic_frames_test.cc",
+ "src/quic/core/http/capsule_test.cc",
"src/quic/core/http/http_decoder_test.cc",
"src/quic/core/http/http_encoder_test.cc",
"src/quic/core/http/http_frames_test.cc",
@@ -1423,7 +1455,6 @@ source_set("quiche_tests") {
"src/quic/core/uber_received_packet_manager_test.cc",
"src/quic/platform/api/quic_hostname_utils_test.cc",
"src/quic/platform/api/quic_ip_address_test.cc",
- "src/quic/platform/api/quic_mem_slice_span_test.cc",
"src/quic/platform/api/quic_mem_slice_storage_test.cc",
"src/quic/platform/api/quic_mem_slice_test.cc",
"src/quic/platform/api/quic_reference_counted_test.cc",
diff --git a/chromium/net/third_party/quiche/overrides/quiche_platform_impl/quic_mutex_impl.h b/chromium/net/third_party/quiche/overrides/quiche_platform_impl/quic_mutex_impl.h
index 83236b6e30a..8a897536e10 100644
--- a/chromium/net/third_party/quiche/overrides/quiche_platform_impl/quic_mutex_impl.h
+++ b/chromium/net/third_party/quiche/overrides/quiche_platform_impl/quic_mutex_impl.h
@@ -64,6 +64,9 @@ class QUIC_LOCKABLE_IMPL QUIC_EXPORT_PRIVATE QuicLockImpl {
public:
QuicLockImpl() = default;
+ QuicLockImpl(const QuicLockImpl&) = delete;
+ QuicLockImpl& operator=(const QuicLockImpl&) = delete;
+
// Block until lock_ is free, then acquire it exclusively.
void WriterLock() EXCLUSIVE_LOCK_FUNCTION();
@@ -81,8 +84,6 @@ class QUIC_LOCKABLE_IMPL QUIC_EXPORT_PRIVATE QuicLockImpl {
private:
base::Lock lock_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicLockImpl);
};
// A Notification allows threads to receive notification of a single occurrence
diff --git a/chromium/net/third_party/quiche/src/README.md b/chromium/net/third_party/quiche/src/README.md
index 60f24da2b09..1a3502f12ac 100644
--- a/chromium/net/third_party/quiche/src/README.md
+++ b/chromium/net/third_party/quiche/src/README.md
@@ -25,4 +25,7 @@ Envoy to get started:
* [Platform implementations in Envoy](https://github.com/envoyproxy/envoy/tree/master/source/common/quic/platform)
* [Build file in Envoy](https://github.com/envoyproxy/envoy/blob/main/bazel/external/quiche.BUILD)
+To contribute to QUICHE, follow instructions at
+[CONTRIBUTING.md](CONTRIBUTING.md).
+
QUICHE is only supported on little-endian platforms.
diff --git a/chromium/net/third_party/quiche/src/common/platform/default/quiche_platform_impl/quiche_containers_impl.h b/chromium/net/third_party/quiche/src/common/platform/default/quiche_platform_impl/quiche_containers_impl.h
new file mode 100644
index 00000000000..56ce474b540
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/common/platform/default/quiche_platform_impl/quiche_containers_impl.h
@@ -0,0 +1,22 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_COMMON_PLATFORM_DEFAULT_QUICHE_PLATFORM_IMPL_QUICHE_CONTAINERS_IMPL_H_
+#define QUICHE_COMMON_PLATFORM_DEFAULT_QUICHE_PLATFORM_IMPL_QUICHE_CONTAINERS_IMPL_H_
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Weverything"
+
+#include "absl/container/btree_set.h"
+
+#pragma clang diagnostic pop
+
+namespace quiche {
+
+template <typename Key, typename Compare>
+using QuicheSmallOrderedSetImpl = absl::btree_set<Key, Compare>;
+
+} // namespace quiche
+
+#endif // QUICHE_COMMON_PLATFORM_DEFAULT_QUICHE_PLATFORM_IMPL_QUICHE_CONTAINERS_IMPL_H_
diff --git a/chromium/net/third_party/quiche/src/common/print_elements.h b/chromium/net/third_party/quiche/src/common/print_elements.h
index f241a4b9509..7a0997f4ba3 100644
--- a/chromium/net/third_party/quiche/src/common/print_elements.h
+++ b/chromium/net/third_party/quiche/src/common/print_elements.h
@@ -20,11 +20,13 @@ QUICHE_EXPORT_PRIVATE inline std::string PrintElements(const T& container) {
std::stringstream debug_string;
debug_string << "{";
auto it = container.cbegin();
- debug_string << *it;
- ++it;
- while (it != container.cend()) {
- debug_string << ", " << *it;
+ if (it != container.cend()) {
+ debug_string << *it;
++it;
+ while (it != container.cend()) {
+ debug_string << ", " << *it;
+ ++it;
+ }
}
debug_string << "}";
return debug_string.str();
diff --git a/chromium/net/third_party/quiche/src/http2/adapter/callback_visitor.cc b/chromium/net/third_party/quiche/src/http2/adapter/callback_visitor.cc
index 4381749d430..becf5bf4133 100644
--- a/chromium/net/third_party/quiche/src/http2/adapter/callback_visitor.cc
+++ b/chromium/net/third_party/quiche/src/http2/adapter/callback_visitor.cc
@@ -1,5 +1,6 @@
#include "http2/adapter/callback_visitor.h"
+#include "absl/strings/escaping.h"
#include "http2/adapter/nghttp2_util.h"
#include "third_party/nghttp2/src/lib/includes/nghttp2/nghttp2.h"
#include "common/quiche_endian.h"
@@ -48,13 +49,16 @@ CallbackVisitor::CallbackVisitor(Perspective perspective,
callbacks_ = MakeCallbacksPtr(c);
}
-ssize_t CallbackVisitor::OnReadyToSend(absl::string_view serialized) {
+int64_t CallbackVisitor::OnReadyToSend(absl::string_view serialized) {
if (!callbacks_->send_callback) {
return kSendError;
}
- ssize_t result = callbacks_->send_callback(
+ int64_t result = callbacks_->send_callback(
nullptr, ToUint8Ptr(serialized.data()), serialized.size(), 0, user_data_);
- QUICHE_VLOG(1) << "CallbackVisitor::OnReadyToSend returning " << result;
+ QUICHE_VLOG(1) << "CallbackVisitor::OnReadyToSend called with "
+ << serialized.size() << " bytes, returning " << result;
+ QUICHE_VLOG(2) << (perspective_ == Perspective::kClient ? "Client" : "Server")
+ << " sending: [" << absl::CEscape(serialized) << "]";
if (result > 0) {
return result;
} else if (result == NGHTTP2_ERR_WOULDBLOCK) {
@@ -68,13 +72,11 @@ void CallbackVisitor::OnConnectionError() {
QUICHE_LOG(ERROR) << "OnConnectionError not implemented";
}
-void CallbackVisitor::OnFrameHeader(Http2StreamId stream_id,
- size_t length,
- uint8_t type,
- uint8_t flags) {
- QUICHE_VLOG(1) << "CallbackVisitor::OnFrameHeader(stream_id: " << stream_id
- << ", len: " << length << ", type: " << int(type)
- << ", flags: " << int(flags) << ")";
+bool CallbackVisitor::OnFrameHeader(Http2StreamId stream_id, size_t length,
+ uint8_t type, uint8_t flags) {
+ QUICHE_VLOG(1) << "CallbackVisitor::OnFrameHeader(stream_id=" << stream_id
+ << ", type=" << int(type) << ", length=" << length
+ << ", flags=" << int(flags) << ")";
if (static_cast<FrameType>(type) == FrameType::CONTINUATION) {
// Treat CONTINUATION as HEADERS
QUICHE_DCHECK_EQ(current_frame_.hd.stream_id, stream_id);
@@ -89,9 +91,11 @@ void CallbackVisitor::OnFrameHeader(Http2StreamId stream_id,
hd.type = type;
hd.flags = flags;
if (callbacks_->on_begin_frame_callback) {
- callbacks_->on_begin_frame_callback(nullptr, &hd, user_data_);
+ const int result =
+ callbacks_->on_begin_frame_callback(nullptr, &hd, user_data_);
+ return result == 0;
}
- return;
+ return true;
}
// The general strategy is to clear |current_frame_| at the start of a new
// frame, accumulate frame information from the various callback events, then
@@ -102,15 +106,17 @@ void CallbackVisitor::OnFrameHeader(Http2StreamId stream_id,
current_frame_.hd.type = type;
current_frame_.hd.flags = flags;
if (callbacks_->on_begin_frame_callback) {
- callbacks_->on_begin_frame_callback(nullptr, &current_frame_.hd,
- user_data_);
+ const int result = callbacks_->on_begin_frame_callback(
+ nullptr, &current_frame_.hd, user_data_);
+ return result == 0;
}
+ return true;
}
void CallbackVisitor::OnSettingsStart() {}
void CallbackVisitor::OnSetting(Http2Setting setting) {
- settings_.push_back({.settings_id = setting.id, .value = setting.value});
+ settings_.push_back({setting.id, setting.value});
}
void CallbackVisitor::OnSettingsEnd() {
@@ -119,7 +125,9 @@ void CallbackVisitor::OnSettingsEnd() {
QUICHE_VLOG(1) << "OnSettingsEnd, received settings of size "
<< current_frame_.settings.niv;
if (callbacks_->on_frame_recv_callback) {
- callbacks_->on_frame_recv_callback(nullptr, &current_frame_, user_data_);
+ const int result = callbacks_->on_frame_recv_callback(
+ nullptr, &current_frame_, user_data_);
+ QUICHE_DCHECK_EQ(0, result);
}
settings_.clear();
}
@@ -127,7 +135,9 @@ void CallbackVisitor::OnSettingsEnd() {
void CallbackVisitor::OnSettingsAck() {
// ACK is part of the flags, which were set in OnFrameHeader().
if (callbacks_->on_frame_recv_callback) {
- callbacks_->on_frame_recv_callback(nullptr, &current_frame_, user_data_);
+ const int result = callbacks_->on_frame_recv_callback(
+ nullptr, &current_frame_, user_data_);
+ QUICHE_DCHECK_EQ(0, result);
}
}
@@ -182,35 +192,43 @@ Http2VisitorInterface::OnHeaderResult CallbackVisitor::OnHeaderForStream(
return HEADER_OK;
}
-void CallbackVisitor::OnEndHeadersForStream(Http2StreamId /*stream_id*/) {
+bool CallbackVisitor::OnEndHeadersForStream(Http2StreamId /*stream_id*/) {
if (callbacks_->on_frame_recv_callback) {
const int result = callbacks_->on_frame_recv_callback(
nullptr, &current_frame_, user_data_);
- QUICHE_DCHECK_EQ(0, result);
+ return result == 0;
}
+ return true;
}
-void CallbackVisitor::OnBeginDataForStream(Http2StreamId /*stream_id*/,
+bool CallbackVisitor::OnBeginDataForStream(Http2StreamId /*stream_id*/,
size_t payload_length) {
// TODO(b/181586191): Interpret padding, subtract padding from
// |remaining_data_|.
remaining_data_ = payload_length;
if (remaining_data_ == 0 && callbacks_->on_frame_recv_callback) {
- callbacks_->on_frame_recv_callback(nullptr, &current_frame_, user_data_);
+ const int result = callbacks_->on_frame_recv_callback(
+ nullptr, &current_frame_, user_data_);
+ return result == 0;
}
+ return true;
}
-void CallbackVisitor::OnDataForStream(Http2StreamId stream_id,
+bool CallbackVisitor::OnDataForStream(Http2StreamId stream_id,
absl::string_view data) {
+ int result = 0;
if (callbacks_->on_data_chunk_recv_callback) {
- callbacks_->on_data_chunk_recv_callback(nullptr, current_frame_.hd.flags,
- stream_id, ToUint8Ptr(data.data()),
- data.size(), user_data_);
+ result = callbacks_->on_data_chunk_recv_callback(
+ nullptr, current_frame_.hd.flags, stream_id, ToUint8Ptr(data.data()),
+ data.size(), user_data_);
}
remaining_data_ -= data.size();
- if (remaining_data_ == 0 && callbacks_->on_frame_recv_callback) {
- callbacks_->on_frame_recv_callback(nullptr, &current_frame_, user_data_);
+ if (result == 0 && remaining_data_ == 0 &&
+ callbacks_->on_frame_recv_callback) {
+ result = callbacks_->on_frame_recv_callback(nullptr, &current_frame_,
+ user_data_);
}
+ return result == 0;
}
void CallbackVisitor::OnEndStream(Http2StreamId /*stream_id*/) {}
@@ -219,7 +237,9 @@ void CallbackVisitor::OnRstStream(Http2StreamId /*stream_id*/,
Http2ErrorCode error_code) {
current_frame_.rst_stream.error_code = static_cast<uint32_t>(error_code);
if (callbacks_->on_frame_recv_callback) {
- callbacks_->on_frame_recv_callback(nullptr, &current_frame_, user_data_);
+ const int result = callbacks_->on_frame_recv_callback(
+ nullptr, &current_frame_, user_data_);
+ QUICHE_DCHECK_EQ(0, result);
}
}
@@ -240,7 +260,9 @@ void CallbackVisitor::OnPriorityForStream(Http2StreamId /*stream_id*/,
current_frame_.priority.pri_spec.weight = weight;
current_frame_.priority.pri_spec.exclusive = exclusive;
if (callbacks_->on_frame_recv_callback) {
- callbacks_->on_frame_recv_callback(nullptr, &current_frame_, user_data_);
+ const int result = callbacks_->on_frame_recv_callback(
+ nullptr, &current_frame_, user_data_);
+ QUICHE_DCHECK_EQ(0, result);
}
}
@@ -250,7 +272,9 @@ void CallbackVisitor::OnPing(Http2PingId ping_id, bool /*is_ack*/) {
std::memcpy(current_frame_.ping.opaque_data, &network_order_opaque_data,
sizeof(network_order_opaque_data));
if (callbacks_->on_frame_recv_callback) {
- callbacks_->on_frame_recv_callback(nullptr, &current_frame_, user_data_);
+ const int result = callbacks_->on_frame_recv_callback(
+ nullptr, &current_frame_, user_data_);
+ QUICHE_DCHECK_EQ(0, result);
}
}
@@ -259,7 +283,7 @@ void CallbackVisitor::OnPushPromiseForStream(
QUICHE_LOG(DFATAL) << "Not implemented";
}
-void CallbackVisitor::OnGoAway(Http2StreamId last_accepted_stream_id,
+bool CallbackVisitor::OnGoAway(Http2StreamId last_accepted_stream_id,
Http2ErrorCode error_code,
absl::string_view opaque_data) {
current_frame_.goaway.last_stream_id = last_accepted_stream_id;
@@ -267,15 +291,20 @@ void CallbackVisitor::OnGoAway(Http2StreamId last_accepted_stream_id,
current_frame_.goaway.opaque_data = ToUint8Ptr(opaque_data.data());
current_frame_.goaway.opaque_data_len = opaque_data.size();
if (callbacks_->on_frame_recv_callback) {
- callbacks_->on_frame_recv_callback(nullptr, &current_frame_, user_data_);
+ const int result = callbacks_->on_frame_recv_callback(
+ nullptr, &current_frame_, user_data_);
+ return result == 0;
}
+ return true;
}
void CallbackVisitor::OnWindowUpdate(Http2StreamId /*stream_id*/,
int window_increment) {
current_frame_.window_update.window_size_increment = window_increment;
if (callbacks_->on_frame_recv_callback) {
- callbacks_->on_frame_recv_callback(nullptr, &current_frame_, user_data_);
+ const int result = callbacks_->on_frame_recv_callback(
+ nullptr, &current_frame_, user_data_);
+ QUICHE_DCHECK_EQ(0, result);
}
}
@@ -316,8 +345,8 @@ int CallbackVisitor::OnBeforeFrameSent(uint8_t frame_type,
Http2StreamId stream_id, size_t length,
uint8_t flags) {
if (callbacks_->before_frame_send_callback) {
- QUICHE_VLOG(1) << "OnBeforeFrameSent(type=" << int(frame_type)
- << ", stream_id=" << stream_id << ", length=" << length
+ QUICHE_VLOG(1) << "OnBeforeFrameSent(stream_id=" << stream_id
+ << ", type=" << int(frame_type) << ", length=" << length
<< ", flags=" << int(flags) << ")";
nghttp2_frame frame;
auto it = GetStreamInfo(stream_id);
@@ -335,8 +364,8 @@ int CallbackVisitor::OnFrameSent(uint8_t frame_type, Http2StreamId stream_id,
size_t length, uint8_t flags,
uint32_t error_code) {
if (callbacks_->on_frame_send_callback) {
- QUICHE_VLOG(1) << "OnFrameSent(type=" << int(frame_type)
- << ", stream_id=" << stream_id << ", length=" << length
+ QUICHE_VLOG(1) << "OnFrameSent(stream_id=" << stream_id
+ << ", type=" << int(frame_type) << ", length=" << length
<< ", flags=" << int(flags) << ", error_code=" << error_code
<< ")";
nghttp2_frame frame;
@@ -349,14 +378,6 @@ int CallbackVisitor::OnFrameSent(uint8_t frame_type, Http2StreamId stream_id,
return 0;
}
-void CallbackVisitor::OnReadyToSendDataForStream(Http2StreamId /*stream_id*/,
- char* /*destination_buffer*/,
- size_t /*length*/,
- ssize_t* /*written*/,
- bool* /*end_stream*/) {
- QUICHE_LOG(DFATAL) << "Not implemented";
-}
-
bool CallbackVisitor::OnInvalidFrame(Http2StreamId stream_id, int error_code) {
QUICHE_VLOG(1) << "OnInvalidFrame(" << stream_id << ", " << error_code << ")";
QUICHE_DCHECK_EQ(stream_id, current_frame_.hd.stream_id);
@@ -367,30 +388,13 @@ bool CallbackVisitor::OnInvalidFrame(Http2StreamId stream_id, int error_code) {
return true;
}
-void CallbackVisitor::OnReadyToSendMetadataForStream(Http2StreamId stream_id,
- char* buffer,
- size_t length,
- ssize_t* written) {
- if (callbacks_->pack_extension_callback) {
- nghttp2_frame frame;
- frame.hd.type = kMetadataFrameType;
- frame.hd.stream_id = stream_id;
- frame.hd.flags = 0;
- frame.hd.length = 0;
- *written = callbacks_->pack_extension_callback(nullptr, ToUint8Ptr(buffer),
- length, &frame, user_data_);
- }
- QUICHE_VLOG(1) << "OnReadyToSendMetadataForStream(stream_id=" << stream_id
- << ", length=" << length << ", written=" << *written << ")";
-}
-
void CallbackVisitor::OnBeginMetadataForStream(Http2StreamId stream_id,
size_t payload_length) {
QUICHE_VLOG(1) << "OnBeginMetadataForStream(stream_id=" << stream_id
<< ", payload_length=" << payload_length << ")";
}
-void CallbackVisitor::OnMetadataForStream(Http2StreamId stream_id,
+bool CallbackVisitor::OnMetadataForStream(Http2StreamId stream_id,
absl::string_view metadata) {
QUICHE_VLOG(1) << "OnMetadataForStream(stream_id=" << stream_id
<< ", len=" << metadata.size() << ")";
@@ -398,8 +402,9 @@ void CallbackVisitor::OnMetadataForStream(Http2StreamId stream_id,
int result = callbacks_->on_extension_chunk_recv_callback(
nullptr, &current_frame_.hd, ToUint8Ptr(metadata.data()),
metadata.size(), user_data_);
- QUICHE_DCHECK_EQ(0, result);
+ return result == 0;
}
+ return true;
}
bool CallbackVisitor::OnMetadataEndForStream(Http2StreamId stream_id) {
@@ -409,9 +414,10 @@ bool CallbackVisitor::OnMetadataEndForStream(Http2StreamId stream_id) {
void* payload;
int result = callbacks_->unpack_extension_callback(
nullptr, &payload, &current_frame_.hd, user_data_);
- if (callbacks_->on_frame_recv_callback) {
+ if (result == 0 && callbacks_->on_frame_recv_callback) {
current_frame_.ext.payload = payload;
- callbacks_->on_frame_recv_callback(nullptr, &current_frame_, user_data_);
+ result = callbacks_->on_frame_recv_callback(nullptr, &current_frame_,
+ user_data_);
}
return (result == 0);
}
diff --git a/chromium/net/third_party/quiche/src/http2/adapter/callback_visitor.h b/chromium/net/third_party/quiche/src/http2/adapter/callback_visitor.h
index b5afc83a103..f252989477b 100644
--- a/chromium/net/third_party/quiche/src/http2/adapter/callback_visitor.h
+++ b/chromium/net/third_party/quiche/src/http2/adapter/callback_visitor.h
@@ -1,6 +1,7 @@
#ifndef QUICHE_HTTP2_ADAPTER_CALLBACK_VISITOR_H_
#define QUICHE_HTTP2_ADAPTER_CALLBACK_VISITOR_H_
+#include <cstdint>
#include <memory>
#include <vector>
@@ -21,11 +22,9 @@ class QUICHE_EXPORT_PRIVATE CallbackVisitor : public Http2VisitorInterface {
const nghttp2_session_callbacks& callbacks,
void* user_data);
- ssize_t OnReadyToSend(absl::string_view serialized) override;
+ int64_t OnReadyToSend(absl::string_view serialized) override;
void OnConnectionError() override;
- void OnFrameHeader(Http2StreamId stream_id,
- size_t length,
- uint8_t type,
+ bool OnFrameHeader(Http2StreamId stream_id, size_t length, uint8_t type,
uint8_t flags) override;
void OnSettingsStart() override;
void OnSetting(Http2Setting setting) override;
@@ -35,10 +34,10 @@ class QUICHE_EXPORT_PRIVATE CallbackVisitor : public Http2VisitorInterface {
OnHeaderResult OnHeaderForStream(Http2StreamId stream_id,
absl::string_view name,
absl::string_view value) override;
- void OnEndHeadersForStream(Http2StreamId stream_id) override;
- void OnBeginDataForStream(Http2StreamId stream_id,
+ bool OnEndHeadersForStream(Http2StreamId stream_id) override;
+ bool OnBeginDataForStream(Http2StreamId stream_id,
size_t payload_length) override;
- void OnDataForStream(Http2StreamId stream_id,
+ bool OnDataForStream(Http2StreamId stream_id,
absl::string_view data) override;
void OnEndStream(Http2StreamId stream_id) override;
void OnRstStream(Http2StreamId stream_id, Http2ErrorCode error_code) override;
@@ -51,7 +50,7 @@ class QUICHE_EXPORT_PRIVATE CallbackVisitor : public Http2VisitorInterface {
void OnPing(Http2PingId ping_id, bool is_ack) override;
void OnPushPromiseForStream(Http2StreamId stream_id,
Http2StreamId promised_stream_id) override;
- void OnGoAway(Http2StreamId last_accepted_stream_id,
+ bool OnGoAway(Http2StreamId last_accepted_stream_id,
Http2ErrorCode error_code,
absl::string_view opaque_data) override;
void OnWindowUpdate(Http2StreamId stream_id, int window_increment) override;
@@ -59,19 +58,10 @@ class QUICHE_EXPORT_PRIVATE CallbackVisitor : public Http2VisitorInterface {
size_t length, uint8_t flags) override;
int OnFrameSent(uint8_t frame_type, Http2StreamId stream_id, size_t length,
uint8_t flags, uint32_t error_code) override;
- void OnReadyToSendDataForStream(Http2StreamId stream_id,
- char* destination_buffer,
- size_t length,
- ssize_t* written,
- bool* end_stream) override;
bool OnInvalidFrame(Http2StreamId stream_id, int error_code) override;
- void OnReadyToSendMetadataForStream(Http2StreamId stream_id,
- char* buffer,
- size_t length,
- ssize_t* written) override;
void OnBeginMetadataForStream(Http2StreamId stream_id,
size_t payload_length) override;
- void OnMetadataForStream(Http2StreamId stream_id,
+ bool OnMetadataForStream(Http2StreamId stream_id,
absl::string_view metadata) override;
bool OnMetadataEndForStream(Http2StreamId stream_id) override;
void OnErrorDebug(absl::string_view message) override;
diff --git a/chromium/net/third_party/quiche/src/http2/adapter/callback_visitor_test.cc b/chromium/net/third_party/quiche/src/http2/adapter/callback_visitor_test.cc
index 2cb31ed24f4..eaf3f980cc7 100644
--- a/chromium/net/third_party/quiche/src/http2/adapter/callback_visitor_test.cc
+++ b/chromium/net/third_party/quiche/src/http2/adapter/callback_visitor_test.cc
@@ -155,28 +155,6 @@ TEST(ClientCallbackVisitorUnitTest, StreamFrames) {
EXPECT_CALL(callbacks, OnStreamClose(5, NGHTTP2_REFUSED_STREAM));
visitor.OnCloseStream(5, Http2ErrorCode::REFUSED_STREAM);
-
- // Metadata events
- constexpr size_t kMetadataBufferSize = 256;
- char metadata_dest[kMetadataBufferSize];
- ssize_t written = 0;
-
- const absl::string_view kExampleFrame = "This is supposed to be metadata.";
- EXPECT_CALL(
- callbacks,
- OnPackExtension(_, kMetadataBufferSize,
- Field(&nghttp2_frame::hd,
- HasFrameHeaderRef(7, kMetadataFrameType, _))))
- .WillOnce(testing::Invoke(
- [kExampleFrame](uint8_t* buf, size_t /*len*/,
- const nghttp2_frame* /*frame*/) -> ssize_t {
- std::memcpy(buf, kExampleFrame.data(), kExampleFrame.size());
- return kExampleFrame.size();
- }));
- visitor.OnReadyToSendMetadataForStream(7, metadata_dest, kMetadataBufferSize,
- &written);
- ASSERT_EQ(written, kExampleFrame.size());
- EXPECT_EQ(absl::string_view(metadata_dest, written), kExampleFrame);
}
TEST(ClientCallbackVisitorUnitTest, HeadersWithContinuation) {
@@ -311,28 +289,6 @@ TEST(ServerCallbackVisitorUnitTest, StreamFrames) {
EXPECT_CALL(callbacks, OnStreamClose(3, NGHTTP2_INTERNAL_ERROR));
visitor.OnCloseStream(3, Http2ErrorCode::INTERNAL_ERROR);
-
- // Metadata events
- constexpr size_t kMetadataBufferSize = 256;
- char metadata_dest[kMetadataBufferSize];
- ssize_t written = 0;
-
- const absl::string_view kExampleFrame = "This is supposed to be metadata.";
- EXPECT_CALL(
- callbacks,
- OnPackExtension(_, kMetadataBufferSize,
- Field(&nghttp2_frame::hd,
- HasFrameHeaderRef(5, kMetadataFrameType, _))))
- .WillOnce(testing::Invoke(
- [kExampleFrame](uint8_t* buf, size_t /*len*/,
- const nghttp2_frame* /*frame*/) -> ssize_t {
- std::memcpy(buf, kExampleFrame.data(), kExampleFrame.size());
- return kExampleFrame.size();
- }));
- visitor.OnReadyToSendMetadataForStream(5, metadata_dest, kMetadataBufferSize,
- &written);
- ASSERT_EQ(written, kExampleFrame.size());
- EXPECT_EQ(absl::string_view(metadata_dest, written), kExampleFrame);
}
} // namespace
diff --git a/chromium/net/third_party/quiche/src/http2/adapter/data_source.h b/chromium/net/third_party/quiche/src/http2/adapter/data_source.h
index d86714148c3..63448b3e56e 100644
--- a/chromium/net/third_party/quiche/src/http2/adapter/data_source.h
+++ b/chromium/net/third_party/quiche/src/http2/adapter/data_source.h
@@ -1,6 +1,7 @@
#ifndef QUICHE_HTTP2_ADAPTER_DATA_SOURCE_H_
#define QUICHE_HTTP2_ADAPTER_DATA_SOURCE_H_
+#include <cstdint>
#include <string>
#include <utility>
@@ -15,12 +16,12 @@ class QUICHE_EXPORT_PRIVATE DataFrameSource {
public:
virtual ~DataFrameSource() {}
- enum : ssize_t { kBlocked = 0, kError = -1 };
+ enum : int64_t { kBlocked = 0, kError = -1 };
// Returns the number of bytes to send in the next DATA frame, and whether
// this frame indicates the end of the data. Returns {kBlocked, false} if
// blocked, {kError, false} on error.
- virtual std::pair<ssize_t, bool> SelectPayloadLength(size_t max_length) = 0;
+ virtual std::pair<int64_t, bool> SelectPayloadLength(size_t max_length) = 0;
// This method is called with a frame header and a payload length to send. The
// source should send or buffer the entire frame and return true, or return
@@ -37,11 +38,16 @@ class QUICHE_EXPORT_PRIVATE MetadataSource {
public:
virtual ~MetadataSource() {}
+ // Returns the number of frames of at most |max_frame_size| required to
+ // serialize the metadata for this source. Only required by the nghttp2
+ // implementation.
+ virtual size_t NumFrames(size_t max_frame_size) const = 0;
+
// This method is called with a destination buffer and length. It should
// return the number of payload bytes copied to |dest|, or a negative integer
// to indicate an error, as well as a boolean indicating whether the metadata
// has been completely copied.
- virtual std::pair<ssize_t, bool> Pack(uint8_t* dest, size_t dest_len) = 0;
+ virtual std::pair<int64_t, bool> Pack(uint8_t* dest, size_t dest_len) = 0;
};
} // namespace adapter
diff --git a/chromium/net/third_party/quiche/src/http2/adapter/header_validator.cc b/chromium/net/third_party/quiche/src/http2/adapter/header_validator.cc
new file mode 100644
index 00000000000..fef2e2cd343
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/http2/adapter/header_validator.cc
@@ -0,0 +1,99 @@
+#include "http2/adapter/header_validator.h"
+
+#include "absl/strings/escaping.h"
+#include "common/platform/api/quiche_logging.h"
+
+namespace http2 {
+namespace adapter {
+
+namespace {
+
+const absl::string_view kHttp2HeaderNameAllowedChars =
+ "!#$%&\'*+-.0123456789"
+ "^_`abcdefghijklmnopqrstuvwxyz|~";
+
+const absl::string_view kHttp2HeaderValueAllowedChars =
+ "\t "
+ "!\"#$%&'()*+,-./"
+ "0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`"
+ "abcdefghijklmnopqrstuvwxyz{|}~";
+
+const absl::string_view kHttp2StatusValueAllowedChars = "0123456789";
+
+// TODO(birenroy): Support websocket requests, which contain an extra
+// `:protocol` pseudo-header.
+bool ValidateRequestHeaders(const std::vector<std::string>& pseudo_headers) {
+ static const std::vector<std::string>* kRequiredHeaders =
+ new std::vector<std::string>(
+ {":authority", ":method", ":path", ":scheme"});
+ return pseudo_headers == *kRequiredHeaders;
+}
+
+bool ValidateResponseHeaders(const std::vector<std::string>& pseudo_headers) {
+ static const std::vector<std::string>* kRequiredHeaders =
+ new std::vector<std::string>({":status"});
+ return pseudo_headers == *kRequiredHeaders;
+}
+
+bool ValidateResponseTrailers(const std::vector<std::string>& pseudo_headers) {
+ return pseudo_headers.empty();
+}
+
+} // namespace
+
+void HeaderValidator::StartHeaderBlock() {
+ pseudo_headers_.clear();
+ status_.clear();
+}
+
+HeaderValidator::HeaderStatus HeaderValidator::ValidateSingleHeader(
+ absl::string_view key, absl::string_view value) {
+ if (key.empty()) {
+ return HEADER_NAME_EMPTY;
+ }
+ const absl::string_view validated_key = key[0] == ':' ? key.substr(1) : key;
+ if (validated_key.find_first_not_of(kHttp2HeaderNameAllowedChars) !=
+ absl::string_view::npos) {
+ QUICHE_VLOG(2) << "invalid chars in header name: ["
+ << absl::CEscape(validated_key) << "]";
+ return HEADER_NAME_INVALID_CHAR;
+ }
+ if (value.find_first_not_of(kHttp2HeaderValueAllowedChars) !=
+ absl::string_view::npos) {
+ QUICHE_VLOG(2) << "invalid chars in header value: [" << absl::CEscape(value)
+ << "]";
+ return HEADER_VALUE_INVALID_CHAR;
+ }
+ if (key[0] == ':') {
+ if (key == ":status") {
+ if (value.size() != 3 ||
+ value.find_first_not_of(kHttp2StatusValueAllowedChars) !=
+ absl::string_view::npos) {
+ QUICHE_VLOG(2) << "malformed status value: [" << absl::CEscape(value)
+ << "]";
+ return HEADER_VALUE_INVALID_CHAR;
+ }
+ status_ = std::string(value);
+ }
+ pseudo_headers_.push_back(std::string(key));
+ }
+ return HEADER_OK;
+}
+
+// Returns true if all required pseudoheaders and no extra pseudoheaders are
+// present for the given header type.
+bool HeaderValidator::FinishHeaderBlock(HeaderType type) {
+ std::sort(pseudo_headers_.begin(), pseudo_headers_.end());
+ switch (type) {
+ case HeaderType::REQUEST:
+ return ValidateRequestHeaders(pseudo_headers_);
+ case HeaderType::RESPONSE_100:
+ case HeaderType::RESPONSE:
+ return ValidateResponseHeaders(pseudo_headers_);
+ case HeaderType::RESPONSE_TRAILER:
+ return ValidateResponseTrailers(pseudo_headers_);
+ }
+}
+
+} // namespace adapter
+} // namespace http2
diff --git a/chromium/net/third_party/quiche/src/http2/adapter/header_validator.h b/chromium/net/third_party/quiche/src/http2/adapter/header_validator.h
new file mode 100644
index 00000000000..2d7585e1a05
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/http2/adapter/header_validator.h
@@ -0,0 +1,49 @@
+#ifndef QUICHE_HTTP2_ADAPTER_HEADER_VALIDATOR_H_
+#define QUICHE_HTTP2_ADAPTER_HEADER_VALIDATOR_H_
+
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "common/platform/api/quiche_export.h"
+
+namespace http2 {
+namespace adapter {
+
+enum class HeaderType : uint8_t {
+ REQUEST,
+ RESPONSE_100,
+ RESPONSE,
+ RESPONSE_TRAILER,
+};
+
+class QUICHE_EXPORT_PRIVATE HeaderValidator {
+ public:
+ HeaderValidator() {}
+
+ void StartHeaderBlock();
+
+ enum HeaderStatus {
+ HEADER_OK,
+ HEADER_NAME_EMPTY,
+ HEADER_NAME_INVALID_CHAR,
+ HEADER_VALUE_INVALID_CHAR,
+ };
+ HeaderStatus ValidateSingleHeader(absl::string_view key,
+ absl::string_view value);
+
+ // Returns true if all required pseudoheaders and no extra pseudoheaders are
+ // present for the given header type.
+ bool FinishHeaderBlock(HeaderType type);
+
+ absl::string_view status_header() const { return status_; }
+
+ private:
+ std::vector<std::string> pseudo_headers_;
+ std::string status_;
+};
+
+} // namespace adapter
+} // namespace http2
+
+#endif // QUICHE_HTTP2_ADAPTER_HEADER_VALIDATOR_H_
diff --git a/chromium/net/third_party/quiche/src/http2/adapter/header_validator_test.cc b/chromium/net/third_party/quiche/src/http2/adapter/header_validator_test.cc
new file mode 100644
index 00000000000..01460c9a94b
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/http2/adapter/header_validator_test.cc
@@ -0,0 +1,213 @@
+#include "http2/adapter/header_validator.h"
+
+#include "absl/strings/str_cat.h"
+#include "common/platform/api/quiche_test.h"
+
+namespace http2 {
+namespace adapter {
+namespace test {
+
+TEST(HeaderValidatorTest, HeaderNameEmpty) {
+ HeaderValidator v;
+ HeaderValidator::HeaderStatus status = v.ValidateSingleHeader("", "value");
+ EXPECT_EQ(HeaderValidator::HEADER_NAME_EMPTY, status);
+}
+
+TEST(HeaderValidatorTest, HeaderValueEmpty) {
+ HeaderValidator v;
+ HeaderValidator::HeaderStatus status = v.ValidateSingleHeader("name", "");
+ EXPECT_EQ(HeaderValidator::HEADER_OK, status);
+}
+
+TEST(HeaderValidatorTest, NameHasInvalidChar) {
+ HeaderValidator v;
+ for (const bool is_pseudo_header : {true, false}) {
+ // These characters should be allowed. (Not exhaustive.)
+ for (const char* c : {"!", "3", "a", "_", "|", "~"}) {
+ const std::string name = is_pseudo_header ? absl::StrCat(":met", c, "hod")
+ : absl::StrCat("na", c, "me");
+ HeaderValidator::HeaderStatus status =
+ v.ValidateSingleHeader(name, "value");
+ EXPECT_EQ(HeaderValidator::HEADER_OK, status);
+ }
+ // These should not. (Not exhaustive.)
+ for (const char* c : {"\\", "<", ";", "[", "=", " ", "\r", "\n", ",", "\"",
+ "\x1F", "\x91"}) {
+ const std::string name = is_pseudo_header ? absl::StrCat(":met", c, "hod")
+ : absl::StrCat("na", c, "me");
+ HeaderValidator::HeaderStatus status =
+ v.ValidateSingleHeader(name, "value");
+ EXPECT_EQ(HeaderValidator::HEADER_NAME_INVALID_CHAR, status);
+ }
+ // Uppercase characters in header names should not be allowed.
+ const std::string uc_name = is_pseudo_header ? ":Method" : "Name";
+ HeaderValidator::HeaderStatus status =
+ v.ValidateSingleHeader(uc_name, "value");
+ EXPECT_EQ(HeaderValidator::HEADER_NAME_INVALID_CHAR, status);
+ }
+}
+
+TEST(HeaderValidatorTest, ValueHasInvalidChar) {
+ HeaderValidator v;
+ // These characters should be allowed. (Not exhaustive.)
+ for (const char* c :
+ {"!", "3", "a", "_", "|", "~", "\\", "<", ";", "[", "=", "A", "\t"}) {
+ HeaderValidator::HeaderStatus status =
+ v.ValidateSingleHeader("name", absl::StrCat("val", c, "ue"));
+ EXPECT_EQ(HeaderValidator::HEADER_OK, status);
+ }
+ // These should not.
+ for (const char* c : {"\r", "\n"}) {
+ HeaderValidator::HeaderStatus status =
+ v.ValidateSingleHeader("name", absl::StrCat("val", c, "ue"));
+ EXPECT_EQ(HeaderValidator::HEADER_VALUE_INVALID_CHAR, status);
+ }
+}
+
+TEST(HeaderValidatorTest, StatusHasInvalidChar) {
+ HeaderValidator v;
+
+ for (HeaderType type : {HeaderType::RESPONSE, HeaderType::RESPONSE_100}) {
+ // When `:status` has a non-digit value, validation will fail.
+ v.StartHeaderBlock();
+ EXPECT_EQ(HeaderValidator::HEADER_VALUE_INVALID_CHAR,
+ v.ValidateSingleHeader(":status", "bar"));
+ EXPECT_FALSE(v.FinishHeaderBlock(type));
+
+ // When `:status` is too short, validation will fail.
+ v.StartHeaderBlock();
+ EXPECT_EQ(HeaderValidator::HEADER_VALUE_INVALID_CHAR,
+ v.ValidateSingleHeader(":status", "10"));
+ EXPECT_FALSE(v.FinishHeaderBlock(type));
+
+ // When `:status` is too long, validation will fail.
+ v.StartHeaderBlock();
+ EXPECT_EQ(HeaderValidator::HEADER_VALUE_INVALID_CHAR,
+ v.ValidateSingleHeader(":status", "9000"));
+ EXPECT_FALSE(v.FinishHeaderBlock(type));
+
+ // When `:status` is just right, validation will succeed.
+ v.StartHeaderBlock();
+ EXPECT_EQ(HeaderValidator::HEADER_OK,
+ v.ValidateSingleHeader(":status", "400"));
+ EXPECT_TRUE(v.FinishHeaderBlock(type));
+ }
+}
+
+TEST(HeaderValidatorTest, RequestPseudoHeaders) {
+ HeaderValidator v;
+ const absl::string_view headers[] = {":authority", ":method", ":path",
+ ":scheme"};
+ for (absl::string_view to_skip : headers) {
+ v.StartHeaderBlock();
+ for (absl::string_view to_add : headers) {
+ if (to_add != to_skip) {
+ EXPECT_EQ(HeaderValidator::HEADER_OK,
+ v.ValidateSingleHeader(to_add, "foo"));
+ }
+ }
+ // When any pseudo-header is missing, final validation will fail.
+ EXPECT_FALSE(v.FinishHeaderBlock(HeaderType::REQUEST));
+ }
+
+ // When all pseudo-headers are present, final validation will succeed.
+ v.StartHeaderBlock();
+ for (absl::string_view to_add : headers) {
+ EXPECT_EQ(HeaderValidator::HEADER_OK,
+ v.ValidateSingleHeader(to_add, "foo"));
+ }
+ EXPECT_TRUE(v.FinishHeaderBlock(HeaderType::REQUEST));
+
+ // When an extra pseudo-header is present, final validation will fail.
+ v.StartHeaderBlock();
+ for (absl::string_view to_add : headers) {
+ EXPECT_EQ(HeaderValidator::HEADER_OK,
+ v.ValidateSingleHeader(to_add, "foo"));
+ }
+ EXPECT_EQ(HeaderValidator::HEADER_OK,
+ v.ValidateSingleHeader(":extra", "blah"));
+ EXPECT_FALSE(v.FinishHeaderBlock(HeaderType::REQUEST));
+
+ // When a required pseudo-header is repeated, final validation will fail.
+ for (absl::string_view to_repeat : headers) {
+ v.StartHeaderBlock();
+ for (absl::string_view to_add : headers) {
+ EXPECT_EQ(HeaderValidator::HEADER_OK,
+ v.ValidateSingleHeader(to_add, "foo"));
+ if (to_add == to_repeat) {
+ EXPECT_EQ(HeaderValidator::HEADER_OK,
+ v.ValidateSingleHeader(to_add, "foo"));
+ }
+ }
+ EXPECT_FALSE(v.FinishHeaderBlock(HeaderType::REQUEST));
+ }
+}
+
+TEST(HeaderValidatorTest, WebsocketPseudoHeaders) {
+ HeaderValidator v;
+ const absl::string_view headers[] = {":authority", ":method", ":path",
+ ":scheme"};
+ v.StartHeaderBlock();
+ for (absl::string_view to_add : headers) {
+ EXPECT_EQ(HeaderValidator::HEADER_OK,
+ v.ValidateSingleHeader(to_add, "foo"));
+ }
+ EXPECT_EQ(HeaderValidator::HEADER_OK,
+ v.ValidateSingleHeader(":protocol", "websocket"));
+ // For now, `:protocol` is treated as an extra pseudo-header.
+ EXPECT_FALSE(v.FinishHeaderBlock(HeaderType::REQUEST));
+}
+
+TEST(HeaderValidatorTest, ResponsePseudoHeaders) {
+ HeaderValidator v;
+
+ for (HeaderType type : {HeaderType::RESPONSE, HeaderType::RESPONSE_100}) {
+ // When `:status` is missing, validation will fail.
+ v.StartHeaderBlock();
+ EXPECT_EQ(HeaderValidator::HEADER_OK, v.ValidateSingleHeader("foo", "bar"));
+ EXPECT_FALSE(v.FinishHeaderBlock(type));
+
+ // When all pseudo-headers are present, final validation will succeed.
+ v.StartHeaderBlock();
+ EXPECT_EQ(HeaderValidator::HEADER_OK,
+ v.ValidateSingleHeader(":status", "199"));
+ EXPECT_TRUE(v.FinishHeaderBlock(type));
+ EXPECT_EQ("199", v.status_header());
+
+ // When `:status` is repeated, validation will fail.
+ v.StartHeaderBlock();
+ EXPECT_EQ(HeaderValidator::HEADER_OK,
+ v.ValidateSingleHeader(":status", "199"));
+ EXPECT_EQ(HeaderValidator::HEADER_OK,
+ v.ValidateSingleHeader(":status", "299"));
+ EXPECT_FALSE(v.FinishHeaderBlock(type));
+
+ // When an extra pseudo-header is present, final validation will fail.
+ v.StartHeaderBlock();
+ EXPECT_EQ(HeaderValidator::HEADER_OK,
+ v.ValidateSingleHeader(":status", "199"));
+ EXPECT_EQ(HeaderValidator::HEADER_OK,
+ v.ValidateSingleHeader(":extra", "blorp"));
+ EXPECT_FALSE(v.FinishHeaderBlock(type));
+ }
+}
+
+TEST(HeaderValidatorTest, ResponseTrailerPseudoHeaders) {
+ HeaderValidator v;
+
+ // When no pseudo-headers are present, validation will succeed.
+ v.StartHeaderBlock();
+ EXPECT_EQ(HeaderValidator::HEADER_OK, v.ValidateSingleHeader("foo", "bar"));
+ EXPECT_TRUE(v.FinishHeaderBlock(HeaderType::RESPONSE_TRAILER));
+
+ // When any pseudo-header is present, final validation will fail.
+ v.StartHeaderBlock();
+ EXPECT_EQ(HeaderValidator::HEADER_OK,
+ v.ValidateSingleHeader(":status", "200"));
+ EXPECT_EQ(HeaderValidator::HEADER_OK, v.ValidateSingleHeader("foo", "bar"));
+ EXPECT_FALSE(v.FinishHeaderBlock(HeaderType::RESPONSE_TRAILER));
+}
+
+} // namespace test
+} // namespace adapter
+} // namespace http2
diff --git a/chromium/net/third_party/quiche/src/http2/adapter/http2_adapter.h b/chromium/net/third_party/quiche/src/http2/adapter/http2_adapter.h
index 789be98ae3b..8c231d1e6db 100644
--- a/chromium/net/third_party/quiche/src/http2/adapter/http2_adapter.h
+++ b/chromium/net/third_party/quiche/src/http2/adapter/http2_adapter.h
@@ -1,6 +1,8 @@
#ifndef QUICHE_HTTP2_ADAPTER_HTTP2_ADAPTER_H_
#define QUICHE_HTTP2_ADAPTER_HTTP2_ADAPTER_H_
+#include <cstdint>
+
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
#include "absl/types/span.h"
@@ -24,11 +26,16 @@ class QUICHE_EXPORT_PRIVATE Http2Adapter {
Http2Adapter(const Http2Adapter&) = delete;
Http2Adapter& operator=(const Http2Adapter&) = delete;
+ virtual ~Http2Adapter() {}
+
virtual bool IsServerSession() const = 0;
+ virtual bool want_read() const = 0;
+ virtual bool want_write() const = 0;
+
// Processes the incoming |bytes| as HTTP/2 and invokes callbacks on the
// |visitor_| as appropriate.
- virtual ssize_t ProcessBytes(absl::string_view bytes) = 0;
+ virtual int64_t ProcessBytes(absl::string_view bytes) = 0;
// Submits the |settings| to be written to the peer, e.g., as part of the
// HTTP/2 connection preface.
@@ -64,7 +71,7 @@ class QUICHE_EXPORT_PRIVATE Http2Adapter {
// Submits a sequence of METADATA frames for the given stream. A |stream_id|
// of 0 indicates connection-level METADATA.
- virtual void SubmitMetadata(Http2StreamId stream_id,
+ virtual void SubmitMetadata(Http2StreamId stream_id, size_t max_frame_size,
std::unique_ptr<MetadataSource> source) = 0;
// Invokes the visitor's OnReadyToSend() method for serialized frame data.
@@ -142,7 +149,6 @@ class QUICHE_EXPORT_PRIVATE Http2Adapter {
// Subclasses should expose a public factory method for constructing and
// initializing (via Initialize()) adapter instances.
explicit Http2Adapter(Http2VisitorInterface& visitor) : visitor_(visitor) {}
- virtual ~Http2Adapter() {}
// Accessors. Do not transfer ownership.
Http2VisitorInterface& visitor() { return visitor_; }
diff --git a/chromium/net/third_party/quiche/src/http2/adapter/http2_session.h b/chromium/net/third_party/quiche/src/http2/adapter/http2_session.h
index 3b57d8f1aba..e88a555faf0 100644
--- a/chromium/net/third_party/quiche/src/http2/adapter/http2_session.h
+++ b/chromium/net/third_party/quiche/src/http2/adapter/http2_session.h
@@ -18,7 +18,7 @@ class QUICHE_EXPORT_PRIVATE Http2Session {
Http2Session() = default;
virtual ~Http2Session() {}
- virtual ssize_t ProcessBytes(absl::string_view bytes) = 0;
+ virtual int64_t ProcessBytes(absl::string_view bytes) = 0;
virtual int Consume(Http2StreamId stream_id, size_t num_bytes) = 0;
diff --git a/chromium/net/third_party/quiche/src/http2/adapter/http2_visitor_interface.h b/chromium/net/third_party/quiche/src/http2/adapter/http2_visitor_interface.h
index 292021a23f4..4d12e42a380 100644
--- a/chromium/net/third_party/quiche/src/http2/adapter/http2_visitor_interface.h
+++ b/chromium/net/third_party/quiche/src/http2/adapter/http2_visitor_interface.h
@@ -1,6 +1,7 @@
#ifndef QUICHE_HTTP2_ADAPTER_HTTP2_VISITOR_INTERFACE_H_
#define QUICHE_HTTP2_ADAPTER_HTTP2_VISITOR_INTERFACE_H_
+#include <cstdint>
#include <vector>
#include "absl/strings/string_view.h"
@@ -51,18 +52,22 @@ class QUICHE_EXPORT_PRIVATE Http2VisitorInterface {
Http2VisitorInterface& operator=(const Http2VisitorInterface&) = delete;
virtual ~Http2VisitorInterface() = default;
- static const ssize_t kSendBlocked = 0;
- static const ssize_t kSendError = -1;
+ enum : int64_t {
+ kSendBlocked = 0,
+ kSendError = -1,
+ };
// Called when there are serialized frames to send. Should return how many
// bytes were actually sent. May return kSendBlocked or kSendError.
- virtual ssize_t OnReadyToSend(absl::string_view serialized) = 0;
+ virtual int64_t OnReadyToSend(absl::string_view serialized) = 0;
// Called when a connection-level processing error has been encountered.
virtual void OnConnectionError() = 0;
// Called when the header for a frame is received.
- virtual void OnFrameHeader(Http2StreamId /*stream_id*/, size_t /*length*/,
- uint8_t /*type*/, uint8_t /*flags*/) {}
+ virtual bool OnFrameHeader(Http2StreamId /*stream_id*/, size_t /*length*/,
+ uint8_t /*type*/, uint8_t /*flags*/) {
+ return true;
+ }
// Called when a non-ack SETTINGS frame is received.
virtual void OnSettingsStart() = 0;
@@ -103,16 +108,16 @@ class QUICHE_EXPORT_PRIVATE Http2VisitorInterface {
// Called when the connection has received the complete header block for a
// logical HEADERS frame on a stream (which may contain CONTINUATION frames,
// transparent to the user).
- virtual void OnEndHeadersForStream(Http2StreamId stream_id) = 0;
+ virtual bool OnEndHeadersForStream(Http2StreamId stream_id) = 0;
// Called when the connection receives the beginning of a DATA frame. The data
// payload will be provided via subsequent calls to OnDataForStream().
- virtual void OnBeginDataForStream(Http2StreamId stream_id,
+ virtual bool OnBeginDataForStream(Http2StreamId stream_id,
size_t payload_length) = 0;
// Called when the connection receives some |data| (as part of a DATA frame
// payload) for a stream.
- virtual void OnDataForStream(Http2StreamId stream_id,
+ virtual bool OnDataForStream(Http2StreamId stream_id,
absl::string_view data) = 0;
// Called when the peer sends the END_STREAM flag on a stream, indicating that
@@ -142,7 +147,7 @@ class QUICHE_EXPORT_PRIVATE Http2VisitorInterface {
Http2StreamId promised_stream_id) = 0;
// Called when the connection receives a GOAWAY frame.
- virtual void OnGoAway(Http2StreamId last_accepted_stream_id,
+ virtual bool OnGoAway(Http2StreamId last_accepted_stream_id,
Http2ErrorCode error_code,
absl::string_view opaque_data) = 0;
@@ -163,31 +168,12 @@ class QUICHE_EXPORT_PRIVATE Http2VisitorInterface {
size_t length, uint8_t flags,
uint32_t error_code) = 0;
- // Called when the connection is ready to send data for a stream. The
- // implementation should write at most |length| bytes of the data payload to
- // the |destination_buffer| and set |end_stream| to true IFF there will be no
- // more data sent on this stream. Sets |written| to the number of bytes
- // written to the |destination_buffer| or a negative value if an error occurs.
- virtual void OnReadyToSendDataForStream(Http2StreamId stream_id,
- char* destination_buffer,
- size_t length,
- ssize_t* written,
- bool* end_stream) = 0;
-
// Called when the connection receives an invalid frame. |error_code| is a
// negative integer error code generated by the library. A return value of
// false will result in the connection entering an error state, with no
// further frame processing possible.
virtual bool OnInvalidFrame(Http2StreamId stream_id, int error_code) = 0;
- // Called when the connection is ready to write metadata for |stream_id| to
- // the wire. The implementation should write at most |length| bytes of the
- // serialized metadata payload to the |buffer| and set |written| to the number
- // of bytes written or a negative value if there was an error.
- virtual void OnReadyToSendMetadataForStream(Http2StreamId stream_id,
- char* buffer, size_t length,
- ssize_t* written) = 0;
-
// Called when the connection receives the beginning of a METADATA frame
// (which may itself be the middle of a logical metadata block). The metadata
// payload will be provided via subsequent calls to OnMetadataForStream().
@@ -196,8 +182,8 @@ class QUICHE_EXPORT_PRIVATE Http2VisitorInterface {
size_t payload_length) = 0;
// Called when the connection receives |metadata| as part of a METADATA frame
- // payload for a stream.
- virtual void OnMetadataForStream(Http2StreamId stream_id,
+ // payload for a stream. Returns false if a fatal error has occurred.
+ virtual bool OnMetadataForStream(Http2StreamId stream_id,
absl::string_view metadata) = 0;
// Called when the connection has finished receiving a logical metadata block
diff --git a/chromium/net/third_party/quiche/src/http2/adapter/mock_http2_visitor.h b/chromium/net/third_party/quiche/src/http2/adapter/mock_http2_visitor.h
index 3daa8053962..1faf443339e 100644
--- a/chromium/net/third_party/quiche/src/http2/adapter/mock_http2_visitor.h
+++ b/chromium/net/third_party/quiche/src/http2/adapter/mock_http2_visitor.h
@@ -1,6 +1,8 @@
#ifndef QUICHE_HTTP2_ADAPTER_MOCK_HTTP2_VISITOR_INTERFACE_H_
#define QUICHE_HTTP2_ADAPTER_MOCK_HTTP2_VISITOR_INTERFACE_H_
+#include <cstdint>
+
#include "http2/adapter/http2_visitor_interface.h"
#include "common/platform/api/quiche_export.h"
#include "common/platform/api/quiche_test.h"
@@ -13,23 +15,26 @@ namespace test {
class QUICHE_NO_EXPORT MockHttp2Visitor : public Http2VisitorInterface {
public:
MockHttp2Visitor() {
+ ON_CALL(*this, OnFrameHeader).WillByDefault(testing::Return(true));
ON_CALL(*this, OnBeginHeadersForStream)
.WillByDefault(testing::Return(true));
ON_CALL(*this, OnHeaderForStream).WillByDefault(testing::Return(HEADER_OK));
+ ON_CALL(*this, OnEndHeadersForStream).WillByDefault(testing::Return(true));
+ ON_CALL(*this, OnBeginDataForStream).WillByDefault(testing::Return(true));
+ ON_CALL(*this, OnDataForStream).WillByDefault(testing::Return(true));
+ ON_CALL(*this, OnGoAway).WillByDefault(testing::Return(true));
ON_CALL(*this, OnInvalidFrame).WillByDefault(testing::Return(true));
+ ON_CALL(*this, OnMetadataForStream).WillByDefault(testing::Return(true));
ON_CALL(*this, OnMetadataEndForStream).WillByDefault(testing::Return(true));
}
- MOCK_METHOD(ssize_t,
- OnReadyToSend,
- (absl::string_view serialized),
+ MOCK_METHOD(int64_t, OnReadyToSend, (absl::string_view serialized),
(override));
MOCK_METHOD(void, OnConnectionError, (), (override));
- MOCK_METHOD(
- void,
- OnFrameHeader,
- (Http2StreamId stream_id, size_t length, uint8_t type, uint8_t flags),
- (override));
+ MOCK_METHOD(bool, OnFrameHeader,
+ (Http2StreamId stream_id, size_t length, uint8_t type,
+ uint8_t flags),
+ (override));
MOCK_METHOD(void, OnSettingsStart, (), (override));
MOCK_METHOD(void, OnSetting, (Http2Setting setting), (override));
MOCK_METHOD(void, OnSettingsEnd, (), (override));
@@ -42,20 +47,14 @@ class QUICHE_NO_EXPORT MockHttp2Visitor : public Http2VisitorInterface {
absl::string_view value),
(override));
- MOCK_METHOD(void,
- OnEndHeadersForStream,
- (Http2StreamId stream_id),
+ MOCK_METHOD(bool, OnEndHeadersForStream, (Http2StreamId stream_id),
(override));
- MOCK_METHOD(void,
- OnBeginDataForStream,
- (Http2StreamId stream_id, size_t payload_length),
- (override));
+ MOCK_METHOD(bool, OnBeginDataForStream,
+ (Http2StreamId stream_id, size_t payload_length), (override));
- MOCK_METHOD(void,
- OnDataForStream,
- (Http2StreamId stream_id, absl::string_view data),
- (override));
+ MOCK_METHOD(bool, OnDataForStream,
+ (Http2StreamId stream_id, absl::string_view data), (override));
MOCK_METHOD(void, OnEndStream, (Http2StreamId stream_id), (override));
@@ -84,10 +83,8 @@ class QUICHE_NO_EXPORT MockHttp2Visitor : public Http2VisitorInterface {
(Http2StreamId stream_id, Http2StreamId promised_stream_id),
(override));
- MOCK_METHOD(void,
- OnGoAway,
- (Http2StreamId last_accepted_stream_id,
- Http2ErrorCode error_code,
+ MOCK_METHOD(bool, OnGoAway,
+ (Http2StreamId last_accepted_stream_id, Http2ErrorCode error_code,
absl::string_view opaque_data),
(override));
@@ -110,27 +107,11 @@ class QUICHE_NO_EXPORT MockHttp2Visitor : public Http2VisitorInterface {
(override));
MOCK_METHOD(void,
- OnReadyToSendDataForStream,
- (Http2StreamId stream_id,
- char* destination_buffer,
- size_t length,
- ssize_t* written,
- bool* end_stream),
- (override));
-
- MOCK_METHOD(
- void,
- OnReadyToSendMetadataForStream,
- (Http2StreamId stream_id, char* buffer, size_t length, ssize_t* written),
- (override));
-
- MOCK_METHOD(void,
OnBeginMetadataForStream,
(Http2StreamId stream_id, size_t payload_length),
(override));
- MOCK_METHOD(void,
- OnMetadataForStream,
+ MOCK_METHOD(bool, OnMetadataForStream,
(Http2StreamId stream_id, absl::string_view metadata),
(override));
diff --git a/chromium/net/third_party/quiche/src/http2/adapter/mock_nghttp2_callbacks.h b/chromium/net/third_party/quiche/src/http2/adapter/mock_nghttp2_callbacks.h
index 08d15be7d7d..98acad96e52 100644
--- a/chromium/net/third_party/quiche/src/http2/adapter/mock_nghttp2_callbacks.h
+++ b/chromium/net/third_party/quiche/src/http2/adapter/mock_nghttp2_callbacks.h
@@ -1,6 +1,8 @@
#ifndef QUICHE_HTTP2_ADAPTER_MOCK_NGHTTP2_CALLBACKS_H_
#define QUICHE_HTTP2_ADAPTER_MOCK_NGHTTP2_CALLBACKS_H_
+#include <cstdint>
+
#include "absl/strings/string_view.h"
#include "http2/adapter/nghttp2_util.h"
#include "third_party/nghttp2/src/lib/includes/nghttp2/nghttp2.h"
diff --git a/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_adapter.cc b/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_adapter.cc
index 9b444a3243d..5da518fefc9 100644
--- a/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_adapter.cc
+++ b/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_adapter.cc
@@ -12,6 +12,32 @@
namespace http2 {
namespace adapter {
+namespace {
+
+// A metadata source that deletes itself upon completion.
+class SelfDeletingMetadataSource : public MetadataSource {
+ public:
+ explicit SelfDeletingMetadataSource(std::unique_ptr<MetadataSource> source)
+ : source_(std::move(source)) {}
+
+ size_t NumFrames(size_t max_frame_size) const override {
+ return source_->NumFrames(max_frame_size);
+ }
+
+ std::pair<int64_t, bool> Pack(uint8_t* dest, size_t dest_len) override {
+ const auto result = source_->Pack(dest, dest_len);
+ if (result.first < 0 || result.second) {
+ delete this;
+ }
+ return result;
+ }
+
+ private:
+ std::unique_ptr<MetadataSource> source_;
+};
+
+} // anonymous namespace
+
/* static */
std::unique_ptr<NgHttp2Adapter> NgHttp2Adapter::CreateClientAdapter(
Http2VisitorInterface& visitor, const nghttp2_option* options) {
@@ -34,8 +60,8 @@ bool NgHttp2Adapter::IsServerSession() const {
return result > 0;
}
-ssize_t NgHttp2Adapter::ProcessBytes(absl::string_view bytes) {
- const ssize_t processed_bytes = session_->ProcessBytes(bytes);
+int64_t NgHttp2Adapter::ProcessBytes(absl::string_view bytes) {
+ const int64_t processed_bytes = session_->ProcessBytes(bytes);
if (processed_bytes < 0) {
visitor_.OnConnectionError();
}
@@ -90,9 +116,26 @@ void NgHttp2Adapter::SubmitWindowUpdate(Http2StreamId stream_id,
stream_id, window_increment);
}
-void NgHttp2Adapter::SubmitMetadata(
- Http2StreamId /*stream_id*/, std::unique_ptr<MetadataSource> /*source*/) {
- QUICHE_LOG(DFATAL) << "Not implemented";
+void NgHttp2Adapter::SubmitMetadata(Http2StreamId stream_id,
+ size_t max_frame_size,
+ std::unique_ptr<MetadataSource> source) {
+ auto* wrapped_source = new SelfDeletingMetadataSource(std::move(source));
+ const size_t num_frames = wrapped_source->NumFrames(max_frame_size);
+ size_t num_successes = 0;
+ for (size_t i = 1; i <= num_frames; ++i) {
+ const int result = nghttp2_submit_extension(
+ session_->raw_ptr(), kMetadataFrameType,
+ i == num_frames ? kMetadataEndFlag : 0, stream_id, wrapped_source);
+ if (result != 0) {
+ QUICHE_LOG(DFATAL) << "Failed to submit extension frame " << i << " of "
+ << num_frames;
+ break;
+ }
+ ++num_successes;
+ }
+ if (num_successes == 0) {
+ delete wrapped_source;
+ }
}
int NgHttp2Adapter::Send() {
diff --git a/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_adapter.h b/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_adapter.h
index 151f9a7ae5a..90782787867 100644
--- a/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_adapter.h
+++ b/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_adapter.h
@@ -1,6 +1,8 @@
#ifndef QUICHE_HTTP2_ADAPTER_NGHTTP2_ADAPTER_H_
#define QUICHE_HTTP2_ADAPTER_NGHTTP2_ADAPTER_H_
+#include <cstdint>
+
#include "absl/container/flat_hash_map.h"
#include "http2/adapter/http2_adapter.h"
#include "http2/adapter/http2_protocol.h"
@@ -26,8 +28,10 @@ class QUICHE_EXPORT_PRIVATE NgHttp2Adapter : public Http2Adapter {
Http2VisitorInterface& visitor, const nghttp2_option* options = nullptr);
bool IsServerSession() const override;
+ bool want_read() const override { return session_->want_read(); }
+ bool want_write() const override { return session_->want_write(); }
- ssize_t ProcessBytes(absl::string_view bytes) override;
+ int64_t ProcessBytes(absl::string_view bytes) override;
void SubmitSettings(absl::Span<const Http2Setting> settings) override;
void SubmitPriorityForStream(Http2StreamId stream_id,
Http2StreamId parent_stream_id,
@@ -49,7 +53,7 @@ class QUICHE_EXPORT_PRIVATE NgHttp2Adapter : public Http2Adapter {
void SubmitRst(Http2StreamId stream_id, Http2ErrorCode error_code) override;
- void SubmitMetadata(Http2StreamId stream_id,
+ void SubmitMetadata(Http2StreamId stream_id, size_t max_frame_size,
std::unique_ptr<MetadataSource> source) override;
int Send() override;
@@ -84,10 +88,6 @@ class QUICHE_EXPORT_PRIVATE NgHttp2Adapter : public Http2Adapter {
bool ResumeStream(Http2StreamId stream_id) override;
- // TODO(b/181586191): Temporary accessor until equivalent functionality is
- // available in this adapter class.
- NgHttp2Session& session() { return *session_; }
-
private:
NgHttp2Adapter(Http2VisitorInterface& visitor, Perspective perspective,
const nghttp2_option* options);
diff --git a/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_adapter_test.cc b/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_adapter_test.cc
index 785e476c94d..ccfb1acd4f3 100644
--- a/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_adapter_test.cc
+++ b/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_adapter_test.cc
@@ -1,7 +1,9 @@
#include "http2/adapter/nghttp2_adapter.h"
+#include "http2/adapter/http2_protocol.h"
#include "http2/adapter/mock_http2_visitor.h"
#include "http2/adapter/nghttp2_test_utils.h"
+#include "http2/adapter/oghttp2_util.h"
#include "http2/adapter/test_frame_sequence.h"
#include "http2/adapter/test_utils.h"
#include "common/platform/api/quiche_test.h"
@@ -48,8 +50,8 @@ TEST(NgHttp2AdapterTest, ClientConstruction) {
testing::StrictMock<MockHttp2Visitor> visitor;
auto adapter = NgHttp2Adapter::CreateClientAdapter(visitor);
ASSERT_NE(nullptr, adapter);
- EXPECT_TRUE(adapter->session().want_read());
- EXPECT_FALSE(adapter->session().want_write());
+ EXPECT_TRUE(adapter->want_read());
+ EXPECT_FALSE(adapter->want_write());
EXPECT_FALSE(adapter->IsServerSession());
}
@@ -81,7 +83,7 @@ TEST(NgHttp2AdapterTest, ClientHandlesFrames) {
EXPECT_CALL(visitor, OnFrameHeader(0, 4, WINDOW_UPDATE, 0));
EXPECT_CALL(visitor, OnWindowUpdate(0, 1000));
- const ssize_t initial_result = adapter->ProcessBytes(initial_frames);
+ const int64_t initial_result = adapter->ProcessBytes(initial_frames);
EXPECT_EQ(initial_frames.size(), initial_result);
EXPECT_EQ(adapter->GetSendWindowSize(), kInitialFlowControlWindowSize + 1000);
@@ -202,7 +204,7 @@ TEST(NgHttp2AdapterTest, ClientHandlesFrames) {
EXPECT_CALL(visitor, OnFrameHeader(0, 19, GOAWAY, 0));
EXPECT_CALL(visitor,
OnGoAway(5, Http2ErrorCode::ENHANCE_YOUR_CALM, "calm down!!"));
- const ssize_t stream_result = adapter->ProcessBytes(stream_frames);
+ const int64_t stream_result = adapter->ProcessBytes(stream_frames);
EXPECT_EQ(stream_frames.size(), stream_result);
// First stream has received some data.
@@ -229,7 +231,7 @@ TEST(NgHttp2AdapterTest, ClientHandlesFrames) {
EXPECT_EQ(0, adapter->GetHighestReceivedStreamId());
// Even though the client recieved a GOAWAY, streams 1 and 5 are still active.
- EXPECT_TRUE(adapter->session().want_read());
+ EXPECT_TRUE(adapter->want_read());
EXPECT_CALL(visitor, OnFrameHeader(1, 0, DATA, 1));
EXPECT_CALL(visitor, OnBeginDataForStream(1, 0));
@@ -248,10 +250,10 @@ TEST(NgHttp2AdapterTest, ClientHandlesFrames) {
// After receiving END_STREAM for 1 and RST_STREAM for 5, the session no
// longer expects reads.
- EXPECT_FALSE(adapter->session().want_read());
+ EXPECT_FALSE(adapter->want_read());
// Client will not have anything else to write.
- EXPECT_FALSE(adapter->session().want_write());
+ EXPECT_FALSE(adapter->want_write());
result = adapter->Send();
EXPECT_EQ(0, result);
EXPECT_THAT(visitor.data(), testing::IsEmpty());
@@ -321,13 +323,13 @@ TEST(NgHttp2AdapterTest, ClientHandlesTrailers) {
EXPECT_CALL(visitor, OnEndStream(1));
EXPECT_CALL(visitor, OnCloseStream(1, Http2ErrorCode::NO_ERROR));
- const ssize_t stream_result = adapter->ProcessBytes(stream_frames);
+ const int64_t stream_result = adapter->ProcessBytes(stream_frames);
EXPECT_EQ(stream_frames.size(), stream_result);
EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, _, 0x1));
EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, _, 0x1, 0));
- EXPECT_TRUE(adapter->session().want_write());
+ EXPECT_TRUE(adapter->want_write());
result = adapter->Send();
EXPECT_EQ(0, result);
EXPECT_THAT(visitor.data(), EqualsFrames({spdy::SpdyFrameType::SETTINGS}));
@@ -401,13 +403,88 @@ TEST(NgHttp2AdapterTest, ClientHandlesMetadata) {
EXPECT_CALL(visitor, OnEndStream(1));
EXPECT_CALL(visitor, OnCloseStream(1, Http2ErrorCode::NO_ERROR));
- const ssize_t stream_result = adapter->ProcessBytes(stream_frames);
+ const int64_t stream_result = adapter->ProcessBytes(stream_frames);
EXPECT_EQ(stream_frames.size(), stream_result);
EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, _, 0x1));
EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, _, 0x1, 0));
- EXPECT_TRUE(adapter->session().want_write());
+ EXPECT_TRUE(adapter->want_write());
+ result = adapter->Send();
+ EXPECT_EQ(0, result);
+ EXPECT_THAT(visitor.data(), EqualsFrames({spdy::SpdyFrameType::SETTINGS}));
+}
+
+TEST(NgHttp2AdapterTest, ClientHandlesMetadataWithError) {
+ DataSavingVisitor visitor;
+ auto adapter = NgHttp2Adapter::CreateClientAdapter(visitor);
+
+ testing::InSequence s;
+
+ const std::vector<const Header> headers1 =
+ ToHeaders({{":method", "GET"},
+ {":scheme", "http"},
+ {":authority", "example.com"},
+ {":path", "/this/is/request/one"}});
+
+ const char* kSentinel1 = "arbitrary pointer 1";
+ const int32_t stream_id1 =
+ adapter->SubmitRequest(headers1, nullptr, const_cast<char*>(kSentinel1));
+ ASSERT_GT(stream_id1, 0);
+ QUICHE_LOG(INFO) << "Created stream: " << stream_id1;
+
+ EXPECT_CALL(visitor, OnBeforeFrameSent(HEADERS, stream_id1, _, 0x5));
+ EXPECT_CALL(visitor, OnFrameSent(HEADERS, stream_id1, _, 0x5, 0));
+
+ int result = adapter->Send();
+ EXPECT_EQ(0, result);
+ visitor.Clear();
+
+ const std::string stream_frames =
+ TestFrameSequence()
+ .ServerPreface()
+ .Metadata(0, "Example connection metadata")
+ .Headers(1,
+ {{":status", "200"},
+ {"server", "my-fake-server"},
+ {"date", "Tue, 6 Apr 2021 12:54:01 GMT"}},
+ /*fin=*/false)
+ .Metadata(1, "Example stream metadata")
+ .Data(1, "This is the response body.", true)
+ .Serialize();
+
+ // Server preface (empty SETTINGS)
+ EXPECT_CALL(visitor, OnFrameHeader(0, 0, SETTINGS, 0));
+ EXPECT_CALL(visitor, OnSettingsStart());
+ EXPECT_CALL(visitor, OnSettingsEnd());
+
+ EXPECT_CALL(visitor, OnFrameHeader(0, _, kMetadataFrameType, 4));
+ EXPECT_CALL(visitor, OnBeginMetadataForStream(0, _));
+ EXPECT_CALL(visitor, OnMetadataForStream(0, _));
+ EXPECT_CALL(visitor, OnMetadataEndForStream(0));
+ EXPECT_CALL(visitor, OnFrameHeader(1, _, HEADERS, 4));
+ EXPECT_CALL(visitor, OnBeginHeadersForStream(1));
+ EXPECT_CALL(visitor, OnHeaderForStream(1, ":status", "200"));
+ EXPECT_CALL(visitor, OnHeaderForStream(1, "server", "my-fake-server"));
+ EXPECT_CALL(visitor,
+ OnHeaderForStream(1, "date", "Tue, 6 Apr 2021 12:54:01 GMT"));
+ EXPECT_CALL(visitor, OnEndHeadersForStream(1));
+ EXPECT_CALL(visitor, OnFrameHeader(1, _, kMetadataFrameType, 4));
+ EXPECT_CALL(visitor, OnBeginMetadataForStream(1, _));
+ EXPECT_CALL(visitor, OnMetadataForStream(1, _))
+ .WillOnce(testing::Return(false));
+ // Remaining frames are not processed due to the error.
+ EXPECT_CALL(visitor, OnConnectionError());
+
+ const int64_t stream_result = adapter->ProcessBytes(stream_frames);
+ // The false return from OnMetadataForStream() results in a connection error.
+ EXPECT_EQ(stream_result, NGHTTP2_ERR_CALLBACK_FAILURE);
+
+ EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, _, 0x1));
+ EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, _, 0x1, 0));
+
+ EXPECT_TRUE(adapter->want_write());
+ EXPECT_TRUE(adapter->want_read()); // Even after an error. Why?
result = adapter->Send();
EXPECT_EQ(0, result);
EXPECT_THAT(visitor.data(), EqualsFrames({spdy::SpdyFrameType::SETTINGS}));
@@ -481,7 +558,7 @@ TEST(NgHttp2AdapterTest, ClientHandlesInvalidTrailers) {
// Bad status trailer will cause a PROTOCOL_ERROR. The header is never
// delivered in an OnHeaderForStream callback.
- const ssize_t stream_result = adapter->ProcessBytes(stream_frames);
+ const int64_t stream_result = adapter->ProcessBytes(stream_frames);
EXPECT_EQ(stream_frames.size(), stream_result);
EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, 0, 0x1));
@@ -490,7 +567,7 @@ TEST(NgHttp2AdapterTest, ClientHandlesInvalidTrailers) {
EXPECT_CALL(visitor, OnFrameSent(RST_STREAM, stream_id1, 4, 0x0, 1));
EXPECT_CALL(visitor, OnCloseStream(1, Http2ErrorCode::PROTOCOL_ERROR));
- EXPECT_TRUE(adapter->session().want_write());
+ EXPECT_TRUE(adapter->want_write());
result = adapter->Send();
EXPECT_EQ(0, result);
EXPECT_THAT(visitor.data(), EqualsFrames({spdy::SpdyFrameType::SETTINGS,
@@ -554,7 +631,7 @@ TEST(NgHttp2AdapterTest, ClientRstStreamWhileHandlingHeaders) {
}),
testing::Return(Http2VisitorInterface::HEADER_RST_STREAM)));
- const ssize_t stream_result = adapter->ProcessBytes(stream_frames);
+ const int64_t stream_result = adapter->ProcessBytes(stream_frames);
EXPECT_EQ(stream_frames.size(), stream_result);
EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, 0, 0x1));
@@ -565,7 +642,7 @@ TEST(NgHttp2AdapterTest, ClientRstStreamWhileHandlingHeaders) {
static_cast<int>(Http2ErrorCode::REFUSED_STREAM)));
EXPECT_CALL(visitor, OnCloseStream(1, Http2ErrorCode::REFUSED_STREAM));
- EXPECT_TRUE(adapter->session().want_write());
+ EXPECT_TRUE(adapter->want_write());
result = adapter->Send();
EXPECT_EQ(0, result);
EXPECT_THAT(visitor.data(), EqualsFrames({spdy::SpdyFrameType::SETTINGS,
@@ -627,13 +704,13 @@ TEST(NgHttp2AdapterTest, ClientConnectionErrorWhileHandlingHeaders) {
testing::Return(Http2VisitorInterface::HEADER_CONNECTION_ERROR));
EXPECT_CALL(visitor, OnConnectionError());
- const ssize_t stream_result = adapter->ProcessBytes(stream_frames);
+ const int64_t stream_result = adapter->ProcessBytes(stream_frames);
EXPECT_EQ(-902 /* NGHTTP2_ERR_CALLBACK_FAILURE */, stream_result);
EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, 0, 0x1));
EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, 0, 0x1, 0));
- EXPECT_TRUE(adapter->session().want_write());
+ EXPECT_TRUE(adapter->want_write());
result = adapter->Send();
EXPECT_EQ(0, result);
EXPECT_THAT(visitor.data(), EqualsFrames({spdy::SpdyFrameType::SETTINGS}));
@@ -690,13 +767,84 @@ TEST(NgHttp2AdapterTest, ClientRejectsHeaders) {
// Rejecting headers leads to a connection error.
EXPECT_CALL(visitor, OnConnectionError());
- const ssize_t stream_result = adapter->ProcessBytes(stream_frames);
+ const int64_t stream_result = adapter->ProcessBytes(stream_frames);
+ EXPECT_EQ(NGHTTP2_ERR_CALLBACK_FAILURE, stream_result);
+
+ EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, 0, 0x1));
+ EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, 0, 0x1, 0));
+
+ EXPECT_TRUE(adapter->want_write());
+ result = adapter->Send();
+ EXPECT_EQ(0, result);
+ EXPECT_THAT(visitor.data(), EqualsFrames({spdy::SpdyFrameType::SETTINGS}));
+}
+
+TEST(NgHttp2AdapterTest, ClientFailsOnGoAway) {
+ DataSavingVisitor visitor;
+ auto adapter = NgHttp2Adapter::CreateClientAdapter(visitor);
+
+ testing::InSequence s;
+
+ const std::vector<const Header> headers1 =
+ ToHeaders({{":method", "GET"},
+ {":scheme", "http"},
+ {":authority", "example.com"},
+ {":path", "/this/is/request/one"}});
+
+ const char* kSentinel1 = "arbitrary pointer 1";
+ const int32_t stream_id1 =
+ adapter->SubmitRequest(headers1, nullptr, const_cast<char*>(kSentinel1));
+ ASSERT_GT(stream_id1, 0);
+ QUICHE_LOG(INFO) << "Created stream: " << stream_id1;
+
+ EXPECT_CALL(visitor, OnBeforeFrameSent(HEADERS, stream_id1, _, 0x5));
+ EXPECT_CALL(visitor, OnFrameSent(HEADERS, stream_id1, _, 0x5, 0));
+
+ int result = adapter->Send();
+ EXPECT_EQ(0, result);
+ absl::string_view data = visitor.data();
+ EXPECT_THAT(data, testing::StartsWith(spdy::kHttp2ConnectionHeaderPrefix));
+ data.remove_prefix(strlen(spdy::kHttp2ConnectionHeaderPrefix));
+ EXPECT_THAT(data, EqualsFrames({spdy::SpdyFrameType::HEADERS}));
+ visitor.Clear();
+
+ const std::string stream_frames =
+ TestFrameSequence()
+ .ServerPreface()
+ .Headers(1,
+ {{":status", "200"},
+ {"server", "my-fake-server"},
+ {"date", "Tue, 6 Apr 2021 12:54:01 GMT"}},
+ /*fin=*/false)
+ .GoAway(1, Http2ErrorCode::INTERNAL_ERROR, "indigestion")
+ .Data(1, "This is the response body.")
+ .Serialize();
+
+ // Server preface (empty SETTINGS)
+ EXPECT_CALL(visitor, OnFrameHeader(0, 0, SETTINGS, 0));
+ EXPECT_CALL(visitor, OnSettingsStart());
+ EXPECT_CALL(visitor, OnSettingsEnd());
+
+ EXPECT_CALL(visitor, OnFrameHeader(1, _, HEADERS, 4));
+ EXPECT_CALL(visitor, OnBeginHeadersForStream(1));
+ EXPECT_CALL(visitor, OnHeaderForStream(1, ":status", "200"));
+ EXPECT_CALL(visitor, OnHeaderForStream(1, "server", "my-fake-server"));
+ EXPECT_CALL(visitor,
+ OnHeaderForStream(1, "date", "Tue, 6 Apr 2021 12:54:01 GMT"));
+ EXPECT_CALL(visitor, OnEndHeadersForStream(1));
+ EXPECT_CALL(visitor, OnFrameHeader(0, _, GOAWAY, 0));
+ EXPECT_CALL(visitor,
+ OnGoAway(1, Http2ErrorCode::INTERNAL_ERROR, "indigestion"))
+ .WillOnce(testing::Return(false));
+ EXPECT_CALL(visitor, OnConnectionError());
+
+ const int64_t stream_result = adapter->ProcessBytes(stream_frames);
EXPECT_EQ(NGHTTP2_ERR_CALLBACK_FAILURE, stream_result);
EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, 0, 0x1));
EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, 0, 0x1, 0));
- EXPECT_TRUE(adapter->session().want_write());
+ EXPECT_TRUE(adapter->want_write());
result = adapter->Send();
EXPECT_EQ(0, result);
EXPECT_THAT(visitor.data(), EqualsFrames({spdy::SpdyFrameType::SETTINGS}));
@@ -721,10 +869,10 @@ TEST(NgHttp2AdapterTest, ClientSubmitRequest) {
EXPECT_CALL(visitor, OnSettingsStart());
EXPECT_CALL(visitor, OnSettingsEnd());
- const ssize_t initial_result = adapter->ProcessBytes(initial_frames);
+ const int64_t initial_result = adapter->ProcessBytes(initial_frames);
EXPECT_EQ(initial_frames.size(), initial_result);
- EXPECT_TRUE(adapter->session().want_write());
+ EXPECT_TRUE(adapter->want_write());
EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, 0, 0x1));
EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, 0, 0x1, 0));
@@ -735,7 +883,7 @@ TEST(NgHttp2AdapterTest, ClientSubmitRequest) {
visitor.Clear();
EXPECT_EQ(0, adapter->GetHpackEncoderDynamicTableSize());
- EXPECT_FALSE(adapter->session().want_write());
+ EXPECT_FALSE(adapter->want_write());
const char* kSentinel = "";
const absl::string_view kBody = "This is an example request body.";
auto body1 = absl::make_unique<TestDataFrameSource>(visitor, true);
@@ -748,7 +896,7 @@ TEST(NgHttp2AdapterTest, ClientSubmitRequest) {
{":path", "/this/is/request/one"}}),
std::move(body1), const_cast<char*>(kSentinel));
EXPECT_GT(stream_id, 0);
- EXPECT_TRUE(adapter->session().want_write());
+ EXPECT_TRUE(adapter->want_write());
EXPECT_CALL(visitor, OnBeforeFrameSent(HEADERS, stream_id, _, 0x4));
EXPECT_CALL(visitor, OnFrameSent(HEADERS, stream_id, _, 0x4, 0));
@@ -777,7 +925,7 @@ TEST(NgHttp2AdapterTest, ClientSubmitRequest) {
spdy::SpdyFrameType::DATA}));
EXPECT_THAT(visitor.data(), testing::HasSubstr(kBody));
visitor.Clear();
- EXPECT_FALSE(adapter->session().want_write());
+ EXPECT_FALSE(adapter->want_write());
stream_id =
adapter->SubmitRequest(ToHeaders({{":method", "POST"},
@@ -786,7 +934,7 @@ TEST(NgHttp2AdapterTest, ClientSubmitRequest) {
{":path", "/this/is/request/one"}}),
nullptr, nullptr);
EXPECT_GT(stream_id, 0);
- EXPECT_TRUE(adapter->session().want_write());
+ EXPECT_TRUE(adapter->want_write());
const char* kSentinel2 = "arbitrary pointer 2";
EXPECT_EQ(nullptr, adapter->GetStreamUserData(stream_id));
adapter->SetStreamUserData(stream_id, const_cast<char*>(kSentinel2));
@@ -827,10 +975,10 @@ TEST(NgHttp2AdapterTest, ClientSubmitRequestWithDataProvider) {
EXPECT_CALL(visitor, OnSettingsStart());
EXPECT_CALL(visitor, OnSettingsEnd());
- const ssize_t initial_result = adapter->ProcessBytes(initial_frames);
+ const int64_t initial_result = adapter->ProcessBytes(initial_frames);
EXPECT_EQ(initial_frames.size(), initial_result);
- EXPECT_TRUE(adapter->session().want_write());
+ EXPECT_TRUE(adapter->want_write());
EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, 0, 0x1));
EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, 0, 0x1, 0));
@@ -840,7 +988,7 @@ TEST(NgHttp2AdapterTest, ClientSubmitRequestWithDataProvider) {
EXPECT_THAT(visitor.data(), EqualsFrames({spdy::SpdyFrameType::SETTINGS}));
visitor.Clear();
- EXPECT_FALSE(adapter->session().want_write());
+ EXPECT_FALSE(adapter->want_write());
const absl::string_view kBody = "This is an example request body.";
// This test will use TestDataSource as the source of the body payload data.
TestDataSource body1{kBody};
@@ -859,7 +1007,7 @@ TEST(NgHttp2AdapterTest, ClientSubmitRequestWithDataProvider) {
{":path", "/this/is/request/one"}}),
std::move(frame_source), nullptr);
EXPECT_GT(stream_id, 0);
- EXPECT_TRUE(adapter->session().want_write());
+ EXPECT_TRUE(adapter->want_write());
EXPECT_CALL(visitor, OnBeforeFrameSent(HEADERS, stream_id, _, 0x4));
EXPECT_CALL(visitor, OnFrameSent(HEADERS, stream_id, _, 0x4, 0));
@@ -870,7 +1018,7 @@ TEST(NgHttp2AdapterTest, ClientSubmitRequestWithDataProvider) {
EXPECT_THAT(visitor.data(), EqualsFrames({spdy::SpdyFrameType::HEADERS,
spdy::SpdyFrameType::DATA}));
EXPECT_THAT(visitor.data(), testing::HasSubstr(kBody));
- EXPECT_FALSE(adapter->session().want_write());
+ EXPECT_FALSE(adapter->want_write());
}
// This test verifies how nghttp2 behaves when a data source becomes
@@ -898,7 +1046,7 @@ TEST(NgHttp2AdapterTest, ClientSubmitRequestWithDataProviderAndReadBlock) {
{":path", "/this/is/request/one"}}),
std::move(frame_source), nullptr);
EXPECT_GT(stream_id, 0);
- EXPECT_TRUE(adapter->session().want_write());
+ EXPECT_TRUE(adapter->want_write());
EXPECT_CALL(visitor, OnBeforeFrameSent(HEADERS, stream_id, _, 0x4));
EXPECT_CALL(visitor, OnFrameSent(HEADERS, stream_id, _, 0x4, 0));
@@ -912,23 +1060,23 @@ TEST(NgHttp2AdapterTest, ClientSubmitRequestWithDataProviderAndReadBlock) {
serialized.remove_prefix(strlen(spdy::kHttp2ConnectionHeaderPrefix));
EXPECT_THAT(serialized, EqualsFrames({spdy::SpdyFrameType::HEADERS}));
visitor.Clear();
- EXPECT_FALSE(adapter->session().want_write());
+ EXPECT_FALSE(adapter->want_write());
// Resume the deferred stream.
body1.set_is_data_available(true);
EXPECT_TRUE(adapter->ResumeStream(stream_id));
- EXPECT_TRUE(adapter->session().want_write());
+ EXPECT_TRUE(adapter->want_write());
EXPECT_CALL(visitor, OnFrameSent(DATA, stream_id, _, 0x1, 0));
result = adapter->Send();
EXPECT_EQ(0, result);
EXPECT_THAT(visitor.data(), EqualsFrames({spdy::SpdyFrameType::DATA}));
- EXPECT_FALSE(adapter->session().want_write());
+ EXPECT_FALSE(adapter->want_write());
// Stream data is done, so this stream cannot be resumed.
EXPECT_FALSE(adapter->ResumeStream(stream_id));
- EXPECT_FALSE(adapter->session().want_write());
+ EXPECT_FALSE(adapter->want_write());
}
// This test verifies how nghttp2 behaves when a data source is read block, then
@@ -956,7 +1104,7 @@ TEST(NgHttp2AdapterTest, ClientSubmitRequestEmptyDataWithFin) {
{":path", "/this/is/request/one"}}),
std::move(frame_source), nullptr);
EXPECT_GT(stream_id, 0);
- EXPECT_TRUE(adapter->session().want_write());
+ EXPECT_TRUE(adapter->want_write());
EXPECT_CALL(visitor, OnBeforeFrameSent(HEADERS, stream_id, _, 0x4));
EXPECT_CALL(visitor, OnFrameSent(HEADERS, stream_id, _, 0x4, 0));
@@ -970,23 +1118,23 @@ TEST(NgHttp2AdapterTest, ClientSubmitRequestEmptyDataWithFin) {
serialized.remove_prefix(strlen(spdy::kHttp2ConnectionHeaderPrefix));
EXPECT_THAT(serialized, EqualsFrames({spdy::SpdyFrameType::HEADERS}));
visitor.Clear();
- EXPECT_FALSE(adapter->session().want_write());
+ EXPECT_FALSE(adapter->want_write());
// Resume the deferred stream.
body1.set_is_data_available(true);
EXPECT_TRUE(adapter->ResumeStream(stream_id));
- EXPECT_TRUE(adapter->session().want_write());
+ EXPECT_TRUE(adapter->want_write());
EXPECT_CALL(visitor, OnFrameSent(DATA, stream_id, 0, 0x1, 0));
result = adapter->Send();
EXPECT_EQ(0, result);
EXPECT_THAT(visitor.data(), EqualsFrames({spdy::SpdyFrameType::DATA}));
- EXPECT_FALSE(adapter->session().want_write());
+ EXPECT_FALSE(adapter->want_write());
// Stream data is done, so this stream cannot be resumed.
EXPECT_FALSE(adapter->ResumeStream(stream_id));
- EXPECT_FALSE(adapter->session().want_write());
+ EXPECT_FALSE(adapter->want_write());
}
// This test verifies how nghttp2 behaves when a connection becomes
@@ -1013,13 +1161,13 @@ TEST(NgHttp2AdapterTest, ClientSubmitRequestWithDataProviderAndWriteBlock) {
{":path", "/this/is/request/one"}}),
std::move(frame_source), nullptr);
EXPECT_GT(stream_id, 0);
- EXPECT_TRUE(adapter->session().want_write());
+ EXPECT_TRUE(adapter->want_write());
visitor.set_is_write_blocked(true);
int result = adapter->Send();
EXPECT_EQ(0, result);
EXPECT_THAT(visitor.data(), testing::IsEmpty());
- EXPECT_TRUE(adapter->session().want_write());
+ EXPECT_TRUE(adapter->want_write());
EXPECT_CALL(visitor, OnBeforeFrameSent(HEADERS, stream_id, _, 0x4));
EXPECT_CALL(visitor, OnFrameSent(HEADERS, stream_id, _, 0x4, 0));
@@ -1036,15 +1184,225 @@ TEST(NgHttp2AdapterTest, ClientSubmitRequestWithDataProviderAndWriteBlock) {
serialized.remove_prefix(strlen(spdy::kHttp2ConnectionHeaderPrefix));
EXPECT_THAT(serialized, EqualsFrames({spdy::SpdyFrameType::HEADERS,
spdy::SpdyFrameType::DATA}));
- EXPECT_FALSE(adapter->session().want_write());
+ EXPECT_FALSE(adapter->want_write());
+}
+
+TEST(NgHttp2AdapterTest, SubmitMetadata) {
+ DataSavingVisitor visitor;
+ auto adapter = NgHttp2Adapter::CreateClientAdapter(visitor);
+
+ auto source = absl::make_unique<TestMetadataSource>(ToHeaderBlock(ToHeaders(
+ {{"query-cost", "is too darn high"}, {"secret-sauce", "hollandaise"}})));
+ adapter->SubmitMetadata(1, 16384u, std::move(source));
+ EXPECT_TRUE(adapter->want_write());
+
+ EXPECT_CALL(visitor, OnBeforeFrameSent(kMetadataFrameType, 1, _, 0x4));
+ EXPECT_CALL(visitor, OnFrameSent(kMetadataFrameType, 1, _, 0x4, 0));
+
+ int result = adapter->Send();
+ EXPECT_EQ(0, result);
+ absl::string_view serialized = visitor.data();
+ EXPECT_THAT(serialized,
+ testing::StartsWith(spdy::kHttp2ConnectionHeaderPrefix));
+ serialized.remove_prefix(strlen(spdy::kHttp2ConnectionHeaderPrefix));
+ EXPECT_THAT(
+ serialized,
+ EqualsFrames({static_cast<spdy::SpdyFrameType>(kMetadataFrameType)}));
+ EXPECT_FALSE(adapter->want_write());
+}
+
+TEST(NgHttp2AdapterTest, SubmitMetadataMultipleFrames) {
+ DataSavingVisitor visitor;
+ auto adapter = NgHttp2Adapter::CreateClientAdapter(visitor);
+
+ const auto kLargeValue = std::string(63 * 1024, 'a');
+ auto source = absl::make_unique<TestMetadataSource>(
+ ToHeaderBlock(ToHeaders({{"large-value", kLargeValue}})));
+ adapter->SubmitMetadata(1, 16384u, std::move(source));
+ EXPECT_TRUE(adapter->want_write());
+
+ testing::InSequence seq;
+ EXPECT_CALL(visitor, OnBeforeFrameSent(kMetadataFrameType, 1, _, 0x0));
+ EXPECT_CALL(visitor, OnFrameSent(kMetadataFrameType, 1, _, 0x0, 0));
+ EXPECT_CALL(visitor, OnBeforeFrameSent(kMetadataFrameType, 1, _, 0x0));
+ EXPECT_CALL(visitor, OnFrameSent(kMetadataFrameType, 1, _, 0x0, 0));
+ EXPECT_CALL(visitor, OnBeforeFrameSent(kMetadataFrameType, 1, _, 0x0));
+ EXPECT_CALL(visitor, OnFrameSent(kMetadataFrameType, 1, _, 0x0, 0));
+ EXPECT_CALL(visitor, OnBeforeFrameSent(kMetadataFrameType, 1, _, 0x4));
+ EXPECT_CALL(visitor, OnFrameSent(kMetadataFrameType, 1, _, 0x4, 0));
+
+ int result = adapter->Send();
+ EXPECT_EQ(0, result);
+ absl::string_view serialized = visitor.data();
+ EXPECT_THAT(serialized,
+ testing::StartsWith(spdy::kHttp2ConnectionHeaderPrefix));
+ serialized.remove_prefix(strlen(spdy::kHttp2ConnectionHeaderPrefix));
+ EXPECT_THAT(
+ serialized,
+ EqualsFrames({static_cast<spdy::SpdyFrameType>(kMetadataFrameType),
+ static_cast<spdy::SpdyFrameType>(kMetadataFrameType),
+ static_cast<spdy::SpdyFrameType>(kMetadataFrameType),
+ static_cast<spdy::SpdyFrameType>(kMetadataFrameType)}));
+ EXPECT_FALSE(adapter->want_write());
+}
+
+TEST(NgHttp2AdapterTest, SubmitConnectionMetadata) {
+ DataSavingVisitor visitor;
+ auto adapter = NgHttp2Adapter::CreateClientAdapter(visitor);
+
+ auto source = absl::make_unique<TestMetadataSource>(ToHeaderBlock(ToHeaders(
+ {{"query-cost", "is too darn high"}, {"secret-sauce", "hollandaise"}})));
+ adapter->SubmitMetadata(0, 16384u, std::move(source));
+ EXPECT_TRUE(adapter->want_write());
+
+ EXPECT_CALL(visitor, OnBeforeFrameSent(kMetadataFrameType, 0, _, 0x4));
+ EXPECT_CALL(visitor, OnFrameSent(kMetadataFrameType, 0, _, 0x4, 0));
+
+ int result = adapter->Send();
+ EXPECT_EQ(0, result);
+ absl::string_view serialized = visitor.data();
+ EXPECT_THAT(serialized,
+ testing::StartsWith(spdy::kHttp2ConnectionHeaderPrefix));
+ serialized.remove_prefix(strlen(spdy::kHttp2ConnectionHeaderPrefix));
+ EXPECT_THAT(
+ serialized,
+ EqualsFrames({static_cast<spdy::SpdyFrameType>(kMetadataFrameType)}));
+ EXPECT_FALSE(adapter->want_write());
+}
+
+TEST(NgHttp2AdapterTest, ClientObeysMaxConcurrentStreams) {
+ DataSavingVisitor visitor;
+ auto adapter = NgHttp2Adapter::CreateClientAdapter(visitor);
+ int result = adapter->Send();
+ EXPECT_EQ(0, result);
+ // Client preface does not appear to include the mandatory SETTINGS frame.
+ EXPECT_THAT(visitor.data(),
+ testing::StrEq(spdy::kHttp2ConnectionHeaderPrefix));
+ visitor.Clear();
+
+ const std::string initial_frames =
+ TestFrameSequence()
+ .ServerPreface({{.id = MAX_CONCURRENT_STREAMS, .value = 1}})
+ .Serialize();
+ testing::InSequence s;
+
+ // Server preface (SETTINGS with MAX_CONCURRENT_STREAMS)
+ EXPECT_CALL(visitor, OnFrameHeader(0, 6, SETTINGS, 0));
+ EXPECT_CALL(visitor, OnSettingsStart());
+ EXPECT_CALL(visitor, OnSetting);
+ EXPECT_CALL(visitor, OnSettingsEnd());
+
+ const int64_t initial_result = adapter->ProcessBytes(initial_frames);
+ EXPECT_EQ(initial_frames.size(), initial_result);
+
+ EXPECT_TRUE(adapter->want_write());
+
+ EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, 0, 0x1));
+ EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, 0, 0x1, 0));
+
+ result = adapter->Send();
+ EXPECT_EQ(0, result);
+ EXPECT_THAT(visitor.data(), EqualsFrames({spdy::SpdyFrameType::SETTINGS}));
+ visitor.Clear();
+
+ EXPECT_FALSE(adapter->want_write());
+ const absl::string_view kBody = "This is an example request body.";
+ auto body1 = absl::make_unique<TestDataFrameSource>(visitor, true);
+ body1->AppendPayload(kBody);
+ body1->EndData();
+ const int stream_id =
+ adapter->SubmitRequest(ToHeaders({{":method", "POST"},
+ {":scheme", "http"},
+ {":authority", "example.com"},
+ {":path", "/this/is/request/one"}}),
+ std::move(body1), nullptr);
+ EXPECT_GT(stream_id, 0);
+ EXPECT_TRUE(adapter->want_write());
+
+ EXPECT_CALL(visitor, OnBeforeFrameSent(HEADERS, stream_id, _, 0x4));
+ EXPECT_CALL(visitor, OnFrameSent(HEADERS, stream_id, _, 0x4, 0));
+ EXPECT_CALL(visitor, OnFrameSent(DATA, stream_id, _, 0x1, 0));
+
+ result = adapter->Send();
+ EXPECT_EQ(0, result);
+
+ EXPECT_THAT(visitor.data(), EqualsFrames({spdy::SpdyFrameType::HEADERS,
+ spdy::SpdyFrameType::DATA}));
+ EXPECT_THAT(visitor.data(), testing::HasSubstr(kBody));
+ visitor.Clear();
+ EXPECT_FALSE(adapter->want_write());
+
+ const int next_stream_id =
+ adapter->SubmitRequest(ToHeaders({{":method", "POST"},
+ {":scheme", "http"},
+ {":authority", "example.com"},
+ {":path", "/this/is/request/two"}}),
+ nullptr, nullptr);
+
+ // A new pending stream is created, but because of MAX_CONCURRENT_STREAMS, the
+ // session should not want to write it at the moment.
+ EXPECT_GT(next_stream_id, stream_id);
+ EXPECT_FALSE(adapter->want_write());
+
+ const std::string stream_frames =
+ TestFrameSequence()
+ .Headers(stream_id,
+ {{":status", "200"},
+ {"server", "my-fake-server"},
+ {"date", "Tue, 6 Apr 2021 12:54:01 GMT"}},
+ /*fin=*/false)
+ .Data(stream_id, "This is the response body.", /*fin=*/true)
+ .Serialize();
+
+ EXPECT_CALL(visitor, OnFrameHeader(stream_id, _, HEADERS, 4));
+ EXPECT_CALL(visitor, OnBeginHeadersForStream(stream_id));
+ EXPECT_CALL(visitor, OnHeaderForStream(stream_id, ":status", "200"));
+ EXPECT_CALL(visitor,
+ OnHeaderForStream(stream_id, "server", "my-fake-server"));
+ EXPECT_CALL(visitor, OnHeaderForStream(stream_id, "date",
+ "Tue, 6 Apr 2021 12:54:01 GMT"));
+ EXPECT_CALL(visitor, OnEndHeadersForStream(stream_id));
+ EXPECT_CALL(visitor, OnFrameHeader(stream_id, 26, DATA, 0x1));
+ EXPECT_CALL(visitor, OnBeginDataForStream(stream_id, 26));
+ EXPECT_CALL(visitor,
+ OnDataForStream(stream_id, "This is the response body."));
+ EXPECT_CALL(visitor, OnEndStream(stream_id));
+ EXPECT_CALL(visitor, OnCloseStream(stream_id, Http2ErrorCode::NO_ERROR));
+
+ // The first stream should close, which should make the session want to write
+ // the next stream.
+ const int64_t stream_result = adapter->ProcessBytes(stream_frames);
+ EXPECT_EQ(stream_frames.size(), stream_result);
+ EXPECT_TRUE(adapter->want_write());
+
+ EXPECT_CALL(visitor, OnBeforeFrameSent(HEADERS, next_stream_id, _, 0x5));
+ EXPECT_CALL(visitor, OnFrameSent(HEADERS, next_stream_id, _, 0x5, 0));
+
+ result = adapter->Send();
+ EXPECT_EQ(0, result);
+
+ EXPECT_THAT(visitor.data(), EqualsFrames({spdy::SpdyFrameType::HEADERS}));
+ visitor.Clear();
+ EXPECT_FALSE(adapter->want_write());
+}
+
+TEST(NgHttp2AdapterTest, FailureSendingConnectionPreface) {
+ DataSavingVisitor visitor;
+ auto adapter = NgHttp2Adapter::CreateClientAdapter(visitor);
+
+ visitor.set_has_write_error();
+ EXPECT_CALL(visitor, OnConnectionError);
+
+ int result = adapter->Send();
+ EXPECT_EQ(result, NGHTTP2_ERR_CALLBACK_FAILURE);
}
TEST(NgHttp2AdapterTest, ServerConstruction) {
testing::StrictMock<MockHttp2Visitor> visitor;
auto adapter = NgHttp2Adapter::CreateServerAdapter(visitor);
ASSERT_NE(nullptr, adapter);
- EXPECT_TRUE(adapter->session().want_read());
- EXPECT_FALSE(adapter->session().want_write());
+ EXPECT_TRUE(adapter->want_read());
+ EXPECT_FALSE(adapter->want_write());
EXPECT_TRUE(adapter->IsServerSession());
}
@@ -1098,6 +1456,7 @@ TEST(NgHttp2AdapterTest, ServerHandlesFrames) {
EXPECT_CALL(visitor, OnEndHeadersForStream(1))
.WillOnce(testing::InvokeWithoutArgs([&adapter, kSentinel1]() {
adapter->SetStreamUserData(1, const_cast<char*>(kSentinel1));
+ return true;
}));
EXPECT_CALL(visitor, OnFrameHeader(1, 4, WINDOW_UPDATE, 0));
EXPECT_CALL(visitor, OnWindowUpdate(1, 2000));
@@ -1118,7 +1477,7 @@ TEST(NgHttp2AdapterTest, ServerHandlesFrames) {
EXPECT_CALL(visitor, OnFrameHeader(0, 8, PING, 0));
EXPECT_CALL(visitor, OnPing(47, false));
- const ssize_t result = adapter->ProcessBytes(frames);
+ const int64_t result = adapter->ProcessBytes(frames);
EXPECT_EQ(frames.size(), result);
EXPECT_EQ(kSentinel1, adapter->GetStreamUserData(1));
@@ -1143,7 +1502,7 @@ TEST(NgHttp2AdapterTest, ServerHandlesFrames) {
EXPECT_EQ(adapter->GetSendWindowSize(), kInitialFlowControlWindowSize + 1000);
- EXPECT_TRUE(adapter->session().want_write());
+ EXPECT_TRUE(adapter->want_write());
EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, 0, 0x1));
EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, 0, 0x1, 0));
@@ -1199,10 +1558,10 @@ TEST(NgHttp2AdapterTest, ServerErrorWhileHandlingHeaders) {
EXPECT_CALL(visitor, OnFrameHeader(0, 4, WINDOW_UPDATE, 0));
EXPECT_CALL(visitor, OnWindowUpdate(0, 2000));
- const ssize_t result = adapter->ProcessBytes(frames);
+ const int64_t result = adapter->ProcessBytes(frames);
EXPECT_EQ(frames.size(), result);
- EXPECT_TRUE(adapter->session().want_write());
+ EXPECT_TRUE(adapter->want_write());
EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, 0, 0x1));
EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, 0, 0x1, 0));
@@ -1220,10 +1579,215 @@ TEST(NgHttp2AdapterTest, ServerErrorWhileHandlingHeaders) {
spdy::SpdyFrameType::RST_STREAM}));
}
+TEST(NgHttp2AdapterTest, ServerErrorAfterHandlingHeaders) {
+ DataSavingVisitor visitor;
+ auto adapter = NgHttp2Adapter::CreateServerAdapter(visitor);
+
+ const std::string frames = TestFrameSequence()
+ .ClientPreface()
+ .Headers(1,
+ {{":method", "POST"},
+ {":scheme", "https"},
+ {":authority", "example.com"},
+ {":path", "/this/is/request/one"}},
+ /*fin=*/false)
+ .WindowUpdate(1, 2000)
+ .Data(1, "This is the request body.")
+ .WindowUpdate(0, 2000)
+ .Serialize();
+ testing::InSequence s;
+
+ // Client preface (empty SETTINGS)
+ EXPECT_CALL(visitor, OnFrameHeader(0, 0, SETTINGS, 0));
+ EXPECT_CALL(visitor, OnSettingsStart());
+ EXPECT_CALL(visitor, OnSettingsEnd());
+
+ EXPECT_CALL(visitor, OnFrameHeader(1, _, HEADERS, 4));
+ EXPECT_CALL(visitor, OnBeginHeadersForStream(1));
+ EXPECT_CALL(visitor, OnHeaderForStream(1, ":method", "POST"));
+ EXPECT_CALL(visitor, OnHeaderForStream(1, ":scheme", "https"));
+ EXPECT_CALL(visitor, OnHeaderForStream(1, ":authority", "example.com"));
+ EXPECT_CALL(visitor, OnHeaderForStream(1, ":path", "/this/is/request/one"));
+ EXPECT_CALL(visitor, OnEndHeadersForStream(1))
+ .WillOnce(testing::Return(false));
+ EXPECT_CALL(visitor, OnConnectionError());
+
+ const int64_t result = adapter->ProcessBytes(frames);
+ EXPECT_EQ(-902, result);
+
+ EXPECT_TRUE(adapter->want_write());
+
+ EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, 0, 0x1));
+ EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, 0, 0x1, 0));
+
+ int send_result = adapter->Send();
+ // Some bytes should have been serialized.
+ EXPECT_EQ(0, send_result);
+ // SETTINGS ack
+ EXPECT_THAT(visitor.data(), EqualsFrames({spdy::SpdyFrameType::SETTINGS}));
+}
+
+// Exercises the case when a visitor chooses to reject a frame based solely on
+// the frame header, which is a fatal error for the connection.
+TEST(NgHttp2AdapterTest, ServerRejectsFrameHeader) {
+ DataSavingVisitor visitor;
+ auto adapter = NgHttp2Adapter::CreateServerAdapter(visitor);
+
+ const std::string frames = TestFrameSequence()
+ .ClientPreface()
+ .Ping(64)
+ .Headers(1,
+ {{":method", "POST"},
+ {":scheme", "https"},
+ {":authority", "example.com"},
+ {":path", "/this/is/request/one"}},
+ /*fin=*/false)
+ .WindowUpdate(1, 2000)
+ .Data(1, "This is the request body.")
+ .WindowUpdate(0, 2000)
+ .Serialize();
+ testing::InSequence s;
+
+ // Client preface (empty SETTINGS)
+ EXPECT_CALL(visitor, OnFrameHeader(0, 0, SETTINGS, 0));
+ EXPECT_CALL(visitor, OnSettingsStart());
+ EXPECT_CALL(visitor, OnSettingsEnd());
+
+ EXPECT_CALL(visitor, OnFrameHeader(0, 8, PING, 0))
+ .WillOnce(testing::Return(false));
+ EXPECT_CALL(visitor, OnConnectionError());
+
+ const int64_t result = adapter->ProcessBytes(frames);
+ EXPECT_EQ(-902, result);
+
+ EXPECT_TRUE(adapter->want_write());
+
+ EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, 0, 0x1));
+ EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, 0, 0x1, 0));
+
+ int send_result = adapter->Send();
+ // Some bytes should have been serialized.
+ EXPECT_EQ(0, send_result);
+ // SETTINGS ack
+ EXPECT_THAT(visitor.data(), EqualsFrames({spdy::SpdyFrameType::SETTINGS}));
+}
+
+TEST(NgHttp2AdapterTest, ServerRejectsBeginningOfData) {
+ DataSavingVisitor visitor;
+ auto adapter = NgHttp2Adapter::CreateServerAdapter(visitor);
+
+ const std::string frames = TestFrameSequence()
+ .ClientPreface()
+ .Headers(1,
+ {{":method", "POST"},
+ {":scheme", "https"},
+ {":authority", "example.com"},
+ {":path", "/this/is/request/one"}},
+ /*fin=*/false)
+ .Data(1, "This is the request body.")
+ .Headers(3,
+ {{":method", "GET"},
+ {":scheme", "http"},
+ {":authority", "example.com"},
+ {":path", "/this/is/request/two"}},
+ /*fin=*/true)
+ .RstStream(3, Http2ErrorCode::CANCEL)
+ .Ping(47)
+ .Serialize();
+ testing::InSequence s;
+
+ // Client preface (empty SETTINGS)
+ EXPECT_CALL(visitor, OnFrameHeader(0, 0, SETTINGS, 0));
+ EXPECT_CALL(visitor, OnSettingsStart());
+ EXPECT_CALL(visitor, OnSettingsEnd());
+
+ EXPECT_CALL(visitor, OnFrameHeader(1, _, HEADERS, 4));
+ EXPECT_CALL(visitor, OnBeginHeadersForStream(1));
+ EXPECT_CALL(visitor, OnHeaderForStream(1, ":method", "POST"));
+ EXPECT_CALL(visitor, OnHeaderForStream(1, ":scheme", "https"));
+ EXPECT_CALL(visitor, OnHeaderForStream(1, ":authority", "example.com"));
+ EXPECT_CALL(visitor, OnHeaderForStream(1, ":path", "/this/is/request/one"));
+ EXPECT_CALL(visitor, OnEndHeadersForStream(1));
+ EXPECT_CALL(visitor, OnFrameHeader(1, 25, DATA, 0));
+ EXPECT_CALL(visitor, OnBeginDataForStream(1, 25))
+ .WillOnce(testing::Return(false));
+ EXPECT_CALL(visitor, OnConnectionError());
+
+ const int64_t result = adapter->ProcessBytes(frames);
+ EXPECT_EQ(NGHTTP2_ERR_CALLBACK_FAILURE, result);
+
+ EXPECT_TRUE(adapter->want_write());
+
+ EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, 0, 0x1));
+ EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, 0, 0x1, 0));
+
+ int send_result = adapter->Send();
+ // Some bytes should have been serialized.
+ EXPECT_EQ(0, send_result);
+ // SETTINGS ack.
+ EXPECT_THAT(visitor.data(), EqualsFrames({spdy::SpdyFrameType::SETTINGS}));
+}
+
+TEST(NgHttp2AdapterTest, ServerRejectsStreamData) {
+ DataSavingVisitor visitor;
+ auto adapter = NgHttp2Adapter::CreateServerAdapter(visitor);
+
+ const std::string frames = TestFrameSequence()
+ .ClientPreface()
+ .Headers(1,
+ {{":method", "POST"},
+ {":scheme", "https"},
+ {":authority", "example.com"},
+ {":path", "/this/is/request/one"}},
+ /*fin=*/false)
+ .Data(1, "This is the request body.")
+ .Headers(3,
+ {{":method", "GET"},
+ {":scheme", "http"},
+ {":authority", "example.com"},
+ {":path", "/this/is/request/two"}},
+ /*fin=*/true)
+ .RstStream(3, Http2ErrorCode::CANCEL)
+ .Ping(47)
+ .Serialize();
+ testing::InSequence s;
+
+ // Client preface (empty SETTINGS)
+ EXPECT_CALL(visitor, OnFrameHeader(0, 0, SETTINGS, 0));
+ EXPECT_CALL(visitor, OnSettingsStart());
+ EXPECT_CALL(visitor, OnSettingsEnd());
+
+ EXPECT_CALL(visitor, OnFrameHeader(1, _, HEADERS, 4));
+ EXPECT_CALL(visitor, OnBeginHeadersForStream(1));
+ EXPECT_CALL(visitor, OnHeaderForStream(1, ":method", "POST"));
+ EXPECT_CALL(visitor, OnHeaderForStream(1, ":scheme", "https"));
+ EXPECT_CALL(visitor, OnHeaderForStream(1, ":authority", "example.com"));
+ EXPECT_CALL(visitor, OnHeaderForStream(1, ":path", "/this/is/request/one"));
+ EXPECT_CALL(visitor, OnEndHeadersForStream(1));
+ EXPECT_CALL(visitor, OnFrameHeader(1, 25, DATA, 0));
+ EXPECT_CALL(visitor, OnBeginDataForStream(1, 25));
+ EXPECT_CALL(visitor, OnDataForStream(1, _)).WillOnce(testing::Return(false));
+ EXPECT_CALL(visitor, OnConnectionError());
+
+ const int64_t result = adapter->ProcessBytes(frames);
+ EXPECT_EQ(NGHTTP2_ERR_CALLBACK_FAILURE, result);
+
+ EXPECT_TRUE(adapter->want_write());
+
+ EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, 0, 0x1));
+ EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, 0, 0x1, 0));
+
+ int send_result = adapter->Send();
+ // Some bytes should have been serialized.
+ EXPECT_EQ(0, send_result);
+ // SETTINGS ack.
+ EXPECT_THAT(visitor.data(), EqualsFrames({spdy::SpdyFrameType::SETTINGS}));
+}
+
TEST(NgHttp2AdapterTest, ServerSubmitResponse) {
DataSavingVisitor visitor;
auto adapter = NgHttp2Adapter::CreateServerAdapter(visitor);
- EXPECT_FALSE(adapter->session().want_write());
+ EXPECT_FALSE(adapter->want_write());
const std::string frames = TestFrameSequence()
.ClientPreface()
@@ -1252,16 +1816,17 @@ TEST(NgHttp2AdapterTest, ServerSubmitResponse) {
EXPECT_CALL(visitor, OnEndHeadersForStream(1))
.WillOnce(testing::InvokeWithoutArgs([&adapter, kSentinel1]() {
adapter->SetStreamUserData(1, const_cast<char*>(kSentinel1));
+ return true;
}));
EXPECT_CALL(visitor, OnEndStream(1));
- const ssize_t result = adapter->ProcessBytes(frames);
+ const int64_t result = adapter->ProcessBytes(frames);
EXPECT_EQ(frames.size(), result);
EXPECT_EQ(1, adapter->GetHighestReceivedStreamId());
// Server will want to send a SETTINGS ack.
- EXPECT_TRUE(adapter->session().want_write());
+ EXPECT_TRUE(adapter->want_write());
EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, 0, 0x1));
EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, 0, 0x1, 0));
@@ -1273,7 +1838,7 @@ TEST(NgHttp2AdapterTest, ServerSubmitResponse) {
EXPECT_EQ(0, adapter->GetHpackEncoderDynamicTableSize());
- EXPECT_FALSE(adapter->session().want_write());
+ EXPECT_FALSE(adapter->want_write());
const absl::string_view kBody = "This is an example response body.";
// A data fin is not sent so that the stream remains open, and the flow
// control state can be verified.
@@ -1285,7 +1850,7 @@ TEST(NgHttp2AdapterTest, ServerSubmitResponse) {
{"x-comment", "I have no idea what you're talking about."}}),
std::move(body1));
EXPECT_EQ(submit_result, 0);
- EXPECT_TRUE(adapter->session().want_write());
+ EXPECT_TRUE(adapter->want_write());
// Stream user data should have been set successfully after receiving headers.
EXPECT_EQ(kSentinel1, adapter->GetStreamUserData(1));
@@ -1302,7 +1867,7 @@ TEST(NgHttp2AdapterTest, ServerSubmitResponse) {
EXPECT_THAT(visitor.data(), EqualsFrames({spdy::SpdyFrameType::HEADERS,
spdy::SpdyFrameType::DATA}));
EXPECT_THAT(visitor.data(), testing::HasSubstr(kBody));
- EXPECT_FALSE(adapter->session().want_write());
+ EXPECT_FALSE(adapter->want_write());
// Some data was sent, so the remaining send window size should be less than
// the default.
@@ -1344,12 +1909,12 @@ TEST(NgHttp2AdapterTest, ServerSendsShutdown) {
EXPECT_CALL(visitor, OnHeaderForStream(1, ":path", "/this/is/request/one"));
EXPECT_CALL(visitor, OnEndHeadersForStream(1));
- const ssize_t result = adapter->ProcessBytes(frames);
+ const int64_t result = adapter->ProcessBytes(frames);
EXPECT_EQ(frames.size(), result);
adapter->SubmitShutdownNotice();
- EXPECT_TRUE(adapter->session().want_write());
+ EXPECT_TRUE(adapter->want_write());
EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, 0, 0x1));
EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, 0, 0x1, 0));
@@ -1365,7 +1930,7 @@ TEST(NgHttp2AdapterTest, ServerSendsShutdown) {
TEST(NgHttp2AdapterTest, ServerSendsTrailers) {
DataSavingVisitor visitor;
auto adapter = NgHttp2Adapter::CreateServerAdapter(visitor);
- EXPECT_FALSE(adapter->session().want_write());
+ EXPECT_FALSE(adapter->want_write());
const std::string frames = TestFrameSequence()
.ClientPreface()
@@ -1392,11 +1957,11 @@ TEST(NgHttp2AdapterTest, ServerSendsTrailers) {
EXPECT_CALL(visitor, OnEndHeadersForStream(1));
EXPECT_CALL(visitor, OnEndStream(1));
- const ssize_t result = adapter->ProcessBytes(frames);
+ const int64_t result = adapter->ProcessBytes(frames);
EXPECT_EQ(frames.size(), result);
// Server will want to send a SETTINGS ack.
- EXPECT_TRUE(adapter->session().want_write());
+ EXPECT_TRUE(adapter->want_write());
EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, 0, 0x1));
EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, 0, 0x1, 0));
@@ -1406,7 +1971,7 @@ TEST(NgHttp2AdapterTest, ServerSendsTrailers) {
EXPECT_THAT(visitor.data(), EqualsFrames({spdy::SpdyFrameType::SETTINGS}));
visitor.Clear();
- EXPECT_FALSE(adapter->session().want_write());
+ EXPECT_FALSE(adapter->want_write());
const absl::string_view kBody = "This is an example response body.";
// The body source must indicate that the end of the body is not the end of
@@ -1418,7 +1983,7 @@ TEST(NgHttp2AdapterTest, ServerSendsTrailers) {
1, ToHeaders({{":status", "200"}, {"x-comment", "Sure, sounds good."}}),
std::move(body1));
EXPECT_EQ(submit_result, 0);
- EXPECT_TRUE(adapter->session().want_write());
+ EXPECT_TRUE(adapter->want_write());
EXPECT_CALL(visitor, OnBeforeFrameSent(HEADERS, 1, _, 0x4));
EXPECT_CALL(visitor, OnFrameSent(HEADERS, 1, _, 0x4, 0));
@@ -1430,14 +1995,14 @@ TEST(NgHttp2AdapterTest, ServerSendsTrailers) {
spdy::SpdyFrameType::DATA}));
EXPECT_THAT(visitor.data(), testing::HasSubstr(kBody));
visitor.Clear();
- EXPECT_FALSE(adapter->session().want_write());
+ EXPECT_FALSE(adapter->want_write());
// The body source has been exhausted by the call to Send() above.
int trailer_result = adapter->SubmitTrailer(
1, ToHeaders({{"final-status", "a-ok"},
{"x-comment", "trailers sure are cool"}}));
ASSERT_EQ(trailer_result, 0);
- EXPECT_TRUE(adapter->session().want_write());
+ EXPECT_TRUE(adapter->want_write());
EXPECT_CALL(visitor, OnBeforeFrameSent(HEADERS, 1, _, 0x5));
EXPECT_CALL(visitor, OnFrameSent(HEADERS, 1, _, 0x5, 0));
@@ -1451,7 +2016,7 @@ TEST(NgHttp2AdapterTest, ServerSendsTrailers) {
TEST(NgHttp2AdapterTest, ClientSendsContinuation) {
DataSavingVisitor visitor;
auto adapter = NgHttp2Adapter::CreateServerAdapter(visitor);
- EXPECT_FALSE(adapter->session().want_write());
+ EXPECT_FALSE(adapter->want_write());
const std::string frames = TestFrameSequence()
.ClientPreface()
@@ -1480,14 +2045,14 @@ TEST(NgHttp2AdapterTest, ClientSendsContinuation) {
EXPECT_CALL(visitor, OnEndHeadersForStream(1));
EXPECT_CALL(visitor, OnEndStream(1));
- const size_t result = adapter->ProcessBytes(frames);
+ const int64_t result = adapter->ProcessBytes(frames);
EXPECT_EQ(frames.size(), result);
}
TEST(NgHttp2AdapterTest, ClientSendsMetadataWithContinuation) {
DataSavingVisitor visitor;
auto adapter = NgHttp2Adapter::CreateServerAdapter(visitor);
- EXPECT_FALSE(adapter->session().want_write());
+ EXPECT_FALSE(adapter->want_write());
const std::string frames =
TestFrameSequence()
@@ -1537,7 +2102,7 @@ TEST(NgHttp2AdapterTest, ClientSendsMetadataWithContinuation) {
EXPECT_CALL(visitor, OnMetadataForStream(1, _));
EXPECT_CALL(visitor, OnMetadataEndForStream(1));
- const size_t result = adapter->ProcessBytes(frames);
+ const int64_t result = adapter->ProcessBytes(frames);
EXPECT_EQ(frames.size(), result);
EXPECT_EQ(TestFrameSequence::MetadataBlockForPayload(
"Example connection metadata in multiple frames"),
@@ -1550,7 +2115,7 @@ TEST(NgHttp2AdapterTest, ClientSendsMetadataWithContinuation) {
TEST(NgHttp2AdapterTest, ServerSendsInvalidTrailers) {
DataSavingVisitor visitor;
auto adapter = NgHttp2Adapter::CreateServerAdapter(visitor);
- EXPECT_FALSE(adapter->session().want_write());
+ EXPECT_FALSE(adapter->want_write());
const std::string frames = TestFrameSequence()
.ClientPreface()
@@ -1577,7 +2142,7 @@ TEST(NgHttp2AdapterTest, ServerSendsInvalidTrailers) {
EXPECT_CALL(visitor, OnEndHeadersForStream(1));
EXPECT_CALL(visitor, OnEndStream(1));
- const ssize_t result = adapter->ProcessBytes(frames);
+ const int64_t result = adapter->ProcessBytes(frames);
EXPECT_EQ(frames.size(), result);
const absl::string_view kBody = "This is an example response body.";
@@ -1591,7 +2156,7 @@ TEST(NgHttp2AdapterTest, ServerSendsInvalidTrailers) {
1, ToHeaders({{":status", "200"}, {"x-comment", "Sure, sounds good."}}),
std::move(body1));
EXPECT_EQ(submit_result, 0);
- EXPECT_TRUE(adapter->session().want_write());
+ EXPECT_TRUE(adapter->want_write());
EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, _, 0x1));
EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, _, 0x1, 0));
@@ -1606,13 +2171,13 @@ TEST(NgHttp2AdapterTest, ServerSendsInvalidTrailers) {
spdy::SpdyFrameType::DATA}));
EXPECT_THAT(visitor.data(), testing::HasSubstr(kBody));
visitor.Clear();
- EXPECT_FALSE(adapter->session().want_write());
+ EXPECT_FALSE(adapter->want_write());
// The body source has been exhausted by the call to Send() above.
int trailer_result =
adapter->SubmitTrailer(1, ToHeaders({{":final-status", "a-ok"}}));
ASSERT_EQ(trailer_result, 0);
- EXPECT_TRUE(adapter->session().want_write());
+ EXPECT_TRUE(adapter->want_write());
EXPECT_CALL(visitor, OnBeforeFrameSent(HEADERS, 1, _, 0x5));
EXPECT_CALL(visitor, OnFrameSent(HEADERS, 1, _, 0x5, 0));
diff --git a/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_callbacks.cc b/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_callbacks.cc
index 4a2221ea2ee..648a5219d73 100644
--- a/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_callbacks.cc
+++ b/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_callbacks.cc
@@ -4,12 +4,13 @@
#include <cstring>
#include "absl/strings/string_view.h"
+#include "http2/adapter/data_source.h"
#include "http2/adapter/http2_protocol.h"
#include "http2/adapter/http2_visitor_interface.h"
#include "http2/adapter/nghttp2_data_provider.h"
#include "http2/adapter/nghttp2_util.h"
-#include "third_party/nghttp2/nghttp2.h"
#include "third_party/nghttp2/src/lib/includes/nghttp2/nghttp2.h"
+#include "common/platform/api/quiche_bug_tracker.h"
#include "common/platform/api/quiche_logging.h"
#include "common/quiche_endian.h"
@@ -21,7 +22,7 @@ ssize_t OnReadyToSend(nghttp2_session* /* session */, const uint8_t* data,
size_t length, int flags, void* user_data) {
QUICHE_CHECK_NE(user_data, nullptr);
auto* visitor = static_cast<Http2VisitorInterface*>(user_data);
- const ssize_t result = visitor->OnReadyToSend(ToStringView(data, length));
+ const int64_t result = visitor->OnReadyToSend(ToStringView(data, length));
QUICHE_VLOG(1) << "OnReadyToSend(length=" << length << ", flags=" << flags
<< ") returning " << result;
if (result > 0) {
@@ -38,14 +39,17 @@ int OnBeginFrame(nghttp2_session* /* session */,
void* user_data) {
QUICHE_CHECK_NE(user_data, nullptr);
auto* visitor = static_cast<Http2VisitorInterface*>(user_data);
- visitor->OnFrameHeader(header->stream_id, header->length, header->type,
- header->flags);
+ bool result = visitor->OnFrameHeader(header->stream_id, header->length,
+ header->type, header->flags);
+ if (!result) {
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+ }
if (header->type == NGHTTP2_DATA) {
- visitor->OnBeginDataForStream(header->stream_id, header->length);
+ result = visitor->OnBeginDataForStream(header->stream_id, header->length);
} else if (header->type == kMetadataFrameType) {
visitor->OnBeginMetadataForStream(header->stream_id, header->length);
}
- return 0;
+ return result ? 0 : NGHTTP2_ERR_CALLBACK_FAILURE;
}
int OnFrameReceived(nghttp2_session* /* session */,
@@ -66,7 +70,10 @@ int OnFrameReceived(nghttp2_session* /* session */,
break;
case NGHTTP2_HEADERS: {
if (frame->hd.flags & NGHTTP2_FLAG_END_HEADERS) {
- visitor->OnEndHeadersForStream(stream_id);
+ const bool result = visitor->OnEndHeadersForStream(stream_id);
+ if (!result) {
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+ }
}
if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
visitor->OnEndStream(stream_id);
@@ -94,8 +101,7 @@ int OnFrameReceived(nghttp2_session* /* session */,
nghttp2_settings_entry entry = frame->settings.iv[i];
// The nghttp2_settings_entry uses int32_t for the ID; we must cast.
visitor->OnSetting(Http2Setting{
- .id = static_cast<Http2SettingsId>(entry.settings_id),
- .value = entry.value});
+ static_cast<Http2SettingsId>(entry.settings_id), entry.value});
}
visitor->OnSettingsEnd();
}
@@ -121,9 +127,12 @@ int OnFrameReceived(nghttp2_session* /* session */,
absl::string_view opaque_data(
reinterpret_cast<const char*>(frame->goaway.opaque_data),
frame->goaway.opaque_data_len);
- visitor->OnGoAway(frame->goaway.last_stream_id,
- ToHttp2ErrorCode(frame->goaway.error_code),
- opaque_data);
+ const bool result = visitor->OnGoAway(
+ frame->goaway.last_stream_id,
+ ToHttp2ErrorCode(frame->goaway.error_code), opaque_data);
+ if (!result) {
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+ }
break;
}
case NGHTTP2_WINDOW_UPDATE: {
@@ -210,9 +219,9 @@ int OnDataChunk(nghttp2_session* /* session */, uint8_t /*flags*/,
void* user_data) {
QUICHE_CHECK_NE(user_data, nullptr);
auto* visitor = static_cast<Http2VisitorInterface*>(user_data);
- visitor->OnDataForStream(
+ const bool result = visitor->OnDataForStream(
stream_id, absl::string_view(reinterpret_cast<const char*>(data), len));
- return 0;
+ return result ? 0 : NGHTTP2_ERR_CALLBACK_FAILURE;
}
int OnStreamClosed(nghttp2_session* /* session */,
@@ -235,8 +244,9 @@ int OnExtensionChunkReceived(nghttp2_session* /*session*/,
<< static_cast<int>(hd->type);
return NGHTTP2_ERR_CANCEL;
}
- visitor->OnMetadataForStream(hd->stream_id, ToStringView(data, len));
- return 0;
+ const bool result =
+ visitor->OnMetadataForStream(hd->stream_id, ToStringView(data, len));
+ return result ? 0 : NGHTTP2_ERR_CALLBACK_FAILURE;
}
int OnUnpackExtensionCallback(nghttp2_session* /*session*/, void** /*payload*/,
@@ -256,11 +266,21 @@ ssize_t OnPackExtensionCallback(nghttp2_session* /*session*/, uint8_t* buf,
size_t len, const nghttp2_frame* frame,
void* user_data) {
QUICHE_CHECK_NE(user_data, nullptr);
- auto* visitor = static_cast<Http2VisitorInterface*>(user_data);
- ssize_t written = 0;
- visitor->OnReadyToSendMetadataForStream(
- frame->hd.stream_id, reinterpret_cast<char*>(buf), len, &written);
- return written;
+ auto* source = static_cast<MetadataSource*>(frame->ext.payload);
+ if (source == nullptr) {
+ QUICHE_BUG(payload_is_nullptr) << "Extension frame payload for stream "
+ << frame->hd.stream_id << " is null!";
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+ }
+ const std::pair<int64_t, bool> result = source->Pack(buf, len);
+ if (result.first < 0) {
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+ }
+ const bool end_metadata_flag = (frame->hd.flags & kMetadataEndFlag);
+ QUICHE_LOG_IF(DFATAL, result.second != end_metadata_flag)
+ << "Metadata ends: " << result.second
+ << " has kMetadataEndFlag: " << end_metadata_flag;
+ return result.first;
}
int OnError(nghttp2_session* /*session*/, int /*lib_error_code*/,
diff --git a/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_callbacks.h b/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_callbacks.h
index 696b6847509..75640ed7442 100644
--- a/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_callbacks.h
+++ b/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_callbacks.h
@@ -1,6 +1,8 @@
#ifndef QUICHE_HTTP2_ADAPTER_NGHTTP2_CALLBACKS_H_
#define QUICHE_HTTP2_ADAPTER_NGHTTP2_CALLBACKS_H_
+#include <cstdint>
+
#include "http2/adapter/http2_protocol.h"
#include "http2/adapter/nghttp2_util.h"
#include "third_party/nghttp2/src/lib/includes/nghttp2/nghttp2.h"
diff --git a/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_data_provider.h b/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_data_provider.h
index 241bab91cdd..9e9119f2e93 100644
--- a/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_data_provider.h
+++ b/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_data_provider.h
@@ -1,6 +1,9 @@
#ifndef QUICHE_HTTP2_ADAPTER_NGHTTP2_DATA_PROVIDER_H_
#define QUICHE_HTTP2_ADAPTER_NGHTTP2_DATA_PROVIDER_H_
+#include <cstdint>
+#include <memory>
+
#include "http2/adapter/data_source.h"
#include "third_party/nghttp2/src/lib/includes/nghttp2/nghttp2.h"
diff --git a/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_session.cc b/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_session.cc
index 9868958bc67..13867bd978d 100644
--- a/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_session.cc
+++ b/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_session.cc
@@ -10,7 +10,7 @@ NgHttp2Session::NgHttp2Session(Perspective perspective,
const nghttp2_option* options, void* userdata)
: session_(MakeSessionPtr(nullptr)), perspective_(perspective) {
nghttp2_session* session;
- switch (perspective) {
+ switch (perspective_) {
case Perspective::kClient:
nghttp2_session_client_new2(&session, callbacks.get(), userdata, options);
break;
@@ -30,7 +30,7 @@ NgHttp2Session::~NgHttp2Session() {
<< " or pending writes: " << pending_writes;
}
-ssize_t NgHttp2Session::ProcessBytes(absl::string_view bytes) {
+int64_t NgHttp2Session::ProcessBytes(absl::string_view bytes) {
return nghttp2_session_mem_recv(
session_.get(), reinterpret_cast<const uint8_t*>(bytes.data()),
bytes.size());
diff --git a/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_session.h b/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_session.h
index 4339875588c..f84713f095c 100644
--- a/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_session.h
+++ b/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_session.h
@@ -1,6 +1,8 @@
#ifndef QUICHE_HTTP2_ADAPTER_NGHTTP2_SESSION_H_
#define QUICHE_HTTP2_ADAPTER_NGHTTP2_SESSION_H_
+#include <cstdint>
+
#include "http2/adapter/http2_session.h"
#include "http2/adapter/nghttp2_util.h"
#include "third_party/nghttp2/src/lib/includes/nghttp2/nghttp2.h"
@@ -18,7 +20,7 @@ class QUICHE_EXPORT_PRIVATE NgHttp2Session : public Http2Session {
const nghttp2_option* options, void* userdata);
~NgHttp2Session() override;
- ssize_t ProcessBytes(absl::string_view bytes) override;
+ int64_t ProcessBytes(absl::string_view bytes) override;
int Consume(Http2StreamId stream_id, size_t num_bytes) override;
diff --git a/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_session_test.cc b/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_session_test.cc
index 487843bcc52..22103942d83 100644
--- a/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_session_test.cc
+++ b/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_session_test.cc
@@ -6,6 +6,7 @@
#include "http2/adapter/test_frame_sequence.h"
#include "http2/adapter/test_utils.h"
#include "common/platform/api/quiche_test.h"
+#include "common/platform/api/quiche_test_helpers.h"
namespace http2 {
namespace adapter {
@@ -77,7 +78,7 @@ TEST_F(NgHttp2SessionTest, ClientHandlesFrames) {
EXPECT_CALL(visitor_, OnFrameHeader(0, 4, WINDOW_UPDATE, 0));
EXPECT_CALL(visitor_, OnWindowUpdate(0, 1000));
- const ssize_t initial_result = session.ProcessBytes(initial_frames);
+ const int64_t initial_result = session.ProcessBytes(initial_frames);
EXPECT_EQ(initial_frames.size(), initial_result);
EXPECT_EQ(session.GetRemoteWindowSize(),
@@ -176,7 +177,7 @@ TEST_F(NgHttp2SessionTest, ClientHandlesFrames) {
EXPECT_CALL(visitor_, OnFrameHeader(0, 19, GOAWAY, 0));
EXPECT_CALL(visitor_,
OnGoAway(5, Http2ErrorCode::ENHANCE_YOUR_CALM, "calm down!!"));
- const ssize_t stream_result = session.ProcessBytes(stream_frames);
+ const int64_t stream_result = session.ProcessBytes(stream_frames);
EXPECT_EQ(stream_frames.size(), stream_result);
// Even though the client recieved a GOAWAY, streams 1 and 5 are still active.
@@ -275,7 +276,7 @@ TEST_F(NgHttp2SessionTest, ServerHandlesFrames) {
EXPECT_CALL(visitor_, OnFrameHeader(0, 8, PING, 0));
EXPECT_CALL(visitor_, OnPing(47, false));
- const ssize_t result = session.ProcessBytes(frames);
+ const int64_t result = session.ProcessBytes(frames);
EXPECT_EQ(frames.size(), result);
EXPECT_EQ(session.GetRemoteWindowSize(),
@@ -298,6 +299,23 @@ TEST_F(NgHttp2SessionTest, ServerHandlesFrames) {
spdy::SpdyFrameType::PING}));
}
+// Verifies that a null payload is caught by the OnPackExtensionCallback
+// implementation.
+TEST_F(NgHttp2SessionTest, NullPayload) {
+ NgHttp2Session session(Perspective::kClient, CreateCallbacks(), options_,
+ &visitor_);
+
+ void* payload = nullptr;
+ const int result = nghttp2_submit_extension(
+ session.raw_ptr(), kMetadataFrameType, 0, 1, payload);
+ ASSERT_EQ(0, result);
+ EXPECT_TRUE(session.want_write());
+ int send_result = -1;
+ EXPECT_QUICHE_BUG(send_result = nghttp2_session_send(session.raw_ptr()),
+ "Extension frame payload for stream 1 is null!");
+ EXPECT_EQ(NGHTTP2_ERR_CALLBACK_FAILURE, send_result);
+}
+
} // namespace
} // namespace test
} // namespace adapter
diff --git a/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_test_utils.h b/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_test_utils.h
index 9b772ffda63..abb11dde076 100644
--- a/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_test_utils.h
+++ b/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_test_utils.h
@@ -1,6 +1,7 @@
#ifndef QUICHE_HTTP2_ADAPTER_NGHTTP2_TEST_UTILS_H_
#define QUICHE_HTTP2_ADAPTER_NGHTTP2_TEST_UTILS_H_
+#include <cstdint>
#include <vector>
#include "absl/strings/string_view.h"
diff --git a/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_util.cc b/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_util.cc
index efb811fc35c..4bfced670ee 100644
--- a/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_util.cc
+++ b/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_util.cc
@@ -131,11 +131,10 @@ class Nghttp2DataFrameSource : public DataFrameSource {
send_data_(std::move(send_data)),
user_data_(user_data) {}
- std::pair<ssize_t, bool> SelectPayloadLength(size_t max_length) override {
+ std::pair<int64_t, bool> SelectPayloadLength(size_t max_length) override {
const int32_t stream_id = 0;
uint32_t data_flags = 0;
- QUICHE_LOG(INFO) << "Invoking read callback";
- ssize_t result = provider_.read_callback(
+ int64_t result = provider_.read_callback(
nullptr /* session */, stream_id, nullptr /* buf */, max_length,
&data_flags, &provider_.source, nullptr /* user_data */);
if (result == NGHTTP2_ERR_DEFERRED) {
diff --git a/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_adapter.cc b/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_adapter.cc
index 27f011ec62f..19841731a0e 100644
--- a/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_adapter.cc
+++ b/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_adapter.cc
@@ -34,7 +34,7 @@ bool OgHttp2Adapter::IsServerSession() const {
return session_->IsServerSession();
}
-ssize_t OgHttp2Adapter::ProcessBytes(absl::string_view bytes) {
+int64_t OgHttp2Adapter::ProcessBytes(absl::string_view bytes) {
return session_->ProcessBytes(bytes);
}
@@ -76,7 +76,10 @@ void OgHttp2Adapter::SubmitWindowUpdate(Http2StreamId stream_id,
}
void OgHttp2Adapter::SubmitMetadata(Http2StreamId stream_id,
+ size_t /* max_frame_size */,
std::unique_ptr<MetadataSource> source) {
+ // Not necessary to pass max_frame_size along, since OgHttp2Session tracks the
+ // peer's advertised max frame size.
session_->SubmitMetadata(stream_id, std::move(source));
}
@@ -155,10 +158,6 @@ bool OgHttp2Adapter::ResumeStream(Http2StreamId stream_id) {
return session_->ResumeStream(stream_id);
}
-const Http2Session& OgHttp2Adapter::session() const {
- return *session_;
-}
-
OgHttp2Adapter::OgHttp2Adapter(Http2VisitorInterface& visitor, Options options)
: Http2Adapter(visitor),
session_(absl::make_unique<OgHttp2Session>(visitor, std::move(options))) {
diff --git a/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_adapter.h b/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_adapter.h
index 9c7bad3c575..0aae5ab1990 100644
--- a/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_adapter.h
+++ b/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_adapter.h
@@ -1,6 +1,7 @@
#ifndef QUICHE_HTTP2_ADAPTER_OGHTTP2_ADAPTER_H_
#define QUICHE_HTTP2_ADAPTER_OGHTTP2_ADAPTER_H_
+#include <cstdint>
#include <memory>
#include "http2/adapter/http2_adapter.h"
@@ -17,11 +18,13 @@ class QUICHE_EXPORT_PRIVATE OgHttp2Adapter : public Http2Adapter {
static std::unique_ptr<OgHttp2Adapter> Create(Http2VisitorInterface& visitor,
Options options);
- ~OgHttp2Adapter();
+ ~OgHttp2Adapter() override;
// From Http2Adapter.
bool IsServerSession() const override;
- ssize_t ProcessBytes(absl::string_view bytes) override;
+ bool want_read() const override { return session_->want_read(); }
+ bool want_write() const override { return session_->want_write(); }
+ int64_t ProcessBytes(absl::string_view bytes) override;
void SubmitSettings(absl::Span<const Http2Setting> settings) override;
void SubmitPriorityForStream(Http2StreamId stream_id,
Http2StreamId parent_stream_id,
@@ -34,7 +37,7 @@ class QUICHE_EXPORT_PRIVATE OgHttp2Adapter : public Http2Adapter {
absl::string_view opaque_data) override;
void SubmitWindowUpdate(Http2StreamId stream_id,
int window_increment) override;
- void SubmitMetadata(Http2StreamId stream_id,
+ void SubmitMetadata(Http2StreamId stream_id, size_t max_frame_size,
std::unique_ptr<MetadataSource> source) override;
int Send() override;
int GetSendWindowSize() const override;
@@ -61,8 +64,6 @@ class QUICHE_EXPORT_PRIVATE OgHttp2Adapter : public Http2Adapter {
void* GetStreamUserData(Http2StreamId stream_id) override;
bool ResumeStream(Http2StreamId stream_id) override;
- const Http2Session& session() const;
-
private:
OgHttp2Adapter(Http2VisitorInterface& visitor, Options options);
diff --git a/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_adapter_test.cc b/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_adapter_test.cc
index 03b45df6aa9..413db77bfff 100644
--- a/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_adapter_test.cc
+++ b/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_adapter_test.cc
@@ -1,6 +1,10 @@
#include "http2/adapter/oghttp2_adapter.h"
+#include <string>
+
#include "absl/strings/str_join.h"
+#include "http2/adapter/http2_protocol.h"
+#include "http2/adapter/http2_visitor_interface.h"
#include "http2/adapter/mock_http2_visitor.h"
#include "http2/adapter/oghttp2_util.h"
#include "http2/adapter/test_frame_sequence.h"
@@ -124,13 +128,13 @@ TEST(OgHttp2AdapterClientTest, ClientHandlesTrailers) {
EXPECT_CALL(visitor, OnEndStream(1));
EXPECT_CALL(visitor, OnCloseStream(1, Http2ErrorCode::NO_ERROR));
- const size_t stream_result = adapter->ProcessBytes(stream_frames);
- EXPECT_EQ(stream_frames.size(), stream_result);
+ const int64_t stream_result = adapter->ProcessBytes(stream_frames);
+ EXPECT_EQ(stream_frames.size(), static_cast<size_t>(stream_result));
EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, _, 0x1));
EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, _, 0x1, 0));
- EXPECT_TRUE(adapter->session().want_write());
+ EXPECT_TRUE(adapter->want_write());
result = adapter->Send();
EXPECT_EQ(0, result);
EXPECT_THAT(visitor.data(), EqualsFrames({spdy::SpdyFrameType::SETTINGS}));
@@ -208,13 +212,91 @@ TEST(OgHttp2AdapterClientTest, ClientHandlesMetadata) {
EXPECT_CALL(visitor, OnEndStream(1));
EXPECT_CALL(visitor, OnCloseStream(1, Http2ErrorCode::NO_ERROR));
- const size_t stream_result = adapter->ProcessBytes(stream_frames);
- EXPECT_EQ(stream_frames.size(), stream_result);
+ const int64_t stream_result = adapter->ProcessBytes(stream_frames);
+ EXPECT_EQ(stream_frames.size(), static_cast<size_t>(stream_result));
EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, _, 0x1));
EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, _, 0x1, 0));
- EXPECT_TRUE(adapter->session().want_write());
+ EXPECT_TRUE(adapter->want_write());
+ result = adapter->Send();
+ EXPECT_EQ(0, result);
+ EXPECT_THAT(visitor.data(), EqualsFrames({spdy::SpdyFrameType::SETTINGS}));
+}
+
+TEST(OgHttp2AdapterClientTest, ClientHandlesMetadataWithError) {
+ DataSavingVisitor visitor;
+ OgHttp2Adapter::Options options{.perspective = Perspective::kClient};
+ auto adapter = OgHttp2Adapter::Create(visitor, options);
+
+ testing::InSequence s;
+
+ const std::vector<const Header> headers1 =
+ ToHeaders({{":method", "GET"},
+ {":scheme", "http"},
+ {":authority", "example.com"},
+ {":path", "/this/is/request/one"}});
+
+ const char* kSentinel1 = "arbitrary pointer 1";
+ const int32_t stream_id1 =
+ adapter->SubmitRequest(headers1, nullptr, const_cast<char*>(kSentinel1));
+ ASSERT_GT(stream_id1, 0);
+ QUICHE_LOG(INFO) << "Created stream: " << stream_id1;
+
+ EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, _, 0x0));
+ EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, _, 0x0, 0));
+ EXPECT_CALL(visitor, OnBeforeFrameSent(HEADERS, stream_id1, _, 0x5));
+ EXPECT_CALL(visitor, OnFrameSent(HEADERS, stream_id1, _, 0x5, 0));
+
+ int result = adapter->Send();
+ EXPECT_EQ(0, result);
+ visitor.Clear();
+
+ const std::string stream_frames =
+ TestFrameSequence()
+ .ServerPreface()
+ .Metadata(0, "Example connection metadata")
+ .Headers(1,
+ {{":status", "200"},
+ {"server", "my-fake-server"},
+ {"date", "Tue, 6 Apr 2021 12:54:01 GMT"}},
+ /*fin=*/false)
+ .Metadata(1, "Example stream metadata")
+ .Data(1, "This is the response body.", true)
+ .Serialize();
+
+ // Server preface (empty SETTINGS)
+ EXPECT_CALL(visitor, OnFrameHeader(0, 0, SETTINGS, 0));
+ EXPECT_CALL(visitor, OnSettingsStart());
+ EXPECT_CALL(visitor, OnSettingsEnd());
+
+ EXPECT_CALL(visitor, OnFrameHeader(0, _, kMetadataFrameType, 4));
+ EXPECT_CALL(visitor, OnBeginMetadataForStream(0, _));
+ EXPECT_CALL(visitor, OnMetadataForStream(0, _));
+ EXPECT_CALL(visitor, OnMetadataEndForStream(0));
+ EXPECT_CALL(visitor, OnFrameHeader(1, _, HEADERS, 4));
+ EXPECT_CALL(visitor, OnBeginHeadersForStream(1));
+ EXPECT_CALL(visitor, OnHeaderForStream(1, ":status", "200"));
+ EXPECT_CALL(visitor, OnHeaderForStream(1, "server", "my-fake-server"));
+ EXPECT_CALL(visitor,
+ OnHeaderForStream(1, "date", "Tue, 6 Apr 2021 12:54:01 GMT"));
+ EXPECT_CALL(visitor, OnEndHeadersForStream(1));
+ EXPECT_CALL(visitor, OnFrameHeader(1, _, kMetadataFrameType, 4));
+ EXPECT_CALL(visitor, OnBeginMetadataForStream(1, _));
+ EXPECT_CALL(visitor, OnMetadataForStream(1, _))
+ .WillOnce(testing::Return(false));
+ // Remaining frames are not processed due to the error.
+ EXPECT_CALL(visitor, OnConnectionError());
+
+ const int64_t stream_result = adapter->ProcessBytes(stream_frames);
+ // Negative integer returned to indicate an error.
+ EXPECT_LT(stream_result, 0);
+
+ EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, _, 0x1));
+ EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, _, 0x1, 0));
+
+ EXPECT_FALSE(adapter->want_read());
+ EXPECT_TRUE(adapter->want_write());
result = adapter->Send();
EXPECT_EQ(0, result);
EXPECT_THAT(visitor.data(), EqualsFrames({spdy::SpdyFrameType::SETTINGS}));
@@ -284,8 +366,8 @@ TEST(OgHttp2AdapterClientTest, ClientRstStreamWhileHandlingHeaders) {
EXPECT_CALL(visitor, OnBeginDataForStream(1, _));
EXPECT_CALL(visitor, OnDataForStream(1, "This is the response body."));
- const size_t stream_result = adapter->ProcessBytes(stream_frames);
- EXPECT_EQ(stream_frames.size(), stream_result);
+ const int64_t stream_result = adapter->ProcessBytes(stream_frames);
+ EXPECT_EQ(stream_frames.size(), static_cast<size_t>(stream_result));
EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, 0, 0x1));
EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, 0, 0x1, 0));
@@ -295,7 +377,7 @@ TEST(OgHttp2AdapterClientTest, ClientRstStreamWhileHandlingHeaders) {
static_cast<int>(Http2ErrorCode::REFUSED_STREAM)));
EXPECT_CALL(visitor, OnCloseStream(1, Http2ErrorCode::NO_ERROR));
- EXPECT_TRUE(adapter->session().want_write());
+ EXPECT_TRUE(adapter->want_write());
result = adapter->Send();
EXPECT_EQ(0, result);
EXPECT_THAT(visitor.data(), EqualsFrames({spdy::SpdyFrameType::SETTINGS,
@@ -366,13 +448,13 @@ TEST(OgHttp2AdapterClientTest, ClientConnectionErrorWhileHandlingHeaders) {
EXPECT_CALL(visitor, OnBeginDataForStream(1, _));
EXPECT_CALL(visitor, OnDataForStream(1, "This is the response body."));
- const size_t stream_result = adapter->ProcessBytes(stream_frames);
- EXPECT_EQ(stream_frames.size(), stream_result);
+ const int64_t stream_result = adapter->ProcessBytes(stream_frames);
+ EXPECT_LT(stream_result, 0);
EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, 0, 0x1));
EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, 0, 0x1, 0));
- EXPECT_TRUE(adapter->session().want_write());
+ EXPECT_TRUE(adapter->want_write());
result = adapter->Send();
EXPECT_EQ(0, result);
EXPECT_THAT(visitor.data(), EqualsFrames({spdy::SpdyFrameType::SETTINGS}));
@@ -438,13 +520,13 @@ TEST(OgHttp2AdapterClientTest, ClientRejectsHeaders) {
EXPECT_CALL(visitor, OnBeginDataForStream(1, _));
EXPECT_CALL(visitor, OnDataForStream(1, "This is the response body."));
- const size_t stream_result = adapter->ProcessBytes(stream_frames);
- EXPECT_EQ(stream_result, stream_frames.size());
+ const int64_t stream_result = adapter->ProcessBytes(stream_frames);
+ EXPECT_LT(stream_result, 0);
EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, 0, 0x1));
EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, 0, 0x1, 0));
- EXPECT_TRUE(adapter->session().want_write());
+ EXPECT_TRUE(adapter->want_write());
result = adapter->Send();
EXPECT_EQ(0, result);
EXPECT_THAT(visitor.data(), EqualsFrames({spdy::SpdyFrameType::SETTINGS}));
@@ -518,8 +600,8 @@ TEST(OgHttp2AdapterClientTest, DISABLED_ClientHandlesInvalidTrailers) {
// Bad status trailer will cause a PROTOCOL_ERROR. The header is never
// delivered in an OnHeaderForStream callback.
- const size_t stream_result = adapter->ProcessBytes(stream_frames);
- EXPECT_EQ(stream_frames.size(), stream_result);
+ const int64_t stream_result = adapter->ProcessBytes(stream_frames);
+ EXPECT_EQ(stream_frames.size(), static_cast<size_t>(stream_result));
EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, 0, 0x1));
EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, 0, 0x1, 0));
@@ -527,18 +609,235 @@ TEST(OgHttp2AdapterClientTest, DISABLED_ClientHandlesInvalidTrailers) {
EXPECT_CALL(visitor, OnFrameSent(RST_STREAM, stream_id1, 4, 0x0, 1));
EXPECT_CALL(visitor, OnCloseStream(1, Http2ErrorCode::PROTOCOL_ERROR));
- EXPECT_TRUE(adapter->session().want_write());
+ EXPECT_TRUE(adapter->want_write());
result = adapter->Send();
EXPECT_EQ(0, result);
EXPECT_THAT(visitor.data(), EqualsFrames({spdy::SpdyFrameType::SETTINGS,
spdy::SpdyFrameType::RST_STREAM}));
}
+TEST(OgHttp2AdapterClientTest, ClientFailsOnGoAway) {
+ DataSavingVisitor visitor;
+ OgHttp2Adapter::Options options{.perspective = Perspective::kClient};
+ auto adapter = OgHttp2Adapter::Create(visitor, options);
+
+ testing::InSequence s;
+
+ const std::vector<const Header> headers1 =
+ ToHeaders({{":method", "GET"},
+ {":scheme", "http"},
+ {":authority", "example.com"},
+ {":path", "/this/is/request/one"}});
+
+ const char* kSentinel1 = "arbitrary pointer 1";
+ const int32_t stream_id1 =
+ adapter->SubmitRequest(headers1, nullptr, const_cast<char*>(kSentinel1));
+ ASSERT_GT(stream_id1, 0);
+ QUICHE_LOG(INFO) << "Created stream: " << stream_id1;
+
+ EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, 0, 0x0));
+ EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, 0, 0x0, 0));
+ EXPECT_CALL(visitor, OnBeforeFrameSent(HEADERS, stream_id1, _, 0x5));
+ EXPECT_CALL(visitor, OnFrameSent(HEADERS, stream_id1, _, 0x5, 0));
+
+ int result = adapter->Send();
+ EXPECT_EQ(0, result);
+ absl::string_view data = visitor.data();
+ EXPECT_THAT(data, testing::StartsWith(spdy::kHttp2ConnectionHeaderPrefix));
+ data.remove_prefix(strlen(spdy::kHttp2ConnectionHeaderPrefix));
+ EXPECT_THAT(data, EqualsFrames({spdy::SpdyFrameType::SETTINGS,
+ spdy::SpdyFrameType::HEADERS}));
+ visitor.Clear();
+
+ const std::string stream_frames =
+ TestFrameSequence()
+ .ServerPreface()
+ .Headers(1,
+ {{":status", "200"},
+ {"server", "my-fake-server"},
+ {"date", "Tue, 6 Apr 2021 12:54:01 GMT"}},
+ /*fin=*/false)
+ .GoAway(1, Http2ErrorCode::INTERNAL_ERROR, "indigestion")
+ .Data(1, "This is the response body.")
+ .Serialize();
+
+ // Server preface (empty SETTINGS)
+ EXPECT_CALL(visitor, OnFrameHeader(0, 0, SETTINGS, 0));
+ EXPECT_CALL(visitor, OnSettingsStart());
+ EXPECT_CALL(visitor, OnSettingsEnd());
+
+ EXPECT_CALL(visitor, OnFrameHeader(1, _, HEADERS, 4));
+ EXPECT_CALL(visitor, OnBeginHeadersForStream(1));
+ EXPECT_CALL(visitor, OnHeaderForStream(1, ":status", "200"));
+ EXPECT_CALL(visitor, OnHeaderForStream(1, "server", "my-fake-server"));
+ EXPECT_CALL(visitor,
+ OnHeaderForStream(1, "date", "Tue, 6 Apr 2021 12:54:01 GMT"));
+ EXPECT_CALL(visitor, OnEndHeadersForStream(1));
+ EXPECT_CALL(visitor, OnFrameHeader(0, _, GOAWAY, 0));
+ // TODO(birenroy): Pass the GOAWAY opaque data through the oghttp2 stack.
+ EXPECT_CALL(visitor, OnGoAway(1, Http2ErrorCode::INTERNAL_ERROR, ""))
+ .WillOnce(testing::Return(false));
+ EXPECT_CALL(visitor, OnConnectionError());
+
+ const int64_t stream_result = adapter->ProcessBytes(stream_frames);
+ EXPECT_LT(stream_result, 0);
+
+ EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, 0, 0x1));
+ EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, 0, 0x1, 0));
+
+ EXPECT_TRUE(adapter->want_write());
+ result = adapter->Send();
+ EXPECT_EQ(0, result);
+ EXPECT_THAT(visitor.data(), EqualsFrames({spdy::SpdyFrameType::SETTINGS}));
+}
+
+TEST(OgHttp2AdapterClientTest, ClientObeysMaxConcurrentStreams) {
+ DataSavingVisitor visitor;
+ OgHttp2Adapter::Options options{.perspective = Perspective::kClient};
+ auto adapter = OgHttp2Adapter::Create(visitor, options);
+
+ EXPECT_FALSE(adapter->want_write());
+
+ EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, _, 0x0));
+ EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, _, 0x0, 0));
+
+ // Even though the user has not queued any frames for the session, it should
+ // still send the connection preface.
+ int result = adapter->Send();
+ EXPECT_EQ(0, result);
+ absl::string_view serialized = visitor.data();
+ EXPECT_THAT(serialized,
+ testing::StartsWith(spdy::kHttp2ConnectionHeaderPrefix));
+ serialized.remove_prefix(strlen(spdy::kHttp2ConnectionHeaderPrefix));
+ // Initial SETTINGS.
+ EXPECT_THAT(serialized, EqualsFrames({SpdyFrameType::SETTINGS}));
+ visitor.Clear();
+
+ const std::string initial_frames =
+ TestFrameSequence()
+ .ServerPreface({{.id = MAX_CONCURRENT_STREAMS, .value = 1}})
+ .Serialize();
+ testing::InSequence s;
+
+ // Server preface (SETTINGS with MAX_CONCURRENT_STREAMS)
+ EXPECT_CALL(visitor, OnFrameHeader(0, 6, SETTINGS, 0));
+ EXPECT_CALL(visitor, OnSettingsStart());
+ EXPECT_CALL(visitor, OnSetting);
+ // TODO(diannahu): Remove this duplicate call with a separate
+ // ExtensionVisitorInterface implementation.
+ EXPECT_CALL(visitor, OnSetting);
+ EXPECT_CALL(visitor, OnSettingsEnd());
+
+ const int64_t initial_result = adapter->ProcessBytes(initial_frames);
+ EXPECT_EQ(initial_frames.size(), static_cast<size_t>(initial_result));
+
+ // Session will want to write a SETTINGS ack.
+ EXPECT_TRUE(adapter->want_write());
+
+ EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, _, 0x1));
+ EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, _, 0x1, 0));
+
+ result = adapter->Send();
+ EXPECT_EQ(0, result);
+ EXPECT_THAT(visitor.data(), EqualsFrames({SpdyFrameType::SETTINGS}));
+ visitor.Clear();
+
+ const std::string kBody = "This is an example request body.";
+ auto body1 = absl::make_unique<TestDataFrameSource>(visitor, true);
+ body1->AppendPayload(kBody);
+ body1->EndData();
+ const int stream_id =
+ adapter->SubmitRequest(ToHeaders({{":method", "POST"},
+ {":scheme", "http"},
+ {":authority", "example.com"},
+ {":path", "/this/is/request/one"}}),
+ std::move(body1), nullptr);
+ EXPECT_GT(stream_id, 0);
+ EXPECT_TRUE(adapter->want_write());
+
+ EXPECT_CALL(visitor, OnBeforeFrameSent(HEADERS, stream_id, _, 0x4));
+ EXPECT_CALL(visitor, OnFrameSent(HEADERS, stream_id, _, 0x4, 0));
+ EXPECT_CALL(visitor, OnFrameSent(DATA, stream_id, _, 0x1, 0));
+
+ result = adapter->Send();
+ EXPECT_EQ(0, result);
+ EXPECT_THAT(visitor.data(), EqualsFrames({spdy::SpdyFrameType::HEADERS,
+ spdy::SpdyFrameType::DATA}));
+ EXPECT_THAT(visitor.data(), testing::HasSubstr(kBody));
+ visitor.Clear();
+ EXPECT_FALSE(adapter->want_write());
+
+ const int next_stream_id =
+ adapter->SubmitRequest(ToHeaders({{":method", "POST"},
+ {":scheme", "http"},
+ {":authority", "example.com"},
+ {":path", "/this/is/request/two"}}),
+ nullptr, nullptr);
+
+ // A new pending stream is created, but because of MAX_CONCURRENT_STREAMS, the
+ // session should not want to write it at the moment.
+ EXPECT_GT(next_stream_id, stream_id);
+ EXPECT_FALSE(adapter->want_write());
+
+ const std::string stream_frames =
+ TestFrameSequence()
+ .Headers(stream_id,
+ {{":status", "200"},
+ {"server", "my-fake-server"},
+ {"date", "Tue, 6 Apr 2021 12:54:01 GMT"}},
+ /*fin=*/false)
+ .Data(stream_id, "This is the response body.", /*fin=*/true)
+ .Serialize();
+
+ EXPECT_CALL(visitor, OnFrameHeader(stream_id, _, HEADERS, 4));
+ EXPECT_CALL(visitor, OnBeginHeadersForStream(stream_id));
+ EXPECT_CALL(visitor, OnHeaderForStream(stream_id, ":status", "200"));
+ EXPECT_CALL(visitor,
+ OnHeaderForStream(stream_id, "server", "my-fake-server"));
+ EXPECT_CALL(visitor, OnHeaderForStream(stream_id, "date",
+ "Tue, 6 Apr 2021 12:54:01 GMT"));
+ EXPECT_CALL(visitor, OnEndHeadersForStream(stream_id));
+ EXPECT_CALL(visitor, OnFrameHeader(stream_id, 26, DATA, 0x1));
+ EXPECT_CALL(visitor, OnBeginDataForStream(stream_id, 26));
+ EXPECT_CALL(visitor,
+ OnDataForStream(stream_id, "This is the response body."));
+ EXPECT_CALL(visitor, OnEndStream(stream_id));
+ EXPECT_CALL(visitor, OnCloseStream(stream_id, Http2ErrorCode::NO_ERROR));
+
+ // The first stream should close, which should make the session want to write
+ // the next stream.
+ const int64_t stream_result = adapter->ProcessBytes(stream_frames);
+ EXPECT_EQ(stream_frames.size(), static_cast<size_t>(stream_result));
+ EXPECT_TRUE(adapter->want_write());
+
+ EXPECT_CALL(visitor, OnBeforeFrameSent(HEADERS, next_stream_id, _, 0x5));
+ EXPECT_CALL(visitor, OnFrameSent(HEADERS, next_stream_id, _, 0x5, 0));
+
+ result = adapter->Send();
+ EXPECT_EQ(0, result);
+
+ EXPECT_THAT(visitor.data(), EqualsFrames({spdy::SpdyFrameType::HEADERS}));
+ visitor.Clear();
+ EXPECT_FALSE(adapter->want_write());
+}
+
+TEST(OgHttp2AdapterClientTest, FailureSendingConnectionPreface) {
+ DataSavingVisitor visitor;
+ OgHttp2Adapter::Options options{.perspective = Perspective::kClient};
+ auto adapter = OgHttp2Adapter::Create(visitor, options);
+
+ visitor.set_has_write_error();
+ EXPECT_CALL(visitor, OnConnectionError);
+
+ int result = adapter->Send();
+ EXPECT_EQ(result, Http2VisitorInterface::kSendError);
+}
+
TEST_F(OgHttp2AdapterTest, SubmitMetadata) {
auto source = absl::make_unique<TestMetadataSource>(ToHeaderBlock(ToHeaders(
{{"query-cost", "is too darn high"}, {"secret-sauce", "hollandaise"}})));
- adapter_->SubmitMetadata(1, std::move(source));
- EXPECT_TRUE(adapter_->session().want_write());
+ adapter_->SubmitMetadata(1, 16384u, std::move(source));
+ EXPECT_TRUE(adapter_->want_write());
EXPECT_CALL(http2_visitor_, OnBeforeFrameSent(SETTINGS, 0, _, 0x0));
EXPECT_CALL(http2_visitor_, OnFrameSent(SETTINGS, 0, _, 0x0, 0));
@@ -551,14 +850,46 @@ TEST_F(OgHttp2AdapterTest, SubmitMetadata) {
http2_visitor_.data(),
EqualsFrames({spdy::SpdyFrameType::SETTINGS,
static_cast<spdy::SpdyFrameType>(kMetadataFrameType)}));
- EXPECT_FALSE(adapter_->session().want_write());
+ EXPECT_FALSE(adapter_->want_write());
+}
+
+TEST_F(OgHttp2AdapterTest, SubmitMetadataMultipleFrames) {
+ const auto kLargeValue = std::string(63 * 1024, 'a');
+ auto source = absl::make_unique<TestMetadataSource>(
+ ToHeaderBlock(ToHeaders({{"large-value", kLargeValue}})));
+ adapter_->SubmitMetadata(1, 16384u, std::move(source));
+ EXPECT_TRUE(adapter_->want_write());
+
+ testing::InSequence seq;
+ EXPECT_CALL(http2_visitor_, OnBeforeFrameSent(SETTINGS, 0, _, 0x0));
+ EXPECT_CALL(http2_visitor_, OnFrameSent(SETTINGS, 0, _, 0x0, 0));
+ EXPECT_CALL(http2_visitor_, OnBeforeFrameSent(kMetadataFrameType, 1, _, 0x0));
+ EXPECT_CALL(http2_visitor_, OnFrameSent(kMetadataFrameType, 1, _, 0x0, 0));
+ EXPECT_CALL(http2_visitor_, OnBeforeFrameSent(kMetadataFrameType, 1, _, 0x0));
+ EXPECT_CALL(http2_visitor_, OnFrameSent(kMetadataFrameType, 1, _, 0x0, 0));
+ EXPECT_CALL(http2_visitor_, OnBeforeFrameSent(kMetadataFrameType, 1, _, 0x0));
+ EXPECT_CALL(http2_visitor_, OnFrameSent(kMetadataFrameType, 1, _, 0x0, 0));
+ EXPECT_CALL(http2_visitor_, OnBeforeFrameSent(kMetadataFrameType, 1, _, 0x4));
+ EXPECT_CALL(http2_visitor_, OnFrameSent(kMetadataFrameType, 1, _, 0x4, 0));
+
+ int result = adapter_->Send();
+ EXPECT_EQ(0, result);
+ absl::string_view serialized = http2_visitor_.data();
+ EXPECT_THAT(
+ serialized,
+ EqualsFrames({spdy::SpdyFrameType::SETTINGS,
+ static_cast<spdy::SpdyFrameType>(kMetadataFrameType),
+ static_cast<spdy::SpdyFrameType>(kMetadataFrameType),
+ static_cast<spdy::SpdyFrameType>(kMetadataFrameType),
+ static_cast<spdy::SpdyFrameType>(kMetadataFrameType)}));
+ EXPECT_FALSE(adapter_->want_write());
}
TEST_F(OgHttp2AdapterTest, SubmitConnectionMetadata) {
auto source = absl::make_unique<TestMetadataSource>(ToHeaderBlock(ToHeaders(
{{"query-cost", "is too darn high"}, {"secret-sauce", "hollandaise"}})));
- adapter_->SubmitMetadata(0, std::move(source));
- EXPECT_TRUE(adapter_->session().want_write());
+ adapter_->SubmitMetadata(0, 16384u, std::move(source));
+ EXPECT_TRUE(adapter_->want_write());
EXPECT_CALL(http2_visitor_, OnBeforeFrameSent(SETTINGS, 0, _, 0x0));
EXPECT_CALL(http2_visitor_, OnFrameSent(SETTINGS, 0, _, 0x0, 0));
@@ -571,7 +902,7 @@ TEST_F(OgHttp2AdapterTest, SubmitConnectionMetadata) {
http2_visitor_.data(),
EqualsFrames({spdy::SpdyFrameType::SETTINGS,
static_cast<spdy::SpdyFrameType>(kMetadataFrameType)}));
- EXPECT_FALSE(adapter_->session().want_write());
+ EXPECT_FALSE(adapter_->want_write());
}
TEST_F(OgHttp2AdapterTest, GetSendWindowSize) {
@@ -585,19 +916,19 @@ TEST_F(OgHttp2AdapterTest, MarkDataConsumedForStream) {
}
TEST_F(OgHttp2AdapterTest, TestSerialize) {
- EXPECT_TRUE(adapter_->session().want_read());
- EXPECT_FALSE(adapter_->session().want_write());
+ EXPECT_TRUE(adapter_->want_read());
+ EXPECT_FALSE(adapter_->want_write());
adapter_->SubmitSettings(
{{HEADER_TABLE_SIZE, 128}, {MAX_FRAME_SIZE, 128 << 10}});
- EXPECT_TRUE(adapter_->session().want_write());
+ EXPECT_TRUE(adapter_->want_write());
adapter_->SubmitPriorityForStream(3, 1, 255, true);
adapter_->SubmitRst(3, Http2ErrorCode::CANCEL);
adapter_->SubmitPing(42);
adapter_->SubmitGoAway(13, Http2ErrorCode::NO_ERROR, "");
adapter_->SubmitWindowUpdate(3, 127);
- EXPECT_TRUE(adapter_->session().want_write());
+ EXPECT_TRUE(adapter_->want_write());
EXPECT_CALL(http2_visitor_, OnBeforeFrameSent(SETTINGS, 0, _, 0x0));
EXPECT_CALL(http2_visitor_, OnFrameSent(SETTINGS, 0, _, 0x0, 0));
@@ -620,34 +951,34 @@ TEST_F(OgHttp2AdapterTest, TestSerialize) {
EqualsFrames({SpdyFrameType::SETTINGS, SpdyFrameType::PRIORITY,
SpdyFrameType::RST_STREAM, SpdyFrameType::PING,
SpdyFrameType::GOAWAY, SpdyFrameType::WINDOW_UPDATE}));
- EXPECT_FALSE(adapter_->session().want_write());
+ EXPECT_FALSE(adapter_->want_write());
}
TEST_F(OgHttp2AdapterTest, TestPartialSerialize) {
- EXPECT_FALSE(adapter_->session().want_write());
+ EXPECT_FALSE(adapter_->want_write());
adapter_->SubmitSettings(
{{HEADER_TABLE_SIZE, 128}, {MAX_FRAME_SIZE, 128 << 10}});
adapter_->SubmitGoAway(13, Http2ErrorCode::NO_ERROR, "And don't come back!");
adapter_->SubmitPing(42);
- EXPECT_TRUE(adapter_->session().want_write());
+ EXPECT_TRUE(adapter_->want_write());
http2_visitor_.set_send_limit(20);
EXPECT_CALL(http2_visitor_, OnBeforeFrameSent(SETTINGS, 0, _, 0x0));
EXPECT_CALL(http2_visitor_, OnFrameSent(SETTINGS, 0, _, 0x0, 0));
int result = adapter_->Send();
EXPECT_EQ(0, result);
- EXPECT_TRUE(adapter_->session().want_write());
+ EXPECT_TRUE(adapter_->want_write());
EXPECT_CALL(http2_visitor_, OnBeforeFrameSent(GOAWAY, 0, _, 0x0));
EXPECT_CALL(http2_visitor_, OnFrameSent(GOAWAY, 0, _, 0x0, 0));
result = adapter_->Send();
EXPECT_EQ(0, result);
- EXPECT_TRUE(adapter_->session().want_write());
+ EXPECT_TRUE(adapter_->want_write());
EXPECT_CALL(http2_visitor_, OnBeforeFrameSent(PING, 0, _, 0x0));
EXPECT_CALL(http2_visitor_, OnFrameSent(PING, 0, _, 0x0, 0));
result = adapter_->Send();
EXPECT_EQ(0, result);
- EXPECT_FALSE(adapter_->session().want_write());
+ EXPECT_FALSE(adapter_->want_write());
EXPECT_THAT(http2_visitor_.data(),
EqualsFrames({SpdyFrameType::SETTINGS, SpdyFrameType::GOAWAY,
SpdyFrameType::PING}));
@@ -657,7 +988,7 @@ TEST(OgHttp2AdapterServerTest, ClientSendsContinuation) {
DataSavingVisitor visitor;
OgHttp2Adapter::Options options{.perspective = Perspective::kServer};
auto adapter = OgHttp2Adapter::Create(visitor, options);
- EXPECT_FALSE(adapter->session().want_write());
+ EXPECT_FALSE(adapter->want_write());
const std::string frames = TestFrameSequence()
.ClientPreface()
@@ -686,15 +1017,15 @@ TEST(OgHttp2AdapterServerTest, ClientSendsContinuation) {
EXPECT_CALL(visitor, OnEndHeadersForStream(1));
EXPECT_CALL(visitor, OnEndStream(1));
- const size_t result = adapter->ProcessBytes(frames);
- EXPECT_EQ(frames.size(), result);
+ const int64_t result = adapter->ProcessBytes(frames);
+ EXPECT_EQ(frames.size(), static_cast<size_t>(result));
}
TEST(OgHttp2AdapterServerTest, ClientSendsMetadataWithContinuation) {
DataSavingVisitor visitor;
OgHttp2Adapter::Options options{.perspective = Perspective::kServer};
auto adapter = OgHttp2Adapter::Create(visitor, options);
- EXPECT_FALSE(adapter->session().want_write());
+ EXPECT_FALSE(adapter->want_write());
const std::string frames =
TestFrameSequence()
@@ -744,8 +1075,8 @@ TEST(OgHttp2AdapterServerTest, ClientSendsMetadataWithContinuation) {
EXPECT_CALL(visitor, OnMetadataForStream(1, _));
EXPECT_CALL(visitor, OnMetadataEndForStream(1));
- const size_t result = adapter->ProcessBytes(frames);
- EXPECT_EQ(frames.size(), result);
+ const int64_t result = adapter->ProcessBytes(frames);
+ EXPECT_EQ(frames.size(), static_cast<size_t>(result));
EXPECT_EQ(TestFrameSequence::MetadataBlockForPayload(
"Example connection metadata in multiple frames"),
absl::StrJoin(visitor.GetMetadata(0), ""));
@@ -758,7 +1089,7 @@ TEST(OgHttp2AdapterServerTest, ServerSendsInvalidTrailers) {
DataSavingVisitor visitor;
OgHttp2Adapter::Options options{.perspective = Perspective::kServer};
auto adapter = OgHttp2Adapter::Create(visitor, options);
- EXPECT_FALSE(adapter->session().want_write());
+ EXPECT_FALSE(adapter->want_write());
const std::string frames = TestFrameSequence()
.ClientPreface()
@@ -785,8 +1116,8 @@ TEST(OgHttp2AdapterServerTest, ServerSendsInvalidTrailers) {
EXPECT_CALL(visitor, OnEndHeadersForStream(1));
EXPECT_CALL(visitor, OnEndStream(1));
- const size_t result = adapter->ProcessBytes(frames);
- EXPECT_EQ(frames.size(), result);
+ const int64_t result = adapter->ProcessBytes(frames);
+ EXPECT_EQ(frames.size(), static_cast<size_t>(result));
const absl::string_view kBody = "This is an example response body.";
@@ -799,7 +1130,7 @@ TEST(OgHttp2AdapterServerTest, ServerSendsInvalidTrailers) {
1, ToHeaders({{":status", "200"}, {"x-comment", "Sure, sounds good."}}),
std::move(body1));
EXPECT_EQ(submit_result, 0);
- EXPECT_TRUE(adapter->session().want_write());
+ EXPECT_TRUE(adapter->want_write());
EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, _, 0x0));
EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, _, 0x0, 0));
@@ -817,14 +1148,14 @@ TEST(OgHttp2AdapterServerTest, ServerSendsInvalidTrailers) {
spdy::SpdyFrameType::HEADERS, spdy::SpdyFrameType::DATA}));
EXPECT_THAT(visitor.data(), testing::HasSubstr(kBody));
visitor.Clear();
- EXPECT_FALSE(adapter->session().want_write());
+ EXPECT_FALSE(adapter->want_write());
// The body source has been exhausted by the call to Send() above.
EXPECT_CALL(visitor, OnCloseStream(1, Http2ErrorCode::NO_ERROR));
int trailer_result =
adapter->SubmitTrailer(1, ToHeaders({{":final-status", "a-ok"}}));
ASSERT_EQ(trailer_result, 0);
- EXPECT_TRUE(adapter->session().want_write());
+ EXPECT_TRUE(adapter->want_write());
EXPECT_CALL(visitor, OnBeforeFrameSent(HEADERS, 1, _, 0x5));
EXPECT_CALL(visitor, OnFrameSent(HEADERS, 1, _, 0x5, 0));
@@ -875,10 +1206,10 @@ TEST(OgHttp2AdapterServerTest, ServerErrorWhileHandlingHeaders) {
EXPECT_CALL(visitor, OnFrameHeader(0, 4, WINDOW_UPDATE, 0));
EXPECT_CALL(visitor, OnWindowUpdate(0, 2000));
- const size_t result = adapter->ProcessBytes(frames);
- EXPECT_EQ(frames.size(), result);
+ const int64_t result = adapter->ProcessBytes(frames);
+ EXPECT_EQ(frames.size(), static_cast<size_t>(result));
- EXPECT_TRUE(adapter->session().want_write());
+ EXPECT_TRUE(adapter->want_write());
EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, _, 0x0));
EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, _, 0x0, 0));
@@ -899,6 +1230,227 @@ TEST(OgHttp2AdapterServerTest, ServerErrorWhileHandlingHeaders) {
spdy::SpdyFrameType::RST_STREAM}));
}
+TEST(OgHttp2AdapterServerTest, ServerErrorAfterHandlingHeaders) {
+ DataSavingVisitor visitor;
+ OgHttp2Adapter::Options options{.perspective = Perspective::kServer};
+ auto adapter = OgHttp2Adapter::Create(visitor, options);
+
+ const std::string frames = TestFrameSequence()
+ .ClientPreface()
+ .Headers(1,
+ {{":method", "POST"},
+ {":scheme", "https"},
+ {":authority", "example.com"},
+ {":path", "/this/is/request/one"}},
+ /*fin=*/false)
+ .WindowUpdate(1, 2000)
+ .Data(1, "This is the request body.")
+ .WindowUpdate(0, 2000)
+ .Serialize();
+ testing::InSequence s;
+
+ // Client preface (empty SETTINGS)
+ EXPECT_CALL(visitor, OnFrameHeader(0, 0, SETTINGS, 0));
+ EXPECT_CALL(visitor, OnSettingsStart());
+ EXPECT_CALL(visitor, OnSettingsEnd());
+
+ EXPECT_CALL(visitor, OnFrameHeader(1, _, HEADERS, 4));
+ EXPECT_CALL(visitor, OnBeginHeadersForStream(1));
+ EXPECT_CALL(visitor, OnHeaderForStream(1, ":method", "POST"));
+ EXPECT_CALL(visitor, OnHeaderForStream(1, ":scheme", "https"));
+ EXPECT_CALL(visitor, OnHeaderForStream(1, ":authority", "example.com"));
+ EXPECT_CALL(visitor, OnHeaderForStream(1, ":path", "/this/is/request/one"));
+ EXPECT_CALL(visitor, OnEndHeadersForStream(1))
+ .WillOnce(testing::Return(false));
+ EXPECT_CALL(visitor, OnConnectionError());
+
+ const int64_t result = adapter->ProcessBytes(frames);
+ EXPECT_LT(result, 0);
+
+ EXPECT_TRUE(adapter->want_write());
+
+ EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, 0, 0x0));
+ EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, 0, 0x0, 0));
+ EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, 0, 0x1));
+ EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, 0, 0x1, 0));
+
+ int send_result = adapter->Send();
+ // Some bytes should have been serialized.
+ EXPECT_EQ(0, send_result);
+ // SETTINGS and SETTINGS ack
+ EXPECT_THAT(visitor.data(), EqualsFrames({spdy::SpdyFrameType::SETTINGS,
+ spdy::SpdyFrameType::SETTINGS}));
+}
+
+// Exercises the case when a visitor chooses to reject a frame based solely on
+// the frame header, which is a fatal error for the connection.
+TEST(OgHttp2AdapterServerTest, ServerRejectsFrameHeader) {
+ DataSavingVisitor visitor;
+ OgHttp2Adapter::Options options{.perspective = Perspective::kServer};
+ auto adapter = OgHttp2Adapter::Create(visitor, options);
+
+ const std::string frames = TestFrameSequence()
+ .ClientPreface()
+ .Ping(64)
+ .Headers(1,
+ {{":method", "POST"},
+ {":scheme", "https"},
+ {":authority", "example.com"},
+ {":path", "/this/is/request/one"}},
+ /*fin=*/false)
+ .WindowUpdate(1, 2000)
+ .Data(1, "This is the request body.")
+ .WindowUpdate(0, 2000)
+ .Serialize();
+ testing::InSequence s;
+
+ // Client preface (empty SETTINGS)
+ EXPECT_CALL(visitor, OnFrameHeader(0, 0, SETTINGS, 0));
+ EXPECT_CALL(visitor, OnSettingsStart());
+ EXPECT_CALL(visitor, OnSettingsEnd());
+
+ EXPECT_CALL(visitor, OnFrameHeader(0, 8, PING, 0))
+ .WillOnce(testing::Return(false));
+ EXPECT_CALL(visitor, OnConnectionError());
+
+ const int64_t result = adapter->ProcessBytes(frames);
+ EXPECT_LT(result, 0);
+
+ EXPECT_TRUE(adapter->want_write());
+
+ EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, 0, 0x0));
+ EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, 0, 0x0, 0));
+ EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, 0, 0x1));
+ EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, 0, 0x1, 0));
+
+ int send_result = adapter->Send();
+ // Some bytes should have been serialized.
+ EXPECT_EQ(0, send_result);
+ // SETTINGS and SETTINGS ack
+ EXPECT_THAT(visitor.data(), EqualsFrames({spdy::SpdyFrameType::SETTINGS,
+ spdy::SpdyFrameType::SETTINGS}));
+}
+
+TEST(OgHttp2AdapterServerTest, ServerRejectsBeginningOfData) {
+ DataSavingVisitor visitor;
+ OgHttp2Adapter::Options options{.perspective = Perspective::kServer};
+ auto adapter = OgHttp2Adapter::Create(visitor, options);
+
+ const std::string frames = TestFrameSequence()
+ .ClientPreface()
+ .Headers(1,
+ {{":method", "POST"},
+ {":scheme", "https"},
+ {":authority", "example.com"},
+ {":path", "/this/is/request/one"}},
+ /*fin=*/false)
+ .Data(1, "This is the request body.")
+ .Headers(3,
+ {{":method", "GET"},
+ {":scheme", "http"},
+ {":authority", "example.com"},
+ {":path", "/this/is/request/two"}},
+ /*fin=*/true)
+ .RstStream(3, Http2ErrorCode::CANCEL)
+ .Ping(47)
+ .Serialize();
+ testing::InSequence s;
+
+ // Client preface (empty SETTINGS)
+ EXPECT_CALL(visitor, OnFrameHeader(0, 0, SETTINGS, 0));
+ EXPECT_CALL(visitor, OnSettingsStart());
+ EXPECT_CALL(visitor, OnSettingsEnd());
+
+ EXPECT_CALL(visitor, OnFrameHeader(1, _, HEADERS, 4));
+ EXPECT_CALL(visitor, OnBeginHeadersForStream(1));
+ EXPECT_CALL(visitor, OnHeaderForStream(1, ":method", "POST"));
+ EXPECT_CALL(visitor, OnHeaderForStream(1, ":scheme", "https"));
+ EXPECT_CALL(visitor, OnHeaderForStream(1, ":authority", "example.com"));
+ EXPECT_CALL(visitor, OnHeaderForStream(1, ":path", "/this/is/request/one"));
+ EXPECT_CALL(visitor, OnEndHeadersForStream(1));
+ EXPECT_CALL(visitor, OnFrameHeader(1, 25, DATA, 0));
+ EXPECT_CALL(visitor, OnBeginDataForStream(1, 25))
+ .WillOnce(testing::Return(false));
+ EXPECT_CALL(visitor, OnConnectionError());
+
+ const int64_t result = adapter->ProcessBytes(frames);
+ EXPECT_LT(result, 0);
+
+ EXPECT_TRUE(adapter->want_write());
+
+ EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, 0, 0x0));
+ EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, 0, 0x0, 0));
+ EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, 0, 0x1));
+ EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, 0, 0x1, 0));
+
+ int send_result = adapter->Send();
+ // Some bytes should have been serialized.
+ EXPECT_EQ(0, send_result);
+ // SETTINGS and SETTINGS ack.
+ EXPECT_THAT(visitor.data(), EqualsFrames({spdy::SpdyFrameType::SETTINGS,
+ spdy::SpdyFrameType::SETTINGS}));
+}
+
+TEST(OgHttp2AdapterServerTest, ServerRejectsStreamData) {
+ DataSavingVisitor visitor;
+ OgHttp2Adapter::Options options{.perspective = Perspective::kServer};
+ auto adapter = OgHttp2Adapter::Create(visitor, options);
+
+ const std::string frames = TestFrameSequence()
+ .ClientPreface()
+ .Headers(1,
+ {{":method", "POST"},
+ {":scheme", "https"},
+ {":authority", "example.com"},
+ {":path", "/this/is/request/one"}},
+ /*fin=*/false)
+ .Data(1, "This is the request body.")
+ .Headers(3,
+ {{":method", "GET"},
+ {":scheme", "http"},
+ {":authority", "example.com"},
+ {":path", "/this/is/request/two"}},
+ /*fin=*/true)
+ .RstStream(3, Http2ErrorCode::CANCEL)
+ .Ping(47)
+ .Serialize();
+ testing::InSequence s;
+
+ // Client preface (empty SETTINGS)
+ EXPECT_CALL(visitor, OnFrameHeader(0, 0, SETTINGS, 0));
+ EXPECT_CALL(visitor, OnSettingsStart());
+ EXPECT_CALL(visitor, OnSettingsEnd());
+
+ EXPECT_CALL(visitor, OnFrameHeader(1, _, HEADERS, 4));
+ EXPECT_CALL(visitor, OnBeginHeadersForStream(1));
+ EXPECT_CALL(visitor, OnHeaderForStream(1, ":method", "POST"));
+ EXPECT_CALL(visitor, OnHeaderForStream(1, ":scheme", "https"));
+ EXPECT_CALL(visitor, OnHeaderForStream(1, ":authority", "example.com"));
+ EXPECT_CALL(visitor, OnHeaderForStream(1, ":path", "/this/is/request/one"));
+ EXPECT_CALL(visitor, OnEndHeadersForStream(1));
+ EXPECT_CALL(visitor, OnFrameHeader(1, 25, DATA, 0));
+ EXPECT_CALL(visitor, OnBeginDataForStream(1, 25));
+ EXPECT_CALL(visitor, OnDataForStream(1, _)).WillOnce(testing::Return(false));
+ EXPECT_CALL(visitor, OnConnectionError());
+
+ const int64_t result = adapter->ProcessBytes(frames);
+ EXPECT_LT(result, 0);
+
+ EXPECT_TRUE(adapter->want_write());
+
+ EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, 0, 0x0));
+ EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, 0, 0x0, 0));
+ EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, 0, 0x1));
+ EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, 0, 0x1, 0));
+
+ int send_result = adapter->Send();
+ // Some bytes should have been serialized.
+ EXPECT_EQ(0, send_result);
+ // SETTINGS and SETTINGS ack.
+ EXPECT_THAT(visitor.data(), EqualsFrames({spdy::SpdyFrameType::SETTINGS,
+ spdy::SpdyFrameType::SETTINGS}));
+}
+
} // namespace
} // namespace test
} // namespace adapter
diff --git a/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_session.cc b/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_session.cc
index 3a32b2e70ea..e3a696ba820 100644
--- a/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_session.cc
+++ b/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_session.cc
@@ -1,16 +1,28 @@
#include "http2/adapter/oghttp2_session.h"
#include <tuple>
+#include <utility>
+#include "absl/memory/memory.h"
#include "absl/strings/escaping.h"
+#include "http2/adapter/http2_protocol.h"
#include "http2/adapter/oghttp2_util.h"
+#include "spdy/core/spdy_protocol.h"
namespace http2 {
namespace adapter {
namespace {
-const size_t kMaxMetadataFrameSize = 16384;
+// #define OGHTTP2_DEBUG_TRACE 1
+
+#ifdef OGHTTP2_DEBUG_TRACE
+const bool kTraceLoggingEnabled = true;
+#else
+const bool kTraceLoggingEnabled = false;
+#endif
+
+const uint32_t kMaxAllowedMetadataFrameSize = 65536u;
// TODO(birenroy): Consider incorporating spdy::FlagsSerializionVisitor here.
class FrameAttributeCollector : public spdy::SpdyFrameVisitor {
@@ -107,28 +119,55 @@ class FrameAttributeCollector : public spdy::SpdyFrameVisitor {
uint8_t flags_ = 0;
};
+absl::string_view TracePerspectiveAsString(Perspective p) {
+ switch (p) {
+ case Perspective::kClient:
+ return "OGHTTP2_CLIENT";
+ case Perspective::kServer:
+ return "OGHTTP2_SERVER";
+ }
+}
+
} // namespace
void OgHttp2Session::PassthroughHeadersHandler::OnHeaderBlockStart() {
+ result_ = Http2VisitorInterface::HEADER_OK;
const bool status = visitor_.OnBeginHeadersForStream(stream_id_);
if (!status) {
result_ = Http2VisitorInterface::HEADER_CONNECTION_ERROR;
}
+ validator_.StartHeaderBlock();
}
void OgHttp2Session::PassthroughHeadersHandler::OnHeader(
absl::string_view key,
absl::string_view value) {
- if (result_ == Http2VisitorInterface::HEADER_OK) {
- result_ = visitor_.OnHeaderForStream(stream_id_, key, value);
+ if (result_ != Http2VisitorInterface::HEADER_OK) {
+ QUICHE_VLOG(2) << "Early return; status not HEADER_OK";
+ return;
+ }
+ const auto validation_result = validator_.ValidateSingleHeader(key, value);
+ if (validation_result != HeaderValidator::HEADER_OK) {
+ QUICHE_VLOG(2) << "RST_STREAM: invalid header found";
+ result_ = Http2VisitorInterface::HEADER_RST_STREAM;
+ return;
}
+ result_ = visitor_.OnHeaderForStream(stream_id_, key, value);
}
void OgHttp2Session::PassthroughHeadersHandler::OnHeaderBlockEnd(
size_t /* uncompressed_header_bytes */,
size_t /* compressed_header_bytes */) {
if (result_ == Http2VisitorInterface::HEADER_OK) {
- visitor_.OnEndHeadersForStream(stream_id_);
+ if (!validator_.FinishHeaderBlock(type_)) {
+ result_ = Http2VisitorInterface::HEADER_RST_STREAM;
+ }
+ }
+ if (result_ == Http2VisitorInterface::HEADER_OK) {
+ const bool result = visitor_.OnEndHeadersForStream(stream_id_);
+ if (!result) {
+ session_.decoder_.StopProcessing();
+ }
} else {
session_.OnHeaderStatus(stream_id_, result_);
}
@@ -136,6 +175,12 @@ void OgHttp2Session::PassthroughHeadersHandler::OnHeaderBlockEnd(
OgHttp2Session::OgHttp2Session(Http2VisitorInterface& visitor, Options options)
: visitor_(visitor),
+ receive_logger_(
+ this, TracePerspectiveAsString(options.perspective),
+ []() { return kTraceLoggingEnabled; }, this),
+ send_logger_(
+ TracePerspectiveAsString(options.perspective),
+ []() { return kTraceLoggingEnabled; }, this),
headers_handler_(*this, visitor),
connection_window_manager_(kInitialFlowControlWindowSize,
[this](size_t window_update_delta) {
@@ -143,7 +188,7 @@ OgHttp2Session::OgHttp2Session(Http2VisitorInterface& visitor, Options options)
window_update_delta);
}),
options_(options) {
- decoder_.set_visitor(this);
+ decoder_.set_visitor(&receive_logger_);
decoder_.set_extension_visitor(this);
if (options_.perspective == Perspective::kServer) {
remaining_preface_ = {spdy::kHttp2ConnectionHeaderPrefix,
@@ -217,8 +262,8 @@ int OgHttp2Session::GetHpackDecoderDynamicTableSize() const {
return decoder == nullptr ? 0 : decoder->GetDynamicTableSize();
}
-ssize_t OgHttp2Session::ProcessBytes(absl::string_view bytes) {
- ssize_t preface_consumed = 0;
+int64_t OgHttp2Session::ProcessBytes(absl::string_view bytes) {
+ int64_t preface_consumed = 0;
if (!remaining_preface_.empty()) {
QUICHE_VLOG(2) << "Preface bytes remaining: " << remaining_preface_.size();
// decoder_ does not understand the client connection preface.
@@ -228,7 +273,7 @@ ssize_t OgHttp2Session::ProcessBytes(absl::string_view bytes) {
QUICHE_DLOG(INFO) << "Preface doesn't match! Expected: ["
<< absl::CEscape(remaining_preface_) << "], actual: ["
<< absl::CEscape(bytes) << "]";
- visitor_.OnConnectionError();
+ LatchErrorAndNotify();
return -1;
}
remaining_preface_.remove_prefix(min_size);
@@ -240,8 +285,14 @@ ssize_t OgHttp2Session::ProcessBytes(absl::string_view bytes) {
}
preface_consumed = min_size;
}
- ssize_t result = decoder_.ProcessInput(bytes.data(), bytes.size());
- return result < 0 ? result : result + preface_consumed;
+ int64_t result = decoder_.ProcessInput(bytes.data(), bytes.size());
+ if (latched_error_) {
+ QUICHE_VLOG(2) << "ProcessBytes encountered an error.";
+ return -1;
+ }
+ const int64_t ret = result < 0 ? result : result + preface_consumed;
+ QUICHE_VLOG(2) << "ProcessBytes returning: " << ret;
+ return ret;
}
int OgHttp2Session::Consume(Http2StreamId stream_id, size_t num_bytes) {
@@ -284,7 +335,7 @@ void OgHttp2Session::EnqueueFrame(std::unique_ptr<spdy::SpdyFrameIR> frame) {
int OgHttp2Session::Send() {
MaybeSetupPreface();
- ssize_t result = std::numeric_limits<ssize_t>::max();
+ int64_t result = std::numeric_limits<int64_t>::max();
// Flush any serialized prefix.
while (result > 0 && !serialized_prefix_.empty()) {
result = visitor_.OnReadyToSend(serialized_prefix_);
@@ -292,9 +343,13 @@ int OgHttp2Session::Send() {
serialized_prefix_.erase(0, result);
}
}
- if (!serialized_prefix_.empty()) {
- return result < 0 ? result : 0;
+ if (result < 0) {
+ LatchErrorAndNotify();
+ return result;
+ } else if (!serialized_prefix_.empty()) {
+ return 0;
}
+
bool continue_writing = SendQueuedFrames();
while (continue_writing && !connection_metadata_.empty()) {
continue_writing = SendMetadata(0, connection_metadata_);
@@ -321,10 +376,11 @@ bool OgHttp2Session::SendQueuedFrames() {
frame_ptr->Visit(&c);
visitor_.OnBeforeFrameSent(c.frame_type(), c.stream_id(), c.length(),
c.flags());
+ frame_ptr->Visit(&send_logger_);
spdy::SpdySerializedFrame frame = framer_.SerializeFrame(*frame_ptr);
- const ssize_t result = visitor_.OnReadyToSend(absl::string_view(frame));
+ const int64_t result = visitor_.OnReadyToSend(absl::string_view(frame));
if (result < 0) {
- visitor_.OnConnectionError();
+ LatchErrorAndNotify();
return false;
} else if (result == 0) {
// Write blocked.
@@ -336,7 +392,7 @@ bool OgHttp2Session::SendQueuedFrames() {
// If this endpoint is resetting the stream, the stream should be
// closed. This endpoint is already aware of the outbound RST_STREAM and
// its error code, so close with NO_ERROR.
- visitor_.OnCloseStream(c.stream_id(), Http2ErrorCode::NO_ERROR);
+ CloseStream(c.stream_id(), Http2ErrorCode::NO_ERROR);
}
frames_.pop_front();
@@ -377,11 +433,12 @@ bool OgHttp2Session::WriteForStream(Http2StreamId stream_id) {
return true;
}
bool source_can_produce = true;
- int32_t available_window = std::min(
- std::min(connection_send_window_, state.send_window), max_frame_payload_);
+ int32_t available_window =
+ std::min({connection_send_window_, state.send_window,
+ static_cast<int32_t>(max_frame_payload_)});
while (connection_can_write && available_window > 0 &&
state.outbound_body != nullptr) {
- ssize_t length;
+ int64_t length;
bool end_data;
std::tie(length, end_data) =
state.outbound_body->SelectPayloadLength(available_window);
@@ -390,7 +447,8 @@ bool OgHttp2Session::WriteForStream(Http2StreamId stream_id) {
break;
} else if (length == DataFrameSource::kError) {
source_can_produce = false;
- visitor_.OnCloseStream(stream_id, Http2ErrorCode::INTERNAL_ERROR);
+ CloseStream(stream_id, Http2ErrorCode::INTERNAL_ERROR);
+ // No more work on the stream; it has been closed.
break;
}
const bool fin = end_data ? state.outbound_body->send_fin() : false;
@@ -411,9 +469,8 @@ bool OgHttp2Session::WriteForStream(Http2StreamId stream_id) {
visitor_.OnFrameSent(/* DATA */ 0, stream_id, length, fin ? 0x1 : 0x0, 0);
connection_send_window_ -= length;
state.send_window -= length;
- available_window =
- std::min(std::min(connection_send_window_, state.send_window),
- max_frame_payload_);
+ available_window = std::min({connection_send_window_, state.send_window,
+ static_cast<int32_t>(max_frame_payload_)});
}
if (end_data) {
bool sent_trailers = false;
@@ -428,14 +485,17 @@ bool OgHttp2Session::WriteForStream(Http2StreamId stream_id) {
}
state.outbound_body = nullptr;
if (fin || sent_trailers) {
- MaybeCloseWithRstStream(stream_id, state);
+ if (MaybeCloseWithRstStream(stream_id, state)) {
+ // No more work on the stream; it has been closed.
+ break;
+ }
}
}
}
- // If the stream still has data to send, it should be marked as ready in the
- // write scheduler.
- if (source_can_produce && state.send_window > 0 &&
- state.outbound_body != nullptr) {
+ // If the stream still exists and has data to send, it should be marked as
+ // ready in the write scheduler.
+ if (stream_map_.contains(stream_id) && source_can_produce &&
+ state.send_window > 0 && state.outbound_body != nullptr) {
write_scheduler_.MarkStreamReady(stream_id, false);
}
// Streams can continue writing as long as the connection is not write-blocked
@@ -445,19 +505,21 @@ bool OgHttp2Session::WriteForStream(Http2StreamId stream_id) {
bool OgHttp2Session::SendMetadata(Http2StreamId stream_id,
OgHttp2Session::MetadataSequence& sequence) {
- auto payload_buffer = absl::make_unique<uint8_t[]>(kMaxMetadataFrameSize);
+ const uint32_t max_payload_size =
+ std::min(kMaxAllowedMetadataFrameSize, max_frame_payload_);
+ auto payload_buffer = absl::make_unique<uint8_t[]>(max_payload_size);
while (!sequence.empty()) {
MetadataSource& source = *sequence.front();
- ssize_t written;
+ int64_t written;
bool end_metadata;
std::tie(written, end_metadata) =
- source.Pack(payload_buffer.get(), kMaxMetadataFrameSize);
+ source.Pack(payload_buffer.get(), max_payload_size);
if (written < 0) {
// Did not touch the connection, so perhaps writes are still possible.
return true;
}
- QUICHE_DCHECK_LE(static_cast<size_t>(written), kMaxMetadataFrameSize);
+ QUICHE_DCHECK_LE(static_cast<size_t>(written), max_payload_size);
auto payload = absl::string_view(
reinterpret_cast<const char*>(payload_buffer.get()), written);
EnqueueFrame(absl::make_unique<spdy::SpdyUnknownIR>(
@@ -476,21 +538,15 @@ int32_t OgHttp2Session::SubmitRequest(
// TODO(birenroy): return an error for the incorrect perspective
const Http2StreamId stream_id = next_stream_id_;
next_stream_id_ += 2;
- // Convert headers to header block, create headers frame.
- auto frame =
- absl::make_unique<spdy::SpdyHeadersIR>(stream_id, ToHeaderBlock(headers));
- // Add data source and user data to stream state
- auto iter = CreateStream(stream_id);
- write_scheduler_.MarkStreamReady(stream_id, false);
- if (data_source == nullptr) {
- frame->set_fin(true);
- iter->second.half_closed_local = true;
+ if (CanCreateStream()) {
+ StartRequest(stream_id, ToHeaderBlock(headers), std::move(data_source),
+ user_data);
} else {
- iter->second.outbound_body = std::move(data_source);
+ // TODO(diannahu): There should probably be a limit to the number of allowed
+ // pending streams.
+ pending_streams_.push_back(
+ {stream_id, ToHeaderBlock(headers), std::move(data_source), user_data});
}
- iter->second.user_data = user_data;
- // Enqueue headers frame
- EnqueueFrame(std::move(frame));
return stream_id;
}
@@ -503,22 +559,17 @@ int OgHttp2Session::SubmitResponse(
QUICHE_LOG(ERROR) << "Unable to find stream " << stream_id;
return -501; // NGHTTP2_ERR_INVALID_ARGUMENT
}
- // Convert headers to header block, create headers frame
- auto frame =
- absl::make_unique<spdy::SpdyHeadersIR>(stream_id, ToHeaderBlock(headers));
- if (data_source == nullptr) {
- frame->set_fin(true);
+ const bool end_stream = data_source == nullptr;
+ if (end_stream) {
if (iter->second.half_closed_remote) {
- visitor_.OnCloseStream(stream_id, Http2ErrorCode::NO_ERROR);
+ CloseStream(stream_id, Http2ErrorCode::NO_ERROR);
}
- // TODO(birenroy): the server adapter should probably delete stream state
- // when calling visitor_.OnCloseStream.
} else {
// Add data source to stream state
iter->second.outbound_body = std::move(data_source);
write_scheduler_.MarkStreamReady(stream_id, false);
}
- EnqueueFrame(std::move(frame));
+ SendHeaders(stream_id, ToHeaderBlock(headers), end_stream);
return 0;
}
@@ -571,7 +622,7 @@ void OgHttp2Session::OnError(http2::Http2DecoderAdapter::SpdyFramerError error,
QUICHE_VLOG(1) << "Error: "
<< http2::Http2DecoderAdapter::SpdyFramerErrorToString(error)
<< " details: " << detailed_error;
- visitor_.OnConnectionError();
+ LatchErrorAndNotify();
}
void OgHttp2Session::OnCommonHeader(spdy::SpdyStreamId stream_id,
@@ -580,19 +631,29 @@ void OgHttp2Session::OnCommonHeader(spdy::SpdyStreamId stream_id,
uint8_t flags) {
highest_received_stream_id_ = std::max(static_cast<Http2StreamId>(stream_id),
highest_received_stream_id_);
- visitor_.OnFrameHeader(stream_id, length, type, flags);
+ const bool result = visitor_.OnFrameHeader(stream_id, length, type, flags);
+ if (!result) {
+ decoder_.StopProcessing();
+ }
}
void OgHttp2Session::OnDataFrameHeader(spdy::SpdyStreamId stream_id,
size_t length, bool /*fin*/) {
- visitor_.OnBeginDataForStream(stream_id, length);
+ const bool result = visitor_.OnBeginDataForStream(stream_id, length);
+ if (!result) {
+ decoder_.StopProcessing();
+ }
}
void OgHttp2Session::OnStreamFrameData(spdy::SpdyStreamId stream_id,
const char* data,
size_t len) {
MarkDataBuffered(stream_id, len);
- visitor_.OnDataForStream(stream_id, absl::string_view(data, len));
+ const bool result =
+ visitor_.OnDataForStream(stream_id, absl::string_view(data, len));
+ if (!result) {
+ decoder_.StopProcessing();
+ }
}
void OgHttp2Session::OnStreamEnd(spdy::SpdyStreamId stream_id) {
@@ -605,7 +666,7 @@ void OgHttp2Session::OnStreamEnd(spdy::SpdyStreamId stream_id) {
options_.perspective == Perspective::kClient) {
// From the client's perspective, the stream can be closed if it's already
// half_closed_local.
- visitor_.OnCloseStream(stream_id, Http2ErrorCode::NO_ERROR);
+ CloseStream(stream_id, Http2ErrorCode::NO_ERROR);
}
}
@@ -624,10 +685,27 @@ void OgHttp2Session::OnStreamPadding(spdy::SpdyStreamId /*stream_id*/, size_t
spdy::SpdyHeadersHandlerInterface* OgHttp2Session::OnHeaderFrameStart(
spdy::SpdyStreamId stream_id) {
headers_handler_.set_stream_id(stream_id);
+ auto it = stream_map_.find(stream_id);
+ if (it != stream_map_.end()) {
+ headers_handler_.set_header_type(
+ NextHeaderType(it->second.received_header_type));
+ }
return &headers_handler_;
}
-void OgHttp2Session::OnHeaderFrameEnd(spdy::SpdyStreamId /*stream_id*/) {
+void OgHttp2Session::OnHeaderFrameEnd(spdy::SpdyStreamId stream_id) {
+ auto it = stream_map_.find(stream_id);
+ if (it != stream_map_.end()) {
+ if (headers_handler_.header_type() == HeaderType::RESPONSE &&
+ !headers_handler_.status_header().empty() &&
+ headers_handler_.status_header()[0] == '1') {
+ // If response headers carried a 1xx response code, final response headers
+ // should still be forthcoming.
+ it->second.received_header_type = HeaderType::RESPONSE_100;
+ } else {
+ it->second.received_header_type = headers_handler_.header_type();
+ }
+ }
headers_handler_.set_stream_id(0);
}
@@ -640,9 +718,7 @@ void OgHttp2Session::OnRstStream(spdy::SpdyStreamId stream_id,
write_scheduler_.UnregisterStream(stream_id);
}
visitor_.OnRstStream(stream_id, TranslateErrorCode(error_code));
- // TODO(birenroy): Consider bundling "close stream" behavior into a dedicated
- // method that also cleans up the stream map.
- visitor_.OnCloseStream(stream_id, TranslateErrorCode(error_code));
+ CloseStream(stream_id, TranslateErrorCode(error_code));
}
void OgHttp2Session::OnSettings() {
@@ -653,6 +729,10 @@ void OgHttp2Session::OnSetting(spdy::SpdySettingsId id, uint32_t value) {
visitor_.OnSetting({id, value});
if (id == kMetadataExtensionId) {
peer_supports_metadata_ = (value != 0);
+ } else if (id == MAX_FRAME_SIZE) {
+ max_frame_payload_ = value;
+ } else if (id == MAX_CONCURRENT_STREAMS) {
+ max_outbound_concurrent_streams_ = value;
}
}
@@ -674,8 +754,11 @@ void OgHttp2Session::OnPing(spdy::SpdyPingId unique_id, bool is_ack) {
void OgHttp2Session::OnGoAway(spdy::SpdyStreamId last_accepted_stream_id,
spdy::SpdyErrorCode error_code) {
received_goaway_ = true;
- visitor_.OnGoAway(last_accepted_stream_id, TranslateErrorCode(error_code),
- "");
+ const bool result = visitor_.OnGoAway(last_accepted_stream_id,
+ TranslateErrorCode(error_code), "");
+ if (!result) {
+ decoder_.StopProcessing();
+ }
}
bool OgHttp2Session::OnGoAwayFrameData(const char* /*goaway_data*/, size_t
@@ -748,7 +831,7 @@ void OgHttp2Session::OnHeaderStatus(
stream_id, spdy::ERROR_CODE_INTERNAL_ERROR));
}
} else if (result == Http2VisitorInterface::HEADER_CONNECTION_ERROR) {
- visitor_.OnConnectionError();
+ LatchErrorAndNotify();
}
}
@@ -771,13 +854,17 @@ bool OgHttp2Session::OnFrameHeader(spdy::SpdyStreamId stream_id, size_t length,
void OgHttp2Session::OnFramePayload(const char* data, size_t len) {
if (metadata_length_ > 0) {
QUICHE_DCHECK_LE(len, metadata_length_);
- visitor_.OnMetadataForStream(metadata_stream_id_,
- absl::string_view(data, len));
- metadata_length_ -= len;
- if (metadata_length_ == 0 && end_metadata_) {
- visitor_.OnMetadataEndForStream(metadata_stream_id_);
- metadata_stream_id_ = 0;
- end_metadata_ = false;
+ const bool success = visitor_.OnMetadataForStream(
+ metadata_stream_id_, absl::string_view(data, len));
+ if (success) {
+ metadata_length_ -= len;
+ if (metadata_length_ == 0 && end_metadata_) {
+ visitor_.OnMetadataEndForStream(metadata_stream_id_);
+ metadata_stream_id_ = 0;
+ end_metadata_ = false;
+ }
+ } else {
+ decoder_.StopProcessing();
}
} else {
QUICHE_DLOG(INFO) << "Unexpected metadata payload for stream "
@@ -808,6 +895,15 @@ void OgHttp2Session::SendWindowUpdate(Http2StreamId stream_id,
absl::make_unique<spdy::SpdyWindowUpdateIR>(stream_id, update_delta));
}
+void OgHttp2Session::SendHeaders(Http2StreamId stream_id,
+ spdy::SpdyHeaderBlock headers,
+ bool end_stream) {
+ auto frame =
+ absl::make_unique<spdy::SpdyHeadersIR>(stream_id, std::move(headers));
+ frame->set_fin(end_stream);
+ EnqueueFrame(std::move(frame));
+}
+
void OgHttp2Session::SendTrailers(Http2StreamId stream_id,
spdy::SpdyHeaderBlock trailers) {
auto frame =
@@ -816,22 +912,22 @@ void OgHttp2Session::SendTrailers(Http2StreamId stream_id,
EnqueueFrame(std::move(frame));
}
-void OgHttp2Session::MaybeCloseWithRstStream(Http2StreamId stream_id,
+bool OgHttp2Session::MaybeCloseWithRstStream(Http2StreamId stream_id,
StreamState& state) {
state.half_closed_local = true;
if (options_.perspective == Perspective::kServer) {
if (state.half_closed_remote) {
- visitor_.OnCloseStream(stream_id, Http2ErrorCode::NO_ERROR);
+ CloseStream(stream_id, Http2ErrorCode::NO_ERROR);
+ return true;
} else {
// Since the peer has not yet ended the stream, this endpoint should
// send a RST_STREAM NO_ERROR. See RFC 7540 Section 8.1.
EnqueueFrame(absl::make_unique<spdy::SpdyRstStreamIR>(
stream_id, spdy::SpdyErrorCode::ERROR_CODE_NO_ERROR));
- // Enqueuing the RST_STREAM also invokes OnCloseStream.
+ // Sending the RST_STREAM also invokes OnCloseStream.
}
- // TODO(birenroy): the server adapter should probably delete stream state
- // when calling visitor_.OnCloseStream.
}
+ return false;
}
void OgHttp2Session::MarkDataBuffered(Http2StreamId stream_id, size_t bytes) {
@@ -861,5 +957,56 @@ OgHttp2Session::StreamStateMap::iterator OgHttp2Session::CreateStream(
return iter;
}
+void OgHttp2Session::StartRequest(Http2StreamId stream_id,
+ spdy::SpdyHeaderBlock headers,
+ std::unique_ptr<DataFrameSource> data_source,
+ void* user_data) {
+ auto iter = CreateStream(stream_id);
+ write_scheduler_.MarkStreamReady(stream_id, false);
+ const bool end_stream = data_source == nullptr;
+ if (end_stream) {
+ iter->second.half_closed_local = true;
+ } else {
+ iter->second.outbound_body = std::move(data_source);
+ }
+ iter->second.user_data = user_data;
+ SendHeaders(stream_id, std::move(headers), end_stream);
+}
+
+void OgHttp2Session::CloseStream(Http2StreamId stream_id,
+ Http2ErrorCode error_code) {
+ visitor_.OnCloseStream(stream_id, error_code);
+ stream_map_.erase(stream_id);
+
+ if (!pending_streams_.empty() && CanCreateStream()) {
+ PendingStreamState& pending_stream = pending_streams_.front();
+ StartRequest(pending_stream.stream_id, std::move(pending_stream.headers),
+ std::move(pending_stream.data_source),
+ pending_stream.user_data);
+ pending_streams_.pop_front();
+ }
+}
+
+bool OgHttp2Session::CanCreateStream() const {
+ return stream_map_.size() < max_outbound_concurrent_streams_;
+}
+
+HeaderType OgHttp2Session::NextHeaderType(
+ absl::optional<HeaderType> current_type) {
+ if (IsServerSession()) {
+ return HeaderType::REQUEST;
+ } else if (!current_type ||
+ current_type.value() == HeaderType::RESPONSE_100) {
+ return HeaderType::RESPONSE;
+ } else {
+ return HeaderType::RESPONSE_TRAILER;
+ }
+}
+
+void OgHttp2Session::LatchErrorAndNotify() {
+ latched_error_ = true;
+ visitor_.OnConnectionError();
+}
+
} // namespace adapter
} // namespace http2
diff --git a/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_session.h b/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_session.h
index 77b9da73c38..75f9c96868c 100644
--- a/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_session.h
+++ b/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_session.h
@@ -1,18 +1,23 @@
#ifndef QUICHE_HTTP2_ADAPTER_OGHTTP2_SESSION_H_
#define QUICHE_HTTP2_ADAPTER_OGHTTP2_SESSION_H_
+#include <cstdint>
#include <list>
#include "http2/adapter/data_source.h"
+#include "http2/adapter/header_validator.h"
+#include "http2/adapter/http2_protocol.h"
#include "http2/adapter/http2_session.h"
#include "http2/adapter/http2_util.h"
#include "http2/adapter/http2_visitor_interface.h"
#include "http2/adapter/window_manager.h"
+#include "http2/core/http2_trace_logging.h"
#include "http2/core/priority_write_scheduler.h"
#include "common/platform/api/quiche_bug_tracker.h"
#include "common/platform/api/quiche_export.h"
#include "spdy/core/http2_frame_decoder_adapter.h"
#include "spdy/core/spdy_framer.h"
+#include "spdy/core/spdy_header_block.h"
namespace http2 {
namespace adapter {
@@ -37,7 +42,8 @@ class QUICHE_EXPORT_PRIVATE OgHttp2Session
// sent.
void StartGracefulShutdown();
- // Invokes the visitor's OnReadyToSend() method for serialized frame data.
+ // Invokes the visitor's OnReadyToSend() method for serialized frames and
+ // DataFrameSource::Send() for data frames.
int Send();
int32_t SubmitRequest(absl::Span<const Header> headers,
@@ -84,9 +90,11 @@ class QUICHE_EXPORT_PRIVATE OgHttp2Session
int GetHpackDecoderDynamicTableSize() const;
// From Http2Session.
- ssize_t ProcessBytes(absl::string_view bytes) override;
+ int64_t ProcessBytes(absl::string_view bytes) override;
int Consume(Http2StreamId stream_id, size_t num_bytes) override;
- bool want_read() const override { return !received_goaway_; }
+ bool want_read() const override {
+ return !received_goaway_ && !decoder_.HasError();
+ }
bool want_write() const override {
return !frames_.empty() || !serialized_prefix_.empty() ||
write_scheduler_.HasReadyStreams() || !connection_metadata_.empty();
@@ -162,6 +170,7 @@ class QUICHE_EXPORT_PRIVATE OgHttp2Session
private:
using MetadataSequence = std::vector<std::unique_ptr<MetadataSource>>;
+
struct QUICHE_EXPORT_PRIVATE StreamState {
StreamState(int32_t stream_receive_window,
WindowManager::WindowUpdateListener listener)
@@ -173,25 +182,43 @@ class QUICHE_EXPORT_PRIVATE OgHttp2Session
std::unique_ptr<spdy::SpdyHeaderBlock> trailers;
void* user_data = nullptr;
int32_t send_window = kInitialFlowControlWindowSize;
+ absl::optional<HeaderType> received_header_type;
bool half_closed_local = false;
bool half_closed_remote = false;
};
using StreamStateMap = absl::flat_hash_map<Http2StreamId, StreamState>;
+ struct QUICHE_EXPORT_PRIVATE PendingStreamState {
+ Http2StreamId stream_id;
+ spdy::SpdyHeaderBlock headers;
+ std::unique_ptr<DataFrameSource> data_source;
+ void* user_data = nullptr;
+ };
+
class QUICHE_EXPORT_PRIVATE PassthroughHeadersHandler
: public spdy::SpdyHeadersHandlerInterface {
public:
explicit PassthroughHeadersHandler(OgHttp2Session& session,
Http2VisitorInterface& visitor)
: session_(session), visitor_(visitor) {}
+
void set_stream_id(Http2StreamId stream_id) {
stream_id_ = stream_id;
result_ = Http2VisitorInterface::HEADER_OK;
}
+
+ void set_header_type(HeaderType type) { type_ = type; }
+ HeaderType header_type() const { return type_; }
+
void OnHeaderBlockStart() override;
void OnHeader(absl::string_view key, absl::string_view value) override;
void OnHeaderBlockEnd(size_t /* uncompressed_header_bytes */,
size_t /* compressed_header_bytes */) override;
+ absl::string_view status_header() {
+ QUICHE_DCHECK(type_ == HeaderType::RESPONSE ||
+ type_ == HeaderType::RESPONSE_100);
+ return validator_.status_header();
+ }
private:
OgHttp2Session& session_;
@@ -199,6 +226,9 @@ class QUICHE_EXPORT_PRIVATE OgHttp2Session
Http2StreamId stream_id_ = 0;
Http2VisitorInterface::OnHeaderResult result_ =
Http2VisitorInterface::HEADER_OK;
+ // Validates header blocks according to the HTTP/2 specification.
+ HeaderValidator validator_;
+ HeaderType type_ = HeaderType::RESPONSE;
};
// Queues the connection preface, if not already done.
@@ -216,30 +246,61 @@ class QUICHE_EXPORT_PRIVATE OgHttp2Session
bool SendMetadata(Http2StreamId stream_id, MetadataSequence& sequence);
+ void SendHeaders(Http2StreamId stream_id, spdy::SpdyHeaderBlock headers,
+ bool end_stream);
+
void SendTrailers(Http2StreamId stream_id, spdy::SpdyHeaderBlock trailers);
// Encapsulates the RST_STREAM NO_ERROR behavior described in RFC 7540
- // Section 8.1.
- void MaybeCloseWithRstStream(Http2StreamId stream_id, StreamState& state);
+ // Section 8.1. Returns true if the stream is closed.
+ bool MaybeCloseWithRstStream(Http2StreamId stream_id, StreamState& state);
// Performs flow control accounting for data sent by the peer.
void MarkDataBuffered(Http2StreamId stream_id, size_t bytes);
- // Creates a stream and returns an iterator pointing to it.
+ // Creates a stream for `stream_id` if not already present and returns an
+ // iterator pointing to it.
StreamStateMap::iterator CreateStream(Http2StreamId stream_id);
+ // Creates a stream for `stream_id`, stores the `data_source` and `user_data`
+ // in the stream state, and sends the `headers`.
+ void StartRequest(Http2StreamId stream_id, spdy::SpdyHeaderBlock headers,
+ std::unique_ptr<DataFrameSource> data_source,
+ void* user_data);
+
+ // Closes the given `stream_id` with the given `error_code`.
+ void CloseStream(Http2StreamId stream_id, Http2ErrorCode error_code);
+
+ // Calculates the next expected header type for a stream in a given state.
+ HeaderType NextHeaderType(absl::optional<HeaderType> current_type);
+
+ // Returns true if the session can create a new stream.
+ bool CanCreateStream() const;
+
+ void LatchErrorAndNotify();
+
// Receives events when inbound frames are parsed.
Http2VisitorInterface& visitor_;
+ // Logs received frames when enabled.
+ Http2TraceLogger receive_logger_;
+ // Logs sent frames when enabled.
+ Http2FrameLogger send_logger_;
+
// Encodes outbound frames.
spdy::SpdyFramer framer_{spdy::SpdyFramer::ENABLE_COMPRESSION};
// Decodes inbound frames.
http2::Http2DecoderAdapter decoder_;
- // Maintains the state of all streams known to this session.
+ // Maintains the state of active streams known to this session.
StreamStateMap stream_map_;
+ // Maintains the state of pending streams known to this session. A pending
+ // stream is kept in this list until it can be created while complying with
+ // `max_outbound_concurrent_streams_`.
+ std::list<PendingStreamState> pending_streams_;
+
// Maintains the queue of outbound frames, and any serialized bytes that have
// not yet been consumed.
std::list<std::unique_ptr<spdy::SpdyFrameIR>> frames_;
@@ -266,10 +327,12 @@ class QUICHE_EXPORT_PRIVATE OgHttp2Session
Http2StreamId highest_received_stream_id_ = 0;
Http2StreamId metadata_stream_id_ = 0;
size_t metadata_length_ = 0;
- int connection_send_window_ = kInitialFlowControlWindowSize;
+ int32_t connection_send_window_ = kInitialFlowControlWindowSize;
// The initial flow control receive window size for any newly created streams.
- int stream_receive_window_limit_ = kInitialFlowControlWindowSize;
- int max_frame_payload_ = 16384;
+ int32_t stream_receive_window_limit_ = kInitialFlowControlWindowSize;
+ uint32_t max_frame_payload_ = 16384u;
+ // The spec encourages a value of at least 100 concurrent streams.
+ uint32_t max_outbound_concurrent_streams_ = 100u;
Options options_;
bool received_goaway_ = false;
bool queued_preface_ = false;
@@ -278,6 +341,7 @@ class QUICHE_EXPORT_PRIVATE OgHttp2Session
// Replace this with a stream ID, for multiple GOAWAY support.
bool queued_goaway_ = false;
+ bool latched_error_ = false;
};
} // namespace adapter
diff --git a/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_session_test.cc b/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_session_test.cc
index 3f24ea200ef..4fdee88aad2 100644
--- a/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_session_test.cc
+++ b/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_session_test.cc
@@ -60,8 +60,8 @@ TEST(OgHttp2SessionTest, ClientHandlesFrames) {
EXPECT_CALL(visitor, OnFrameHeader(0, 4, WINDOW_UPDATE, 0));
EXPECT_CALL(visitor, OnWindowUpdate(0, 1000));
- const size_t initial_result = session.ProcessBytes(initial_frames);
- EXPECT_EQ(initial_frames.size(), initial_result);
+ const int64_t initial_result = session.ProcessBytes(initial_frames);
+ EXPECT_EQ(initial_frames.size(), static_cast<size_t>(initial_result));
EXPECT_EQ(session.GetRemoteWindowSize(),
kInitialFlowControlWindowSize + 1000);
@@ -116,8 +116,8 @@ TEST(OgHttp2SessionTest, ClientHandlesFrames) {
EXPECT_CALL(visitor, OnCloseStream(3, Http2ErrorCode::INTERNAL_ERROR));
EXPECT_CALL(visitor, OnFrameHeader(0, 19, GOAWAY, 0));
EXPECT_CALL(visitor, OnGoAway(5, Http2ErrorCode::ENHANCE_YOUR_CALM, ""));
- const size_t stream_result = session.ProcessBytes(stream_frames);
- EXPECT_EQ(stream_frames.size(), stream_result);
+ const int64_t stream_result = session.ProcessBytes(stream_frames);
+ EXPECT_EQ(stream_frames.size(), static_cast<size_t>(stream_result));
EXPECT_EQ(3, session.GetHighestReceivedStreamId());
// The first stream is active and has received some data.
@@ -231,8 +231,8 @@ TEST(OgHttp2SessionTest, ClientSubmitRequest) {
EXPECT_CALL(visitor, OnSettingsStart());
EXPECT_CALL(visitor, OnSettingsEnd());
- const size_t initial_result = session.ProcessBytes(initial_frames);
- EXPECT_EQ(initial_frames.size(), initial_result);
+ const int64_t initial_result = session.ProcessBytes(initial_frames);
+ EXPECT_EQ(initial_frames.size(), static_cast<size_t>(initial_result));
// Session will want to write a SETTINGS ack.
EXPECT_TRUE(session.want_write());
@@ -550,6 +550,7 @@ TEST(OgHttp2SessionTest, ServerHandlesFrames) {
EXPECT_CALL(visitor, OnEndHeadersForStream(1))
.WillOnce(testing::InvokeWithoutArgs([&session, kSentinel1]() {
session.SetStreamUserData(1, const_cast<char*>(kSentinel1));
+ return true;
}));
EXPECT_CALL(visitor, OnFrameHeader(1, 4, WINDOW_UPDATE, 0));
EXPECT_CALL(visitor, OnWindowUpdate(1, 2000));
@@ -570,8 +571,8 @@ TEST(OgHttp2SessionTest, ServerHandlesFrames) {
EXPECT_CALL(visitor, OnFrameHeader(0, 8, PING, 0));
EXPECT_CALL(visitor, OnPing(47, false));
- const size_t result = session.ProcessBytes(frames);
- EXPECT_EQ(frames.size(), result);
+ const int64_t result = session.ProcessBytes(frames);
+ EXPECT_EQ(frames.size(), static_cast<size_t>(result));
EXPECT_EQ(kSentinel1, session.GetStreamUserData(1));
@@ -587,11 +588,10 @@ TEST(OgHttp2SessionTest, ServerHandlesFrames) {
EXPECT_GT(session.GetHpackDecoderDynamicTableSize(), 0);
- // TODO(birenroy): drop stream state when streams are closed. It should no
- // longer be possible to set user data.
+ // It should no longer be possible to set user data on a closed stream.
const char* kSentinel3 = "another arbitrary pointer";
session.SetStreamUserData(3, const_cast<char*>(kSentinel3));
- EXPECT_EQ(kSentinel3, session.GetStreamUserData(3));
+ EXPECT_EQ(nullptr, session.GetStreamUserData(3));
EXPECT_EQ(session.GetRemoteWindowSize(),
kInitialFlowControlWindowSize + 1000);
@@ -686,11 +686,12 @@ TEST(OgHttp2SessionTest, ServerSubmitResponse) {
EXPECT_CALL(visitor, OnEndHeadersForStream(1))
.WillOnce(testing::InvokeWithoutArgs([&session, kSentinel1]() {
session.SetStreamUserData(1, const_cast<char*>(kSentinel1));
+ return true;
}));
EXPECT_CALL(visitor, OnEndStream(1));
- const size_t result = session.ProcessBytes(frames);
- EXPECT_EQ(frames.size(), result);
+ const int64_t result = session.ProcessBytes(frames);
+ EXPECT_EQ(frames.size(), static_cast<size_t>(result));
EXPECT_EQ(1, session.GetHighestReceivedStreamId());
@@ -830,8 +831,8 @@ TEST(OgHttp2SessionTest, ServerSendsTrailers) {
EXPECT_CALL(visitor, OnEndHeadersForStream(1));
EXPECT_CALL(visitor, OnEndStream(1));
- const size_t result = session.ProcessBytes(frames);
- EXPECT_EQ(frames.size(), result);
+ const int64_t result = session.ProcessBytes(frames);
+ EXPECT_EQ(frames.size(), static_cast<size_t>(result));
// Server will want to send initial SETTINGS, and a SETTINGS ack.
EXPECT_TRUE(session.want_write());
@@ -922,8 +923,8 @@ TEST(OgHttp2SessionTest, ServerQueuesTrailersWithResponse) {
EXPECT_CALL(visitor, OnEndHeadersForStream(1));
EXPECT_CALL(visitor, OnEndStream(1));
- const size_t result = session.ProcessBytes(frames);
- EXPECT_EQ(frames.size(), result);
+ const int64_t result = session.ProcessBytes(frames);
+ EXPECT_EQ(frames.size(), static_cast<size_t>(result));
// Server will want to send initial SETTINGS, and a SETTINGS ack.
EXPECT_TRUE(session.want_write());
diff --git a/chromium/net/third_party/quiche/src/http2/adapter/recording_http2_visitor.cc b/chromium/net/third_party/quiche/src/http2/adapter/recording_http2_visitor.cc
index 75f3749e62c..4dbe4e21ccc 100644
--- a/chromium/net/third_party/quiche/src/http2/adapter/recording_http2_visitor.cc
+++ b/chromium/net/third_party/quiche/src/http2/adapter/recording_http2_visitor.cc
@@ -7,7 +7,7 @@ namespace http2 {
namespace adapter {
namespace test {
-ssize_t RecordingHttp2Visitor::OnReadyToSend(absl::string_view serialized) {
+int64_t RecordingHttp2Visitor::OnReadyToSend(absl::string_view serialized) {
events_.push_back(absl::StrFormat("OnReadyToSend %d", serialized.size()));
return serialized.size();
}
@@ -16,12 +16,12 @@ void RecordingHttp2Visitor::OnConnectionError() {
events_.push_back("OnConnectionError");
}
-void RecordingHttp2Visitor::OnFrameHeader(Http2StreamId stream_id,
- size_t length,
- uint8_t type,
+bool RecordingHttp2Visitor::OnFrameHeader(Http2StreamId stream_id,
+ size_t length, uint8_t type,
uint8_t flags) {
events_.push_back(absl::StrFormat("OnFrameHeader %d %d %d %d", stream_id,
length, type, flags));
+ return true;
}
void RecordingHttp2Visitor::OnSettingsStart() {
@@ -53,19 +53,22 @@ Http2VisitorInterface::OnHeaderResult RecordingHttp2Visitor::OnHeaderForStream(
return HEADER_OK;
}
-void RecordingHttp2Visitor::OnEndHeadersForStream(Http2StreamId stream_id) {
+bool RecordingHttp2Visitor::OnEndHeadersForStream(Http2StreamId stream_id) {
events_.push_back(absl::StrFormat("OnEndHeadersForStream %d", stream_id));
+ return true;
}
-void RecordingHttp2Visitor::OnBeginDataForStream(Http2StreamId stream_id,
+bool RecordingHttp2Visitor::OnBeginDataForStream(Http2StreamId stream_id,
size_t payload_length) {
events_.push_back(
absl::StrFormat("OnBeginDataForStream %d %d", stream_id, payload_length));
+ return true;
}
-void RecordingHttp2Visitor::OnDataForStream(Http2StreamId stream_id,
+bool RecordingHttp2Visitor::OnDataForStream(Http2StreamId stream_id,
absl::string_view data) {
events_.push_back(absl::StrFormat("OnDataForStream %d %s", stream_id, data));
+ return true;
}
void RecordingHttp2Visitor::OnEndStream(Http2StreamId stream_id) {
@@ -104,12 +107,13 @@ void RecordingHttp2Visitor::OnPushPromiseForStream(
promised_stream_id));
}
-void RecordingHttp2Visitor::OnGoAway(Http2StreamId last_accepted_stream_id,
+bool RecordingHttp2Visitor::OnGoAway(Http2StreamId last_accepted_stream_id,
Http2ErrorCode error_code,
absl::string_view opaque_data) {
events_.push_back(
absl::StrFormat("OnGoAway %d %s %s", last_accepted_stream_id,
Http2ErrorCodeToString(error_code), opaque_data));
+ return true;
}
void RecordingHttp2Visitor::OnWindowUpdate(Http2StreamId stream_id,
@@ -141,34 +145,17 @@ bool RecordingHttp2Visitor::OnInvalidFrame(Http2StreamId stream_id,
return true;
}
-void RecordingHttp2Visitor::OnReadyToSendDataForStream(
- Http2StreamId stream_id, char* /*destination_buffer*/, size_t length,
- ssize_t* /*written*/, bool* /*end_stream*/) {
- // TODO(b/181586191): Revisit this. The visitor is expected to write to the
- // |destination_buffer| and set the other pointer values appropriately.
- events_.push_back(
- absl::StrFormat("OnReadyToSendDataForStream %d %d", stream_id, length));
-}
-
-void RecordingHttp2Visitor::OnReadyToSendMetadataForStream(
- Http2StreamId stream_id, char* /*buffer*/, size_t length,
- ssize_t* /*written*/) {
- // TODO(b/181586191): Revisit this. The visitor is expected to write to the
- // |buffer| and set *written appropriately.
- events_.push_back(absl::StrFormat("OnReadyToSendMetadataForStream %d %d",
- stream_id, length));
-}
-
void RecordingHttp2Visitor::OnBeginMetadataForStream(Http2StreamId stream_id,
size_t payload_length) {
events_.push_back(absl::StrFormat("OnBeginMetadataForStream %d %d", stream_id,
payload_length));
}
-void RecordingHttp2Visitor::OnMetadataForStream(Http2StreamId stream_id,
+bool RecordingHttp2Visitor::OnMetadataForStream(Http2StreamId stream_id,
absl::string_view metadata) {
events_.push_back(
absl::StrFormat("OnMetadataForStream %d %s", stream_id, metadata));
+ return true;
}
bool RecordingHttp2Visitor::OnMetadataEndForStream(Http2StreamId stream_id) {
diff --git a/chromium/net/third_party/quiche/src/http2/adapter/recording_http2_visitor.h b/chromium/net/third_party/quiche/src/http2/adapter/recording_http2_visitor.h
index 25b92935b35..8946ad3499c 100644
--- a/chromium/net/third_party/quiche/src/http2/adapter/recording_http2_visitor.h
+++ b/chromium/net/third_party/quiche/src/http2/adapter/recording_http2_visitor.h
@@ -1,6 +1,7 @@
#ifndef QUICHE_HTTP2_ADAPTER_RECORDING_HTTP2_VISITOR_H_
#define QUICHE_HTTP2_ADAPTER_RECORDING_HTTP2_VISITOR_H_
+#include <cstdint>
#include <list>
#include <string>
@@ -19,11 +20,9 @@ class QUICHE_NO_EXPORT RecordingHttp2Visitor : public Http2VisitorInterface {
using EventSequence = std::list<Event>;
// From Http2VisitorInterface
- ssize_t OnReadyToSend(absl::string_view serialized) override;
+ int64_t OnReadyToSend(absl::string_view serialized) override;
void OnConnectionError() override;
- void OnFrameHeader(Http2StreamId stream_id,
- size_t length,
- uint8_t type,
+ bool OnFrameHeader(Http2StreamId stream_id, size_t length, uint8_t type,
uint8_t flags) override;
void OnSettingsStart() override;
void OnSetting(Http2Setting setting) override;
@@ -33,10 +32,10 @@ class QUICHE_NO_EXPORT RecordingHttp2Visitor : public Http2VisitorInterface {
OnHeaderResult OnHeaderForStream(Http2StreamId stream_id,
absl::string_view name,
absl::string_view value) override;
- void OnEndHeadersForStream(Http2StreamId stream_id) override;
- void OnBeginDataForStream(Http2StreamId stream_id,
+ bool OnEndHeadersForStream(Http2StreamId stream_id) override;
+ bool OnBeginDataForStream(Http2StreamId stream_id,
size_t payload_length) override;
- void OnDataForStream(Http2StreamId stream_id,
+ bool OnDataForStream(Http2StreamId stream_id,
absl::string_view data) override;
void OnEndStream(Http2StreamId stream_id) override;
void OnRstStream(Http2StreamId stream_id, Http2ErrorCode error_code) override;
@@ -49,7 +48,7 @@ class QUICHE_NO_EXPORT RecordingHttp2Visitor : public Http2VisitorInterface {
void OnPing(Http2PingId ping_id, bool is_ack) override;
void OnPushPromiseForStream(Http2StreamId stream_id,
Http2StreamId promised_stream_id) override;
- void OnGoAway(Http2StreamId last_accepted_stream_id,
+ bool OnGoAway(Http2StreamId last_accepted_stream_id,
Http2ErrorCode error_code,
absl::string_view opaque_data) override;
void OnWindowUpdate(Http2StreamId stream_id, int window_increment) override;
@@ -58,18 +57,9 @@ class QUICHE_NO_EXPORT RecordingHttp2Visitor : public Http2VisitorInterface {
int OnFrameSent(uint8_t frame_type, Http2StreamId stream_id, size_t length,
uint8_t flags, uint32_t error_code) override;
bool OnInvalidFrame(Http2StreamId stream_id, int error_code) override;
- void OnReadyToSendDataForStream(Http2StreamId stream_id,
- char* destination_buffer,
- size_t length,
- ssize_t* written,
- bool* end_stream) override;
- void OnReadyToSendMetadataForStream(Http2StreamId stream_id,
- char* buffer,
- size_t length,
- ssize_t* written) override;
void OnBeginMetadataForStream(Http2StreamId stream_id,
size_t payload_length) override;
- void OnMetadataForStream(Http2StreamId stream_id,
+ bool OnMetadataForStream(Http2StreamId stream_id,
absl::string_view metadata) override;
bool OnMetadataEndForStream(Http2StreamId stream_id) override;
void OnErrorDebug(absl::string_view message) override;
diff --git a/chromium/net/third_party/quiche/src/http2/adapter/recording_http2_visitor_test.cc b/chromium/net/third_party/quiche/src/http2/adapter/recording_http2_visitor_test.cc
index 8f278d75dcb..6763244d4c7 100644
--- a/chromium/net/third_party/quiche/src/http2/adapter/recording_http2_visitor_test.cc
+++ b/chromium/net/third_party/quiche/src/http2/adapter/recording_http2_visitor_test.cc
@@ -85,11 +85,6 @@ TEST(RecordingHttp2VisitorTest, SameEventsProduceSameSequence) {
visitor->OnPushPromiseForStream(stream_id, another_stream_id);
visitor->OnGoAway(stream_id, error_code, some_string);
visitor->OnWindowUpdate(stream_id, some_int);
- visitor->OnReadyToSendDataForStream(
- stream_id, /*destination_buffer=*/nullptr, length, /*written=*/nullptr,
- /*end_stream=*/nullptr);
- visitor->OnReadyToSendMetadataForStream(stream_id, /*buffer=*/nullptr,
- length, /*written=*/nullptr);
visitor->OnBeginMetadataForStream(stream_id, length);
visitor->OnMetadataForStream(stream_id, some_string);
visitor->OnMetadataForStream(stream_id, another_string);
diff --git a/chromium/net/third_party/quiche/src/http2/adapter/test_frame_sequence.cc b/chromium/net/third_party/quiche/src/http2/adapter/test_frame_sequence.cc
index bb1517d3d73..7a3f1157d0c 100644
--- a/chromium/net/third_party/quiche/src/http2/adapter/test_frame_sequence.cc
+++ b/chromium/net/third_party/quiche/src/http2/adapter/test_frame_sequence.cc
@@ -19,15 +19,15 @@ std::vector<const Header> ToHeaders(
return out;
}
-TestFrameSequence& TestFrameSequence::ClientPreface() {
+TestFrameSequence& TestFrameSequence::ClientPreface(
+ absl::Span<const Http2Setting> settings) {
preface_ = spdy::kHttp2ConnectionHeaderPrefix;
- frames_.push_back(absl::make_unique<spdy::SpdySettingsIR>());
- return *this;
+ return Settings(settings);
}
-TestFrameSequence& TestFrameSequence::ServerPreface() {
- frames_.push_back(absl::make_unique<spdy::SpdySettingsIR>());
- return *this;
+TestFrameSequence& TestFrameSequence::ServerPreface(
+ absl::Span<const Http2Setting> settings) {
+ return Settings(settings);
}
TestFrameSequence& TestFrameSequence::Data(Http2StreamId stream_id,
@@ -51,12 +51,12 @@ TestFrameSequence& TestFrameSequence::RstStream(Http2StreamId stream_id,
}
TestFrameSequence& TestFrameSequence::Settings(
- absl::Span<Http2Setting> values) {
- auto settings = absl::make_unique<spdy::SpdySettingsIR>();
- for (const Http2Setting& setting : values) {
- settings->AddSetting(setting.id, setting.value);
+ absl::Span<const Http2Setting> settings) {
+ auto settings_frame = absl::make_unique<spdy::SpdySettingsIR>();
+ for (const Http2Setting& setting : settings) {
+ settings_frame->AddSetting(setting.id, setting.value);
}
- frames_.push_back(std::move(settings));
+ frames_.push_back(std::move(settings_frame));
return *this;
}
@@ -102,10 +102,9 @@ TestFrameSequence& TestFrameSequence::Headers(Http2StreamId stream_id,
// nonterminal HEADERS frame explicitly, so we'll need to use
// SpdyUnknownIRs. For simplicity, and in order not to mess up HPACK state,
// the payload will be uncompressed.
- std::string encoded_block;
spdy::HpackEncoder encoder;
encoder.DisableCompression();
- encoder.EncodeHeaderSet(block, &encoded_block);
+ std::string encoded_block = encoder.EncodeHeaderBlock(block);
const size_t pos = encoded_block.size() / 2;
const uint8_t flags = fin ? 0x1 : 0x0;
frames_.push_back(absl::make_unique<spdy::SpdyUnknownIR>(
@@ -186,9 +185,7 @@ std::string TestFrameSequence::MetadataBlockForPayload(
block["example-payload"] = payload;
spdy::HpackEncoder encoder;
encoder.DisableCompression();
- std::string encoded_payload;
- encoder.EncodeHeaderSet(block, &encoded_payload);
- return encoded_payload;
+ return encoder.EncodeHeaderBlock(block);
}
} // namespace test
diff --git a/chromium/net/third_party/quiche/src/http2/adapter/test_frame_sequence.h b/chromium/net/third_party/quiche/src/http2/adapter/test_frame_sequence.h
index 99740d38f9e..43e97db2824 100644
--- a/chromium/net/third_party/quiche/src/http2/adapter/test_frame_sequence.h
+++ b/chromium/net/third_party/quiche/src/http2/adapter/test_frame_sequence.h
@@ -1,6 +1,7 @@
#ifndef QUICHE_HTTP2_ADAPTER_TEST_FRAME_SEQUENCE_H_
#define QUICHE_HTTP2_ADAPTER_TEST_FRAME_SEQUENCE_H_
+#include <cstdint>
#include <memory>
#include <string>
#include <vector>
@@ -20,14 +21,16 @@ class QUICHE_NO_EXPORT TestFrameSequence {
public:
TestFrameSequence() = default;
- TestFrameSequence& ClientPreface();
- TestFrameSequence& ServerPreface();
+ TestFrameSequence& ClientPreface(
+ absl::Span<const Http2Setting> settings = {});
+ TestFrameSequence& ServerPreface(
+ absl::Span<const Http2Setting> settings = {});
TestFrameSequence& Data(Http2StreamId stream_id,
absl::string_view payload,
bool fin = false,
absl::optional<int> padding_length = absl::nullopt);
TestFrameSequence& RstStream(Http2StreamId stream_id, Http2ErrorCode error);
- TestFrameSequence& Settings(absl::Span<Http2Setting> values);
+ TestFrameSequence& Settings(absl::Span<const Http2Setting> settings);
TestFrameSequence& SettingsAck();
TestFrameSequence& Ping(Http2PingId id);
TestFrameSequence& PingAck(Http2PingId id);
diff --git a/chromium/net/third_party/quiche/src/http2/adapter/test_utils.cc b/chromium/net/third_party/quiche/src/http2/adapter/test_utils.cc
index b8acddbb87f..80e113e820b 100644
--- a/chromium/net/third_party/quiche/src/http2/adapter/test_utils.cc
+++ b/chromium/net/third_party/quiche/src/http2/adapter/test_utils.cc
@@ -25,14 +25,14 @@ void TestDataFrameSource::AppendPayload(absl::string_view payload) {
void TestDataFrameSource::EndData() { end_data_ = true; }
-std::pair<ssize_t, bool> TestDataFrameSource::SelectPayloadLength(
+std::pair<int64_t, bool> TestDataFrameSource::SelectPayloadLength(
size_t max_length) {
// The stream is done if there's no more data, or if |max_length| is at least
// as large as the remaining data.
const bool end_data = end_data_ && (current_fragment_.empty() ||
(payload_fragments_.size() == 1 &&
max_length >= current_fragment_.size()));
- const ssize_t length = std::min(max_length, current_fragment_.size());
+ const int64_t length = std::min(max_length, current_fragment_.size());
return {length, end_data};
}
@@ -43,7 +43,7 @@ bool TestDataFrameSource::Send(absl::string_view frame_header,
<< " current_fragment_size: " << current_fragment_.size();
const std::string concatenated =
absl::StrCat(frame_header, current_fragment_.substr(0, payload_length));
- const ssize_t result = visitor_.OnReadyToSend(concatenated);
+ const int64_t result = visitor_.OnReadyToSend(concatenated);
if (result < 0) {
// Write encountered error.
visitor_.OnConnectionError();
@@ -77,9 +77,7 @@ bool TestDataFrameSource::Send(absl::string_view frame_header,
std::string EncodeHeaders(const spdy::SpdyHeaderBlock& entries) {
spdy::HpackEncoder encoder;
encoder.DisableCompression();
- std::string result;
- QUICHE_CHECK(encoder.EncodeHeaderSet(entries, &result));
- return result;
+ return encoder.EncodeHeaderBlock(entries);
}
TestMetadataSource::TestMetadataSource(const spdy::SpdyHeaderBlock& entries)
@@ -87,7 +85,7 @@ TestMetadataSource::TestMetadataSource(const spdy::SpdyHeaderBlock& entries)
remaining_ = encoded_entries_;
}
-std::pair<ssize_t, bool> TestMetadataSource::Pack(uint8_t* dest,
+std::pair<int64_t, bool> TestMetadataSource::Pack(uint8_t* dest,
size_t dest_len) {
const size_t copied = std::min(dest_len, remaining_.size());
std::memcpy(dest, remaining_.data(), copied);
diff --git a/chromium/net/third_party/quiche/src/http2/adapter/test_utils.h b/chromium/net/third_party/quiche/src/http2/adapter/test_utils.h
index d92617fa3c9..ec7e95cc4de 100644
--- a/chromium/net/third_party/quiche/src/http2/adapter/test_utils.h
+++ b/chromium/net/third_party/quiche/src/http2/adapter/test_utils.h
@@ -1,6 +1,7 @@
#ifndef QUICHE_HTTP2_ADAPTER_TEST_UTILS_H_
#define QUICHE_HTTP2_ADAPTER_TEST_UTILS_H_
+#include <cstdint>
#include <string>
#include <vector>
@@ -21,7 +22,10 @@ namespace test {
class QUICHE_NO_EXPORT DataSavingVisitor
: public testing::StrictMock<MockHttp2Visitor> {
public:
- ssize_t OnReadyToSend(absl::string_view data) override {
+ int64_t OnReadyToSend(absl::string_view data) override {
+ if (has_write_error_) {
+ return kSendError;
+ }
if (is_write_blocked_) {
return kSendBlocked;
}
@@ -33,13 +37,16 @@ class QUICHE_NO_EXPORT DataSavingVisitor
return to_accept;
}
- void OnMetadataForStream(Http2StreamId stream_id,
+ bool OnMetadataForStream(Http2StreamId stream_id,
absl::string_view metadata) override {
- testing::StrictMock<MockHttp2Visitor>::OnMetadataForStream(stream_id,
- metadata);
- auto result =
- metadata_map_.try_emplace(stream_id, std::vector<std::string>());
- result.first->second.push_back(std::string(metadata));
+ const bool ret = testing::StrictMock<MockHttp2Visitor>::OnMetadataForStream(
+ stream_id, metadata);
+ if (ret) {
+ auto result =
+ metadata_map_.try_emplace(stream_id, std::vector<std::string>());
+ result.first->second.push_back(std::string(metadata));
+ }
+ return ret;
}
const std::vector<std::string> GetMetadata(Http2StreamId stream_id) {
@@ -59,11 +66,14 @@ class QUICHE_NO_EXPORT DataSavingVisitor
bool is_write_blocked() const { return is_write_blocked_; }
void set_is_write_blocked(bool value) { is_write_blocked_ = value; }
+ void set_has_write_error() { has_write_error_ = true; }
+
private:
std::string data_;
absl::flat_hash_map<Http2StreamId, std::vector<std::string>> metadata_map_;
size_t send_limit_ = std::numeric_limits<size_t>::max();
bool is_write_blocked_ = false;
+ bool has_write_error_ = false;
};
// A test DataFrameSource. Starts out in the empty, blocked state.
@@ -74,7 +84,7 @@ class QUICHE_NO_EXPORT TestDataFrameSource : public DataFrameSource {
void AppendPayload(absl::string_view payload);
void EndData();
- std::pair<ssize_t, bool> SelectPayloadLength(size_t max_length) override;
+ std::pair<int64_t, bool> SelectPayloadLength(size_t max_length) override;
bool Send(absl::string_view frame_header, size_t payload_length) override;
bool send_fin() const override { return has_fin_; }
@@ -92,7 +102,11 @@ class QUICHE_NO_EXPORT TestMetadataSource : public MetadataSource {
public:
explicit TestMetadataSource(const spdy::SpdyHeaderBlock& entries);
- std::pair<ssize_t, bool> Pack(uint8_t* dest, size_t dest_len) override;
+ size_t NumFrames(size_t max_frame_size) const override {
+ // Round up to the next frame.
+ return (encoded_entries_.size() + max_frame_size - 1) / max_frame_size;
+ }
+ std::pair<int64_t, bool> Pack(uint8_t* dest, size_t dest_len) override;
private:
const std::string encoded_entries_;
diff --git a/chromium/net/third_party/quiche/src/http2/adapter/window_manager.h b/chromium/net/third_party/quiche/src/http2/adapter/window_manager.h
index f15982d466a..5a7701e91e0 100644
--- a/chromium/net/third_party/quiche/src/http2/adapter/window_manager.h
+++ b/chromium/net/third_party/quiche/src/http2/adapter/window_manager.h
@@ -1,6 +1,8 @@
#ifndef QUICHE_HTTP2_ADAPTER_WINDOW_MANAGER_H_
#define QUICHE_HTTP2_ADAPTER_WINDOW_MANAGER_H_
+#include <stddef.h>
+
#include <functional>
#include "common/platform/api/quiche_export.h"
diff --git a/chromium/net/third_party/quiche/src/http2/core/http2_trace_logging.cc b/chromium/net/third_party/quiche/src/http2/core/http2_trace_logging.cc
new file mode 100644
index 00000000000..2c1bee38a08
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/http2/core/http2_trace_logging.cc
@@ -0,0 +1,454 @@
+#include "http2/core/http2_trace_logging.h"
+
+#include <cstdint>
+
+#include "absl/strings/str_cat.h"
+#include "absl/strings/string_view.h"
+#include "common/platform/api/quiche_bug_tracker.h"
+#include "common/platform/api/quiche_logging.h"
+#include "spdy/core/spdy_protocol.h"
+
+// Convenience macros for printing function arguments in log lines in the
+// format arg_name=value.
+#define FORMAT_ARG(arg) " " #arg "=" << arg
+#define FORMAT_INT_ARG(arg) " " #arg "=" << static_cast<int>(arg)
+
+// Convenience macros for printing Spdy*IR attributes in log lines in the
+// format attrib_name=value.
+#define FORMAT_ATTR(ir, attrib) " " #attrib "=" << ir.attrib()
+#define FORMAT_INT_ATTR(ir, attrib) \
+ " " #attrib "=" << static_cast<int>(ir.attrib())
+
+namespace {
+
+// Logs a container, using a user-provided object to log each individual item.
+template <typename T, typename ItemLogger>
+struct ContainerLogger {
+ explicit ContainerLogger(const T& c, ItemLogger l)
+ : container(c), item_logger(l) {}
+
+ friend std::ostream& operator<<(std::ostream& out,
+ const ContainerLogger& logger) {
+ out << "[";
+ auto begin = logger.container.begin();
+ for (auto it = begin; it != logger.container.end(); ++it) {
+ if (it != begin) {
+ out << ", ";
+ }
+ logger.item_logger.Log(out, *it);
+ }
+ out << "]";
+ return out;
+ }
+ const T& container;
+ ItemLogger item_logger;
+};
+
+// Returns a ContainerLogger that will log |container| using |item_logger|.
+template <typename T, typename ItemLogger>
+auto LogContainer(const T& container, ItemLogger item_logger)
+ -> decltype(ContainerLogger<T, ItemLogger>(container, item_logger)) {
+ return ContainerLogger<T, ItemLogger>(container, item_logger);
+}
+
+} // anonymous namespace
+
+#define FORMAT_HEADER_BLOCK(ir) \
+ " header_block=" << LogContainer(ir.header_block(), LogHeaderBlockEntry())
+
+namespace http2 {
+
+using spdy::SettingsMap;
+using spdy::SpdyAltSvcIR;
+using spdy::SpdyContinuationIR;
+using spdy::SpdyDataIR;
+using spdy::SpdyGoAwayIR;
+using spdy::SpdyHeaderBlock;
+using spdy::SpdyHeadersIR;
+using spdy::SpdyPingIR;
+using spdy::SpdyPriorityIR;
+using spdy::SpdyPushPromiseIR;
+using spdy::SpdyRstStreamIR;
+using spdy::SpdySettingsIR;
+using spdy::SpdyStreamId;
+using spdy::SpdyUnknownIR;
+using spdy::SpdyWindowUpdateIR;
+
+namespace {
+
+// Defines how elements of SpdyHeaderBlocks are logged.
+struct LogHeaderBlockEntry {
+ void Log(std::ostream& out,
+ const SpdyHeaderBlock::value_type& entry) const { // NOLINT
+ out << "\"" << entry.first << "\": \"" << entry.second << "\"";
+ }
+};
+
+// Defines how elements of SettingsMap are logged.
+struct LogSettingsEntry {
+ void Log(std::ostream& out,
+ const SettingsMap::value_type& entry) const { // NOLINT
+ out << spdy::SettingsIdToString(entry.first) << ": " << entry.second;
+ }
+};
+
+// Defines how elements of AlternativeServiceVector are logged.
+struct LogAlternativeService {
+ void Log(std::ostream& out,
+ const spdy::SpdyAltSvcWireFormat::AlternativeService& altsvc)
+ const { // NOLINT
+ out << "{"
+ << "protocol_id=" << altsvc.protocol_id << " host=" << altsvc.host
+ << " port=" << altsvc.port
+ << " max_age_seconds=" << altsvc.max_age_seconds << " version=";
+ for (auto v : altsvc.version) {
+ out << v << ",";
+ }
+ out << "}";
+ }
+};
+
+} // anonymous namespace
+
+Http2TraceLogger::Http2TraceLogger(SpdyFramerVisitorInterface* parent,
+ absl::string_view perspective,
+ std::function<bool()> is_enabled,
+ const void* connection_id)
+ : wrapped_(parent),
+ perspective_(perspective),
+ is_enabled_(std::move(is_enabled)),
+ connection_id_(connection_id) {}
+
+Http2TraceLogger::~Http2TraceLogger() {
+ if (recording_headers_handler_ != nullptr &&
+ !recording_headers_handler_->decoded_block().empty()) {
+ HTTP2_TRACE_LOG(perspective_, is_enabled_)
+ << "connection_id=" << connection_id_
+ << " Received headers that were never logged! keys/values:"
+ << recording_headers_handler_->decoded_block().DebugString();
+ }
+}
+
+void Http2TraceLogger::OnError(Http2DecoderAdapter::SpdyFramerError error,
+ std::string detailed_error) {
+ HTTP2_TRACE_LOG(perspective_, is_enabled_)
+ << "OnError:" << FORMAT_ARG(connection_id_)
+ << ", error=" << Http2DecoderAdapter::SpdyFramerErrorToString(error);
+ wrapped_->OnError(error, detailed_error);
+}
+
+void Http2TraceLogger::OnCommonHeader(SpdyStreamId stream_id, size_t length,
+ uint8_t type, uint8_t flags) {
+ HTTP2_TRACE_LOG(perspective_, is_enabled_)
+ << "OnCommonHeader:" << FORMAT_ARG(connection_id_)
+ << FORMAT_ARG(stream_id) << FORMAT_ARG(length) << FORMAT_INT_ARG(type)
+ << FORMAT_INT_ARG(flags);
+ wrapped_->OnCommonHeader(stream_id, length, type, flags);
+}
+
+void Http2TraceLogger::OnDataFrameHeader(SpdyStreamId stream_id, size_t length,
+ bool fin) {
+ HTTP2_TRACE_LOG(perspective_, is_enabled_)
+ << "OnDataFrameHeader:" << FORMAT_ARG(connection_id_)
+ << FORMAT_ARG(stream_id) << FORMAT_ARG(length) << FORMAT_ARG(fin);
+ wrapped_->OnDataFrameHeader(stream_id, length, fin);
+}
+
+void Http2TraceLogger::OnStreamFrameData(SpdyStreamId stream_id,
+ const char* data, size_t len) {
+ HTTP2_TRACE_LOG(perspective_, is_enabled_)
+ << "OnStreamFrameData:" << FORMAT_ARG(connection_id_)
+ << FORMAT_ARG(stream_id) << FORMAT_ARG(len);
+ wrapped_->OnStreamFrameData(stream_id, data, len);
+}
+
+void Http2TraceLogger::OnStreamEnd(SpdyStreamId stream_id) {
+ HTTP2_TRACE_LOG(perspective_, is_enabled_)
+ << "OnStreamEnd:" << FORMAT_ARG(connection_id_) << FORMAT_ARG(stream_id);
+ wrapped_->OnStreamEnd(stream_id);
+}
+
+void Http2TraceLogger::OnStreamPadLength(SpdyStreamId stream_id, size_t value) {
+ HTTP2_TRACE_LOG(perspective_, is_enabled_)
+ << "OnStreamPadLength:" << FORMAT_ARG(connection_id_)
+ << FORMAT_ARG(stream_id) << FORMAT_ARG(value);
+ wrapped_->OnStreamPadLength(stream_id, value);
+}
+
+void Http2TraceLogger::OnStreamPadding(SpdyStreamId stream_id, size_t len) {
+ HTTP2_TRACE_LOG(perspective_, is_enabled_)
+ << "OnStreamPadding:" << FORMAT_ARG(connection_id_)
+ << FORMAT_ARG(stream_id) << FORMAT_ARG(len);
+ wrapped_->OnStreamPadding(stream_id, len);
+}
+
+spdy::SpdyHeadersHandlerInterface* Http2TraceLogger::OnHeaderFrameStart(
+ SpdyStreamId stream_id) {
+ HTTP2_TRACE_LOG(perspective_, is_enabled_)
+ << "OnHeaderFrameStart:" << FORMAT_ARG(connection_id_)
+ << FORMAT_ARG(stream_id);
+ spdy::SpdyHeadersHandlerInterface* result =
+ wrapped_->OnHeaderFrameStart(stream_id);
+ recording_headers_handler_ =
+ absl::make_unique<spdy::RecordingHeadersHandler>(result);
+ result = recording_headers_handler_.get();
+ return result;
+}
+
+void Http2TraceLogger::OnHeaderFrameEnd(SpdyStreamId stream_id) {
+ HTTP2_TRACE_LOG(perspective_, is_enabled_)
+ << "OnHeaderFrameEnd:" << FORMAT_ARG(connection_id_)
+ << FORMAT_ARG(stream_id);
+ LogReceivedHeaders();
+ wrapped_->OnHeaderFrameEnd(stream_id);
+ recording_headers_handler_ = nullptr;
+}
+
+void Http2TraceLogger::OnRstStream(SpdyStreamId stream_id,
+ SpdyErrorCode error_code) {
+ HTTP2_TRACE_LOG(perspective_, is_enabled_)
+ << "OnRstStream:" << FORMAT_ARG(connection_id_) << FORMAT_ARG(stream_id)
+ << " error_code=" << spdy::ErrorCodeToString(error_code);
+ wrapped_->OnRstStream(stream_id, error_code);
+}
+
+void Http2TraceLogger::OnSettings() { wrapped_->OnSettings(); }
+
+void Http2TraceLogger::OnSetting(SpdySettingsId id, uint32_t value) {
+ HTTP2_TRACE_LOG(perspective_, is_enabled_)
+ << "OnSetting:" << FORMAT_ARG(connection_id_)
+ << " id=" << spdy::SettingsIdToString(id) << FORMAT_ARG(value);
+ wrapped_->OnSetting(id, value);
+}
+
+void Http2TraceLogger::OnSettingsEnd() {
+ HTTP2_TRACE_LOG(perspective_, is_enabled_)
+ << "OnSettingsEnd:" << FORMAT_ARG(connection_id_);
+ wrapped_->OnSettingsEnd();
+}
+
+void Http2TraceLogger::OnSettingsAck() {
+ HTTP2_TRACE_LOG(perspective_, is_enabled_)
+ << "OnSettingsAck:" << FORMAT_ARG(connection_id_);
+ wrapped_->OnSettingsAck();
+}
+
+void Http2TraceLogger::OnPing(SpdyPingId unique_id, bool is_ack) {
+ HTTP2_TRACE_LOG(perspective_, is_enabled_)
+ << "OnPing:" << FORMAT_ARG(connection_id_) << FORMAT_ARG(unique_id)
+ << FORMAT_ARG(is_ack);
+ wrapped_->OnPing(unique_id, is_ack);
+}
+
+void Http2TraceLogger::OnGoAway(SpdyStreamId last_accepted_stream_id,
+ SpdyErrorCode error_code) {
+ HTTP2_TRACE_LOG(perspective_, is_enabled_)
+ << "OnGoAway:" << FORMAT_ARG(connection_id_)
+ << FORMAT_ARG(last_accepted_stream_id)
+ << " error_code=" << spdy::ErrorCodeToString(error_code);
+ wrapped_->OnGoAway(last_accepted_stream_id, error_code);
+}
+
+bool Http2TraceLogger::OnGoAwayFrameData(const char* goaway_data, size_t len) {
+ return wrapped_->OnGoAwayFrameData(goaway_data, len);
+}
+
+void Http2TraceLogger::OnHeaders(SpdyStreamId stream_id, bool has_priority,
+ int weight, SpdyStreamId parent_stream_id,
+ bool exclusive, bool fin, bool end) {
+ HTTP2_TRACE_LOG(perspective_, is_enabled_)
+ << "OnHeaders:" << FORMAT_ARG(connection_id_) << FORMAT_ARG(stream_id)
+ << FORMAT_ARG(has_priority) << FORMAT_INT_ARG(weight)
+ << FORMAT_ARG(parent_stream_id) << FORMAT_ARG(exclusive)
+ << FORMAT_ARG(fin) << FORMAT_ARG(end);
+ wrapped_->OnHeaders(stream_id, has_priority, weight, parent_stream_id,
+ exclusive, fin, end);
+}
+
+void Http2TraceLogger::OnWindowUpdate(SpdyStreamId stream_id,
+ int delta_window_size) {
+ HTTP2_TRACE_LOG(perspective_, is_enabled_)
+ << "OnWindowUpdate:" << FORMAT_ARG(connection_id_)
+ << FORMAT_ARG(stream_id) << FORMAT_ARG(delta_window_size);
+ wrapped_->OnWindowUpdate(stream_id, delta_window_size);
+}
+
+void Http2TraceLogger::OnPushPromise(SpdyStreamId original_stream_id,
+ SpdyStreamId promised_stream_id, bool end) {
+ HTTP2_TRACE_LOG(perspective_, is_enabled_)
+ << "OnPushPromise:" << FORMAT_ARG(connection_id_)
+ << FORMAT_ARG(original_stream_id) << FORMAT_ARG(promised_stream_id)
+ << FORMAT_ARG(end);
+ wrapped_->OnPushPromise(original_stream_id, promised_stream_id, end);
+}
+
+void Http2TraceLogger::OnContinuation(SpdyStreamId stream_id, bool end) {
+ HTTP2_TRACE_LOG(perspective_, is_enabled_)
+ << "OnContinuation:" << FORMAT_ARG(connection_id_)
+ << FORMAT_ARG(stream_id) << FORMAT_ARG(end);
+ wrapped_->OnContinuation(stream_id, end);
+}
+
+void Http2TraceLogger::OnAltSvc(
+ SpdyStreamId stream_id, absl::string_view origin,
+ const SpdyAltSvcWireFormat::AlternativeServiceVector& altsvc_vector) {
+ HTTP2_TRACE_LOG(perspective_, is_enabled_)
+ << "OnAltSvc:" << FORMAT_ARG(connection_id_) << FORMAT_ARG(stream_id)
+ << FORMAT_ARG(origin) << " altsvc_vector="
+ << LogContainer(altsvc_vector, LogAlternativeService());
+ wrapped_->OnAltSvc(stream_id, origin, altsvc_vector);
+}
+
+void Http2TraceLogger::OnPriority(SpdyStreamId stream_id,
+ SpdyStreamId parent_stream_id, int weight,
+ bool exclusive) {
+ HTTP2_TRACE_LOG(perspective_, is_enabled_)
+ << "OnPriority:" << FORMAT_ARG(connection_id_) << FORMAT_ARG(stream_id)
+ << FORMAT_ARG(parent_stream_id) << FORMAT_INT_ARG(weight)
+ << FORMAT_ARG(exclusive);
+ wrapped_->OnPriority(stream_id, parent_stream_id, weight, exclusive);
+}
+
+void Http2TraceLogger::OnPriorityUpdate(
+ SpdyStreamId prioritized_stream_id,
+ absl::string_view priority_field_value) {
+ HTTP2_TRACE_LOG(perspective_, is_enabled_)
+ << "OnPriorityUpdate:" << FORMAT_ARG(connection_id_)
+ << FORMAT_ARG(prioritized_stream_id) << FORMAT_ARG(priority_field_value);
+ wrapped_->OnPriorityUpdate(prioritized_stream_id, priority_field_value);
+}
+
+bool Http2TraceLogger::OnUnknownFrame(SpdyStreamId stream_id,
+ uint8_t frame_type) {
+ HTTP2_TRACE_LOG(perspective_, is_enabled_)
+ << "OnUnknownFrame:" << FORMAT_ARG(connection_id_)
+ << FORMAT_ARG(stream_id) << FORMAT_INT_ARG(frame_type);
+ return wrapped_->OnUnknownFrame(stream_id, frame_type);
+}
+
+void Http2TraceLogger::LogReceivedHeaders() const {
+ if (recording_headers_handler_ == nullptr) {
+ QUICHE_BUG(bug_2794_1) << "Cannot log headers before creating handler.";
+ return;
+ }
+ HTTP2_TRACE_LOG(perspective_, is_enabled_)
+ << "Received headers;" << FORMAT_ARG(connection_id_) << " keys/values:"
+ << recording_headers_handler_->decoded_block().DebugString()
+ << " compressed_bytes="
+ << recording_headers_handler_->compressed_header_bytes()
+ << " uncompressed_bytes="
+ << recording_headers_handler_->uncompressed_header_bytes();
+}
+
+void Http2FrameLogger::VisitRstStream(const SpdyRstStreamIR& rst_stream) {
+ HTTP2_TRACE_LOG(perspective_, is_enabled_)
+ << "Wrote SpdyRstStreamIR:" << FORMAT_ARG(connection_id_)
+ << FORMAT_ATTR(rst_stream, stream_id)
+ << " error_code=" << spdy::ErrorCodeToString(rst_stream.error_code());
+}
+
+void Http2FrameLogger::VisitSettings(const SpdySettingsIR& settings) {
+ HTTP2_TRACE_LOG(perspective_, is_enabled_)
+ << "Wrote SpdySettingsIR:" << FORMAT_ARG(connection_id_)
+ << FORMAT_ATTR(settings, is_ack)
+ << " values=" << LogContainer(settings.values(), LogSettingsEntry());
+}
+
+void Http2FrameLogger::VisitPing(const SpdyPingIR& ping) {
+ HTTP2_TRACE_LOG(perspective_, is_enabled_)
+ << "Wrote SpdyPingIR:" << FORMAT_ARG(connection_id_)
+ << FORMAT_ATTR(ping, id) << FORMAT_ATTR(ping, is_ack);
+}
+
+void Http2FrameLogger::VisitGoAway(const SpdyGoAwayIR& goaway) {
+ HTTP2_TRACE_LOG(perspective_, is_enabled_)
+ << "Wrote SpdyGoAwayIR:" << FORMAT_ARG(connection_id_)
+ << FORMAT_ATTR(goaway, last_good_stream_id)
+ << " error_code=" << spdy::ErrorCodeToString(goaway.error_code())
+ << FORMAT_ATTR(goaway, description);
+}
+
+void Http2FrameLogger::VisitHeaders(const SpdyHeadersIR& headers) {
+ HTTP2_TRACE_LOG(perspective_, is_enabled_)
+ << "Wrote SpdyHeadersIR:" << FORMAT_ARG(connection_id_)
+ << FORMAT_ATTR(headers, stream_id) << FORMAT_ATTR(headers, fin)
+ << FORMAT_ATTR(headers, has_priority) << FORMAT_INT_ATTR(headers, weight)
+ << FORMAT_ATTR(headers, parent_stream_id)
+ << FORMAT_ATTR(headers, exclusive) << FORMAT_ATTR(headers, padded)
+ << FORMAT_ATTR(headers, padding_payload_len)
+ << FORMAT_HEADER_BLOCK(headers);
+}
+
+void Http2FrameLogger::VisitWindowUpdate(
+ const SpdyWindowUpdateIR& window_update) {
+ HTTP2_TRACE_LOG(perspective_, is_enabled_)
+ << "Wrote SpdyWindowUpdateIR:" << FORMAT_ARG(connection_id_)
+ << FORMAT_ATTR(window_update, stream_id)
+ << FORMAT_ATTR(window_update, delta);
+}
+
+void Http2FrameLogger::VisitPushPromise(const SpdyPushPromiseIR& push_promise) {
+ HTTP2_TRACE_LOG(perspective_, is_enabled_)
+ << "Wrote SpdyPushPromiseIR:" << FORMAT_ARG(connection_id_)
+ << FORMAT_ATTR(push_promise, stream_id) << FORMAT_ATTR(push_promise, fin)
+ << FORMAT_ATTR(push_promise, promised_stream_id)
+ << FORMAT_ATTR(push_promise, padded)
+ << FORMAT_ATTR(push_promise, padding_payload_len)
+ << FORMAT_HEADER_BLOCK(push_promise);
+}
+
+void Http2FrameLogger::VisitContinuation(
+ const SpdyContinuationIR& continuation) {
+ HTTP2_TRACE_LOG(perspective_, is_enabled_)
+ << "Wrote SpdyContinuationIR:" << FORMAT_ARG(connection_id_)
+ << FORMAT_ATTR(continuation, stream_id)
+ << FORMAT_ATTR(continuation, end_headers);
+}
+
+void Http2FrameLogger::VisitAltSvc(const SpdyAltSvcIR& altsvc) {
+ HTTP2_TRACE_LOG(perspective_, is_enabled_)
+ << "Wrote SpdyAltSvcIR:" << FORMAT_ARG(connection_id_)
+ << FORMAT_ATTR(altsvc, stream_id) << FORMAT_ATTR(altsvc, origin)
+ << " altsvc_vector="
+ << LogContainer(altsvc.altsvc_vector(), LogAlternativeService());
+}
+
+void Http2FrameLogger::VisitPriority(const SpdyPriorityIR& priority) {
+ HTTP2_TRACE_LOG(perspective_, is_enabled_)
+ << "Wrote SpdyPriorityIR:" << FORMAT_ARG(connection_id_)
+ << FORMAT_ATTR(priority, stream_id)
+ << FORMAT_ATTR(priority, parent_stream_id)
+ << FORMAT_INT_ATTR(priority, weight) << FORMAT_ATTR(priority, exclusive);
+}
+
+void Http2FrameLogger::VisitData(const SpdyDataIR& data) {
+ HTTP2_TRACE_LOG(perspective_, is_enabled_)
+ << "Wrote SpdyDataIR:" << FORMAT_ARG(connection_id_)
+ << FORMAT_ATTR(data, stream_id) << FORMAT_ATTR(data, fin)
+ << " data_len=" << data.data_len() << FORMAT_ATTR(data, padded)
+ << FORMAT_ATTR(data, padding_payload_len);
+}
+
+void Http2FrameLogger::VisitPriorityUpdate(
+ const spdy::SpdyPriorityUpdateIR& priority_update) {
+ HTTP2_TRACE_LOG(perspective_, is_enabled_)
+ << "Wrote SpdyPriorityUpdateIR:" << FORMAT_ARG(connection_id_)
+ << FORMAT_ATTR(priority_update, stream_id)
+ << FORMAT_ATTR(priority_update, prioritized_stream_id)
+ << FORMAT_ATTR(priority_update, priority_field_value);
+}
+
+void Http2FrameLogger::VisitAcceptCh(
+ const spdy::SpdyAcceptChIR& /*accept_ch*/) {
+ QUICHE_BUG(bug_2794_2)
+ << "Sending ACCEPT_CH frames is currently unimplemented.";
+}
+
+void Http2FrameLogger::VisitUnknown(const SpdyUnknownIR& ir) {
+ HTTP2_TRACE_LOG(perspective_, is_enabled_)
+ << "Wrote SpdyUnknownIR:" << FORMAT_ARG(connection_id_)
+ << FORMAT_ATTR(ir, stream_id) << FORMAT_INT_ATTR(ir, type)
+ << FORMAT_INT_ATTR(ir, flags) << FORMAT_ATTR(ir, length);
+}
+
+} // namespace http2
diff --git a/chromium/net/third_party/quiche/src/http2/core/http2_trace_logging.h b/chromium/net/third_party/quiche/src/http2/core/http2_trace_logging.h
new file mode 100644
index 00000000000..e1185bf0e58
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/http2/core/http2_trace_logging.h
@@ -0,0 +1,140 @@
+// Classes and utilities for supporting HTTP/2 trace logging, which logs
+// information about all control and data frames sent and received over
+// HTTP/2 connections.
+
+#ifndef QUICHE_HTTP2_CORE_HTTP2_TRACE_LOGGING_H_
+#define QUICHE_HTTP2_CORE_HTTP2_TRACE_LOGGING_H_
+
+#include <cstdint>
+
+#include "absl/strings/string_view.h"
+#include "common/platform/api/quiche_export.h"
+#include "common/platform/api/quiche_logging.h"
+#include "spdy/core/http2_frame_decoder_adapter.h"
+#include "spdy/core/recording_headers_handler.h"
+#include "spdy/core/spdy_headers_handler_interface.h"
+#include "spdy/core/spdy_protocol.h"
+
+// Logging macro to use for all HTTP/2 trace logging. Iff trace logging is
+// enabled, logs at level INFO with a common prefix prepended (to facilitate
+// post-hoc filtering of trace logging output).
+#define HTTP2_TRACE_LOG(perspective, is_enabled) \
+ QUICHE_LOG_IF(INFO, is_enabled()) << "[HTTP2_TRACE " << perspective << "] "
+
+namespace http2 {
+
+// Intercepts deframing events to provide detailed logs. Intended to be used for
+// manual debugging.
+//
+// Note any new methods in SpdyFramerVisitorInterface MUST be overridden here to
+// properly forward the event. This could be ensured by making every event in
+// SpdyFramerVisitorInterface a pure virtual.
+class QUICHE_EXPORT_PRIVATE Http2TraceLogger
+ : public spdy::SpdyFramerVisitorInterface {
+ public:
+ typedef spdy::SpdyAltSvcWireFormat SpdyAltSvcWireFormat;
+ typedef spdy::SpdyErrorCode SpdyErrorCode;
+ typedef spdy::SpdyFramerVisitorInterface SpdyFramerVisitorInterface;
+ typedef spdy::SpdyPingId SpdyPingId;
+ typedef spdy::SpdyPriority SpdyPriority;
+ typedef spdy::SpdySettingsId SpdySettingsId;
+ typedef spdy::SpdyStreamId SpdyStreamId;
+
+ Http2TraceLogger(SpdyFramerVisitorInterface* parent,
+ absl::string_view perspective,
+ std::function<bool()> is_enabled, const void* connection_id);
+ ~Http2TraceLogger() override;
+
+ Http2TraceLogger(const Http2TraceLogger&) = delete;
+ Http2TraceLogger& operator=(const Http2TraceLogger&) = delete;
+
+ void OnError(http2::Http2DecoderAdapter::SpdyFramerError error,
+ std::string detailed_error) override;
+ void OnCommonHeader(SpdyStreamId stream_id, size_t length, uint8_t type,
+ uint8_t flags) override;
+ spdy::SpdyHeadersHandlerInterface* OnHeaderFrameStart(
+ SpdyStreamId stream_id) override;
+ void OnHeaderFrameEnd(SpdyStreamId stream_id) override;
+ void OnDataFrameHeader(SpdyStreamId stream_id, size_t length,
+ bool fin) override;
+ void OnStreamFrameData(SpdyStreamId stream_id, const char* data,
+ size_t len) override;
+ void OnStreamEnd(SpdyStreamId stream_id) override;
+ void OnStreamPadLength(SpdyStreamId stream_id, size_t value) override;
+ void OnStreamPadding(SpdyStreamId stream_id, size_t len) override;
+ void OnRstStream(SpdyStreamId stream_id, SpdyErrorCode error_code) override;
+ void OnSetting(spdy::SpdySettingsId id, uint32_t value) override;
+ void OnPing(SpdyPingId unique_id, bool is_ack) override;
+ void OnSettings() override;
+ void OnSettingsEnd() override;
+ void OnSettingsAck() override;
+ void OnGoAway(SpdyStreamId last_accepted_stream_id,
+ SpdyErrorCode error_code) override;
+ bool OnGoAwayFrameData(const char* goaway_data, size_t len) override;
+ void OnHeaders(SpdyStreamId stream_id, bool has_priority, int weight,
+ SpdyStreamId parent_stream_id, bool exclusive, bool fin,
+ bool end) override;
+ void OnWindowUpdate(SpdyStreamId stream_id, int delta_window_size) override;
+ void OnPushPromise(SpdyStreamId stream_id, SpdyStreamId promised_stream_id,
+ bool end) override;
+ void OnContinuation(SpdyStreamId stream_id, bool end) override;
+ void OnAltSvc(SpdyStreamId stream_id, absl::string_view origin,
+ const SpdyAltSvcWireFormat::AlternativeServiceVector&
+ altsvc_vector) override;
+ void OnPriority(SpdyStreamId stream_id, SpdyStreamId parent_stream_id,
+ int weight, bool exclusive) override;
+ void OnPriorityUpdate(SpdyStreamId prioritized_stream_id,
+ absl::string_view priority_field_value) override;
+ bool OnUnknownFrame(SpdyStreamId stream_id, uint8_t frame_type) override;
+
+ private:
+ void LogReceivedHeaders() const;
+
+ std::unique_ptr<spdy::RecordingHeadersHandler> recording_headers_handler_;
+
+ SpdyFramerVisitorInterface* wrapped_;
+ const absl::string_view perspective_;
+ const std::function<bool()> is_enabled_;
+ const void* connection_id_;
+};
+
+// Visitor to log control frames that have been written.
+class QUICHE_EXPORT_PRIVATE Http2FrameLogger : public spdy::SpdyFrameVisitor {
+ public:
+ // This class will preface all of its log messages with the value of
+ // |connection_id| in hexadecimal.
+ Http2FrameLogger(absl::string_view perspective,
+ std::function<bool()> is_enabled, const void* connection_id)
+ : perspective_(perspective),
+ is_enabled_(std::move(is_enabled)),
+ connection_id_(connection_id) {}
+
+ Http2FrameLogger(const Http2FrameLogger&) = delete;
+ Http2FrameLogger& operator=(const Http2FrameLogger&) = delete;
+
+ void VisitRstStream(const spdy::SpdyRstStreamIR& rst_stream) override;
+ void VisitSettings(const spdy::SpdySettingsIR& settings) override;
+ void VisitPing(const spdy::SpdyPingIR& ping) override;
+ void VisitGoAway(const spdy::SpdyGoAwayIR& goaway) override;
+ void VisitHeaders(const spdy::SpdyHeadersIR& headers) override;
+ void VisitWindowUpdate(
+ const spdy::SpdyWindowUpdateIR& window_update) override;
+ void VisitPushPromise(const spdy::SpdyPushPromiseIR& push_promise) override;
+ void VisitContinuation(const spdy::SpdyContinuationIR& continuation) override;
+ void VisitAltSvc(const spdy::SpdyAltSvcIR& altsvc) override;
+ void VisitPriority(const spdy::SpdyPriorityIR& priority) override;
+ void VisitData(const spdy::SpdyDataIR& data) override;
+ void VisitPriorityUpdate(
+ const spdy::SpdyPriorityUpdateIR& priority_update) override;
+ void VisitAcceptCh(const spdy::SpdyAcceptChIR& accept_ch) override;
+ void VisitUnknown(const spdy::SpdyUnknownIR& ir) override;
+
+ private:
+ const absl::string_view perspective_;
+ const std::function<bool()> is_enabled_;
+ const void* connection_id_;
+};
+
+} // namespace http2
+
+#endif // QUICHE_HTTP2_CORE_HTTP2_TRACE_LOGGING_H_
diff --git a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder.h b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder.h
index 92177070acc..3ac581926a1 100644
--- a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder.h
+++ b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder.h
@@ -69,6 +69,11 @@ class QUICHE_EXPORT_PRIVATE HpackDecoder {
// decoding the SETTINGS ACK, and before the next HPACK block is decoded.
void ApplyHeaderTableSizeSetting(uint32_t max_header_table_size);
+ // Returns the most recently applied value of SETTINGS_HEADER_TABLE_SIZE.
+ size_t GetCurrentHeaderTableSizeSetting() const {
+ return decoder_state_.GetCurrentHeaderTableSizeSetting();
+ }
+
// Prepares the decoder for decoding a new HPACK block, and announces this to
// its listener. Returns true if OK to continue with decoding, false if an
// error has been detected, which for StartDecodingBlock means the error was
diff --git a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_state.h b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_state.h
index 5dcdc40bf99..3040c181471 100644
--- a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_state.h
+++ b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_state.h
@@ -57,6 +57,11 @@ class QUICHE_EXPORT_PRIVATE HpackDecoderState : public HpackWholeEntryListener {
// decoding the SETTINGS ACK, and before the next HPACK block is decoded.
void ApplyHeaderTableSizeSetting(uint32_t max_header_table_size);
+ // Returns the most recently applied value of SETTINGS_HEADER_TABLE_SIZE.
+ size_t GetCurrentHeaderTableSizeSetting() const {
+ return final_header_table_size_;
+ }
+
// OnHeaderBlockStart notifies this object that we're starting to decode the
// HPACK payload of a HEADERS or PUSH_PROMISE frame.
void OnHeaderBlockStart();
diff --git a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_state_test.cc b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_state_test.cc
index 698c655c961..7e36a178a74 100644
--- a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_state_test.cc
+++ b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_state_test.cc
@@ -427,8 +427,10 @@ TEST_F(HpackDecoderStateTest, OptionalTableSizeChanges) {
// Confirm that required size updates are indeed required before headers.
TEST_F(HpackDecoderStateTest, RequiredTableSizeChangeBeforeHeader) {
+ EXPECT_EQ(4096u, decoder_state_.GetCurrentHeaderTableSizeSetting());
decoder_state_.ApplyHeaderTableSizeSetting(1024);
decoder_state_.ApplyHeaderTableSizeSetting(2048);
+ EXPECT_EQ(2048u, decoder_state_.GetCurrentHeaderTableSizeSetting());
// First provide the required update, and an allowed second update.
SendStartAndVerifyCallback();
@@ -442,6 +444,7 @@ TEST_F(HpackDecoderStateTest, RequiredTableSizeChangeBeforeHeader) {
// Another HPACK block, but this time missing the required size update.
decoder_state_.ApplyHeaderTableSizeSetting(1024);
+ EXPECT_EQ(1024u, decoder_state_.GetCurrentHeaderTableSizeSetting());
SendStartAndVerifyCallback();
EXPECT_CALL(listener_,
OnHeaderErrorDetected(Eq("Missing dynamic table size update")));
diff --git a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_test.cc b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_test.cc
index ce44ccb04b5..c160bfe30bf 100644
--- a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_test.cc
+++ b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_test.cc
@@ -961,11 +961,13 @@ TEST_P(HpackDecoderTest, ProcessesOptionalTableSizeUpdates) {
// Confirm that the table size can be changed when required, but at most twice.
TEST_P(HpackDecoderTest, ProcessesRequiredTableSizeUpdate) {
+ EXPECT_EQ(4096u, decoder_.GetCurrentHeaderTableSizeSetting());
// One update required, two allowed, one provided, followed by a header.
decoder_.ApplyHeaderTableSizeSetting(1024);
decoder_.ApplyHeaderTableSizeSetting(2048);
EXPECT_EQ(Http2SettingsInfo::DefaultHeaderTableSize(),
header_table_size_limit());
+ EXPECT_EQ(2048u, decoder_.GetCurrentHeaderTableSizeSetting());
{
HpackBlockBuilder hbb;
hbb.AppendDynamicTableSizeUpdate(1024);
@@ -979,6 +981,7 @@ TEST_P(HpackDecoderTest, ProcessesRequiredTableSizeUpdate) {
// One update required, two allowed, two provided, followed by a header.
decoder_.ApplyHeaderTableSizeSetting(1000);
decoder_.ApplyHeaderTableSizeSetting(1500);
+ EXPECT_EQ(1500u, decoder_.GetCurrentHeaderTableSizeSetting());
{
HpackBlockBuilder hbb;
hbb.AppendDynamicTableSizeUpdate(500);
@@ -994,6 +997,7 @@ TEST_P(HpackDecoderTest, ProcessesRequiredTableSizeUpdate) {
// The third update is rejected, so the final size is 1000, not 500.
decoder_.ApplyHeaderTableSizeSetting(500);
decoder_.ApplyHeaderTableSizeSetting(1000);
+ EXPECT_EQ(1000u, decoder_.GetCurrentHeaderTableSizeSetting());
{
HpackBlockBuilder hbb;
hbb.AppendDynamicTableSizeUpdate(200);
@@ -1011,6 +1015,7 @@ TEST_P(HpackDecoderTest, ProcessesRequiredTableSizeUpdate) {
EXPECT_EQ(0u, current_header_table_size());
EXPECT_TRUE(header_entries_.empty());
}
+ EXPECT_EQ(1000u, decoder_.GetCurrentHeaderTableSizeSetting());
// Now that an error has been detected, StartDecodingBlock should return
// false.
EXPECT_FALSE(decoder_.StartDecodingBlock());
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 657cad1a46a..240e9ddf754 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
@@ -23,21 +23,72 @@ std::ostream& operator<<(std::ostream& os, const SendTimeState& s) {
return os;
}
-QuicByteCount MaxAckHeightTracker::Update(QuicBandwidth bandwidth_estimate,
- QuicRoundTripCount round_trip_count,
- QuicTime ack_time,
- QuicByteCount bytes_acked) {
- if (aggregation_epoch_start_time_ == QuicTime::Zero()) {
+QuicByteCount MaxAckHeightTracker::Update(
+ QuicBandwidth bandwidth_estimate, bool is_new_max_bandwidth,
+ QuicRoundTripCount round_trip_count,
+ QuicPacketNumber last_sent_packet_number,
+ QuicPacketNumber last_acked_packet_number, QuicTime ack_time,
+ QuicByteCount bytes_acked) {
+ bool force_new_epoch = false;
+
+ if (reduce_extra_acked_on_bandwidth_increase_ && is_new_max_bandwidth) {
+ // Save and clear existing entries.
+ ExtraAckedEvent best = max_ack_height_filter_.GetBest();
+ ExtraAckedEvent second_best = max_ack_height_filter_.GetSecondBest();
+ ExtraAckedEvent third_best = max_ack_height_filter_.GetThirdBest();
+ max_ack_height_filter_.Clear();
+
+ // Reinsert the heights into the filter after recalculating.
+ QuicByteCount expected_bytes_acked = bandwidth_estimate * best.time_delta;
+ if (expected_bytes_acked < best.bytes_acked) {
+ best.extra_acked = best.bytes_acked - expected_bytes_acked;
+ max_ack_height_filter_.Update(best, best.round);
+ }
+ expected_bytes_acked = bandwidth_estimate * second_best.time_delta;
+ if (expected_bytes_acked < second_best.bytes_acked) {
+ QUICHE_DCHECK_LE(best.round, second_best.round);
+ second_best.extra_acked = second_best.bytes_acked - expected_bytes_acked;
+ max_ack_height_filter_.Update(second_best, second_best.round);
+ }
+ expected_bytes_acked = bandwidth_estimate * third_best.time_delta;
+ if (expected_bytes_acked < third_best.bytes_acked) {
+ QUICHE_DCHECK_LE(second_best.round, third_best.round);
+ third_best.extra_acked = third_best.bytes_acked - expected_bytes_acked;
+ max_ack_height_filter_.Update(third_best, third_best.round);
+ }
+ }
+
+ // If any packet sent after the start of the epoch has been acked, start a new
+ // epoch.
+ if (start_new_aggregation_epoch_after_full_round_ &&
+ last_sent_packet_number_before_epoch_.IsInitialized() &&
+ last_acked_packet_number.IsInitialized() &&
+ last_acked_packet_number > last_sent_packet_number_before_epoch_) {
+ QUIC_RELOADABLE_FLAG_COUNT(
+ quic_bbr_start_new_aggregation_epoch_after_a_full_round);
+ QUIC_DVLOG(3) << "Force starting a new aggregation epoch. "
+ "last_sent_packet_number_before_epoch_:"
+ << last_sent_packet_number_before_epoch_
+ << ", last_acked_packet_number:" << last_acked_packet_number;
+ if (reduce_extra_acked_on_bandwidth_increase_) {
+ QUIC_BUG(quic_bwsampler_46)
+ << "A full round of aggregation should never "
+ << "pass with startup_include_extra_acked(B204) enabled.";
+ }
+ force_new_epoch = true;
+ }
+ if (aggregation_epoch_start_time_ == QuicTime::Zero() || force_new_epoch) {
aggregation_epoch_bytes_ = bytes_acked;
aggregation_epoch_start_time_ = ack_time;
+ last_sent_packet_number_before_epoch_ = last_sent_packet_number;
++num_ack_aggregation_epochs_;
return 0;
}
// Compute how many bytes are expected to be delivered, assuming max bandwidth
// is correct.
- QuicByteCount expected_bytes_acked =
- bandwidth_estimate * (ack_time - aggregation_epoch_start_time_);
+ QuicTime::Delta aggregation_delta = ack_time - aggregation_epoch_start_time_;
+ QuicByteCount expected_bytes_acked = bandwidth_estimate * aggregation_delta;
// Reset the current aggregation epoch as soon as the ack arrival rate is less
// than or equal to the max bandwidth.
if (aggregation_epoch_bytes_ <=
@@ -50,13 +101,13 @@ QuicByteCount MaxAckHeightTracker::Update(QuicBandwidth bandwidth_estimate,
<< ack_aggregation_bandwidth_threshold_
<< ", expected_bytes_acked:" << expected_bytes_acked
<< ", bandwidth_estimate:" << bandwidth_estimate
- << ", aggregation_duration:"
- << (ack_time - aggregation_epoch_start_time_)
+ << ", aggregation_duration:" << aggregation_delta
<< ", new_aggregation_epoch:" << ack_time
<< ", new_aggregation_bytes_acked:" << bytes_acked;
// Reset to start measuring a new aggregation epoch.
aggregation_epoch_bytes_ = bytes_acked;
aggregation_epoch_start_time_ = ack_time;
+ last_sent_packet_number_before_epoch_ = last_sent_packet_number;
++num_ack_aggregation_epochs_;
return 0;
}
@@ -67,13 +118,17 @@ QuicByteCount MaxAckHeightTracker::Update(QuicBandwidth bandwidth_estimate,
QuicByteCount extra_bytes_acked =
aggregation_epoch_bytes_ - expected_bytes_acked;
QUIC_DVLOG(3) << "Updating MaxAckHeight. ack_time:" << ack_time
- << ", round trip count:" << round_trip_count
+ << ", last sent packet:" << last_sent_packet_number
<< ", bandwidth_estimate:" << bandwidth_estimate
<< ", bytes_acked:" << bytes_acked
<< ", expected_bytes_acked:" << expected_bytes_acked
<< ", aggregation_epoch_bytes_:" << aggregation_epoch_bytes_
<< ", extra_bytes_acked:" << extra_bytes_acked;
- max_ack_height_filter_.Update(extra_bytes_acked, round_trip_count);
+ ExtraAckedEvent new_event;
+ new_event.extra_acked = extra_bytes_acked;
+ new_event.bytes_acked = aggregation_epoch_bytes_;
+ new_event.time_delta = aggregation_delta;
+ max_ack_height_filter_.Update(new_event, round_trip_count);
return extra_bytes_acked;
}
@@ -93,7 +148,8 @@ BandwidthSampler::BandwidthSampler(
unacked_packet_map_(unacked_packet_map),
max_ack_height_tracker_(max_height_tracker_window_length),
total_bytes_acked_after_last_ack_event_(0),
- overestimate_avoidance_(false) {}
+ overestimate_avoidance_(false),
+ limit_max_ack_height_tracker_by_send_rate_(false) {}
BandwidthSampler::BandwidthSampler(const BandwidthSampler& other)
: total_bytes_sent_(other.total_bytes_sent_),
@@ -105,6 +161,7 @@ BandwidthSampler::BandwidthSampler(const BandwidthSampler& other)
last_acked_packet_sent_time_(other.last_acked_packet_sent_time_),
last_acked_packet_ack_time_(other.last_acked_packet_ack_time_),
last_sent_packet_(other.last_sent_packet_),
+ last_acked_packet_(other.last_acked_packet_),
is_app_limited_(other.is_app_limited_),
end_of_app_limited_phase_(other.end_of_app_limited_phase_),
connection_state_map_(other.connection_state_map_),
@@ -115,7 +172,9 @@ BandwidthSampler::BandwidthSampler(const BandwidthSampler& other)
max_ack_height_tracker_(other.max_ack_height_tracker_),
total_bytes_acked_after_last_ack_event_(
other.total_bytes_acked_after_last_ack_event_),
- overestimate_avoidance_(other.overestimate_avoidance_) {}
+ overestimate_avoidance_(other.overestimate_avoidance_),
+ limit_max_ack_height_tracker_by_send_rate_(
+ other.limit_max_ack_height_tracker_by_send_rate_) {}
void BandwidthSampler::EnableOverestimateAvoidance() {
if (overestimate_avoidance_) {
@@ -244,6 +303,7 @@ BandwidthSampler::OnCongestionEvent(QuicTime ack_time,
}
SendTimeState last_acked_packet_send_state;
+ QuicBandwidth max_send_rate = QuicBandwidth::Zero();
for (const auto& packet : acked_packets) {
BandwidthSample sample =
OnPacketAcknowledged(ack_time, packet.packet_number);
@@ -260,6 +320,9 @@ BandwidthSampler::OnCongestionEvent(QuicTime ack_time,
event_sample.sample_max_bandwidth = sample.bandwidth;
event_sample.sample_is_app_limited = sample.state_at_send.is_app_limited;
}
+ if (!sample.send_rate.IsInfinite()) {
+ max_send_rate = std::max(max_send_rate, sample.send_rate);
+ }
const QuicByteCount inflight_sample =
total_bytes_acked() - last_acked_packet_send_state.total_bytes_acked;
if (inflight_sample > event_sample.sample_max_inflight) {
@@ -282,15 +345,21 @@ BandwidthSampler::OnCongestionEvent(QuicTime ack_time,
: last_acked_packet_send_state;
}
+ bool is_new_max_bandwidth = event_sample.sample_max_bandwidth > max_bandwidth;
max_bandwidth = std::max(max_bandwidth, event_sample.sample_max_bandwidth);
- event_sample.extra_acked = OnAckEventEnd(
- std::min(est_bandwidth_upper_bound, max_bandwidth), round_trip_count);
+ if (limit_max_ack_height_tracker_by_send_rate_) {
+ max_bandwidth = std::max(max_bandwidth, max_send_rate);
+ }
+ // TODO(ianswett): Why is the min being passed in here?
+ event_sample.extra_acked =
+ OnAckEventEnd(std::min(est_bandwidth_upper_bound, max_bandwidth),
+ is_new_max_bandwidth, round_trip_count);
return event_sample;
}
QuicByteCount BandwidthSampler::OnAckEventEnd(
- QuicBandwidth bandwidth_estimate,
+ QuicBandwidth bandwidth_estimate, bool is_new_max_bandwidth,
QuicRoundTripCount round_trip_count) {
const QuicByteCount newly_acked_bytes =
total_bytes_acked_ - total_bytes_acked_after_last_ack_event_;
@@ -299,9 +368,9 @@ QuicByteCount BandwidthSampler::OnAckEventEnd(
return 0;
}
total_bytes_acked_after_last_ack_event_ = total_bytes_acked_;
-
QuicByteCount extra_acked = max_ack_height_tracker_.Update(
- bandwidth_estimate, round_trip_count, last_acked_packet_ack_time_,
+ bandwidth_estimate, is_new_max_bandwidth, round_trip_count,
+ last_sent_packet_, last_acked_packet_, last_acked_packet_ack_time_,
newly_acked_bytes);
// If |extra_acked| is zero, i.e. this ack event marks the start of a new ack
// aggregation epoch, save LessRecentPoint, which is the last ack point of the
@@ -316,6 +385,7 @@ QuicByteCount BandwidthSampler::OnAckEventEnd(
BandwidthSample BandwidthSampler::OnPacketAcknowledged(
QuicTime ack_time,
QuicPacketNumber packet_number) {
+ last_acked_packet_ = packet_number;
ConnectionStateOnSentPacket* sent_packet_pointer =
connection_state_map_.GetEntry(packet_number);
if (sent_packet_pointer == nullptr) {
@@ -412,6 +482,7 @@ BandwidthSample BandwidthSampler::OnPacketAcknowledgedInner(
// means that the RTT measurements here can be artificially high, especially
// on low bandwidth connections.
sample.rtt = ack_time - sent_packet.sent_time;
+ sample.send_rate = send_rate;
SentPacketToSendTimeState(sent_packet, &sample.state_at_send);
if (sample.bandwidth.IsZero()) {
diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.h
index 2d5924b06e1..814571746c0 100644
--- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.h
+++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.h
@@ -9,6 +9,7 @@
#include "quic/core/congestion_control/windowed_filter.h"
#include "quic/core/packet_number_indexed_queue.h"
#include "quic/core/quic_bandwidth.h"
+#include "quic/core/quic_packet_number.h"
#include "quic/core/quic_packets.h"
#include "quic/core/quic_time.h"
#include "quic/core/quic_types.h"
@@ -77,20 +78,39 @@ struct QUIC_EXPORT_PRIVATE SendTimeState {
QuicByteCount bytes_in_flight;
};
+struct QUIC_NO_EXPORT ExtraAckedEvent {
+ // The excess bytes acknowlwedged in the time delta for this event.
+ QuicByteCount extra_acked = 0;
+
+ // The bytes acknowledged and time delta from the event.
+ QuicByteCount bytes_acked = 0;
+ QuicTime::Delta time_delta = QuicTime::Delta::Zero();
+ // The round trip of the event.
+ QuicRoundTripCount round = 0;
+
+ inline bool operator>=(const ExtraAckedEvent& other) const {
+ return extra_acked >= other.extra_acked;
+ }
+ inline bool operator==(const ExtraAckedEvent& other) const {
+ return extra_acked == other.extra_acked;
+ }
+};
+
struct QUIC_EXPORT_PRIVATE BandwidthSample {
// The bandwidth at that particular sample. Zero if no valid bandwidth sample
// is available.
- QuicBandwidth bandwidth;
+ QuicBandwidth bandwidth = QuicBandwidth::Zero();
// The RTT measurement at this particular sample. Zero if no RTT sample is
// available. Does not correct for delayed ack time.
- QuicTime::Delta rtt;
+ QuicTime::Delta rtt = QuicTime::Delta::Zero();
+
+ // |send_rate| is computed from the current packet being acked('P') and an
+ // earlier packet that is acked before P was sent.
+ QuicBandwidth send_rate = QuicBandwidth::Infinite();
// States captured when the packet was sent.
SendTimeState state_at_send;
-
- BandwidthSample()
- : bandwidth(QuicBandwidth::Zero()), rtt(QuicTime::Delta::Zero()) {}
};
// MaxAckHeightTracker is part of the BandwidthSampler. It is called after every
@@ -98,27 +118,42 @@ struct QUIC_EXPORT_PRIVATE BandwidthSample {
class QUIC_EXPORT_PRIVATE MaxAckHeightTracker {
public:
explicit MaxAckHeightTracker(QuicRoundTripCount initial_filter_window)
- : max_ack_height_filter_(initial_filter_window, 0, 0) {}
+ : max_ack_height_filter_(initial_filter_window, ExtraAckedEvent(), 0) {}
- QuicByteCount Get() const { return max_ack_height_filter_.GetBest(); }
+ QuicByteCount Get() const {
+ return max_ack_height_filter_.GetBest().extra_acked;
+ }
QuicByteCount Update(QuicBandwidth bandwidth_estimate,
+ bool is_new_max_bandwidth,
QuicRoundTripCount round_trip_count,
- QuicTime ack_time,
- QuicByteCount bytes_acked);
+ QuicPacketNumber last_sent_packet_number,
+ QuicPacketNumber last_acked_packet_number,
+ QuicTime ack_time, QuicByteCount bytes_acked);
void SetFilterWindowLength(QuicRoundTripCount length) {
max_ack_height_filter_.SetWindowLength(length);
}
void Reset(QuicByteCount new_height, QuicRoundTripCount new_time) {
- max_ack_height_filter_.Reset(new_height, new_time);
+ ExtraAckedEvent new_event;
+ new_event.extra_acked = new_height;
+ new_event.round = new_time;
+ max_ack_height_filter_.Reset(new_event, new_time);
}
void SetAckAggregationBandwidthThreshold(double threshold) {
ack_aggregation_bandwidth_threshold_ = threshold;
}
+ void SetStartNewAggregationEpochAfterFullRound(bool value) {
+ start_new_aggregation_epoch_after_full_round_ = value;
+ }
+
+ void SetReduceExtraAckedOnBandwidthIncrease(bool value) {
+ reduce_extra_acked_on_bandwidth_increase_ = value;
+ }
+
double ack_aggregation_bandwidth_threshold() const {
return ack_aggregation_bandwidth_threshold_;
}
@@ -130,20 +165,23 @@ class QUIC_EXPORT_PRIVATE MaxAckHeightTracker {
private:
// Tracks the maximum number of bytes acked faster than the estimated
// bandwidth.
- using MaxAckHeightFilter = WindowedFilter<QuicByteCount,
- MaxFilter<QuicByteCount>,
- QuicRoundTripCount,
- QuicRoundTripCount>;
+ using MaxAckHeightFilter =
+ WindowedFilter<ExtraAckedEvent, MaxFilter<ExtraAckedEvent>,
+ QuicRoundTripCount, QuicRoundTripCount>;
MaxAckHeightFilter max_ack_height_filter_;
// The time this aggregation started and the number of bytes acked during it.
QuicTime aggregation_epoch_start_time_ = QuicTime::Zero();
QuicByteCount aggregation_epoch_bytes_ = 0;
+ // The last sent packet number before the current aggregation epoch started.
+ QuicPacketNumber last_sent_packet_number_before_epoch_;
// The number of ack aggregation epochs ever started, including the ongoing
// one. Stats only.
uint64_t num_ack_aggregation_epochs_ = 0;
double ack_aggregation_bandwidth_threshold_ =
GetQuicFlag(FLAGS_quic_ack_aggregation_bandwidth_threshold);
+ bool start_new_aggregation_epoch_after_full_round_ = false;
+ bool reduce_extra_acked_on_bandwidth_increase_ = false;
};
// An interface common to any class that can provide bandwidth samples from the
@@ -325,6 +363,7 @@ class QUIC_EXPORT_PRIVATE BandwidthSampler : public BandwidthSamplerInterface {
QuicBandwidth est_bandwidth_upper_bound,
QuicRoundTripCount round_trip_count) override;
QuicByteCount OnAckEventEnd(QuicBandwidth bandwidth_estimate,
+ bool is_new_max_bandwidth,
QuicRoundTripCount round_trip_count);
void OnAppLimited() override;
@@ -355,6 +394,18 @@ class QUIC_EXPORT_PRIVATE BandwidthSampler : public BandwidthSamplerInterface {
max_ack_height_tracker_.Reset(new_height, new_time);
}
+ void SetStartNewAggregationEpochAfterFullRound(bool value) {
+ max_ack_height_tracker_.SetStartNewAggregationEpochAfterFullRound(value);
+ }
+
+ void SetLimitMaxAckHeightTrackerBySendRate(bool value) {
+ limit_max_ack_height_tracker_by_send_rate_ = value;
+ }
+
+ void SetReduceExtraAckedOnBandwidthIncrease(bool value) {
+ max_ack_height_tracker_.SetReduceExtraAckedOnBandwidthIncrease(value);
+ }
+
// AckPoint represents a point on the ack line.
struct QUIC_NO_EXPORT AckPoint {
QuicTime ack_time = QuicTime::Zero();
@@ -528,6 +579,9 @@ class QUIC_EXPORT_PRIVATE BandwidthSampler : public BandwidthSamplerInterface {
// The most recently sent packet.
QuicPacketNumber last_sent_packet_;
+ // The most recently acked packet.
+ QuicPacketNumber last_acked_packet_;
+
// Indicates whether the bandwidth sampler is currently in an app-limited
// phase.
bool is_app_limited_;
@@ -563,6 +617,9 @@ class QUIC_EXPORT_PRIVATE BandwidthSampler : public BandwidthSamplerInterface {
// True if connection option 'BSAO' is set.
bool overestimate_avoidance_;
+
+ // True if connection option 'BBRB' is set.
+ bool limit_max_ack_height_tracker_by_send_rate_;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler_test.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler_test.cc
index 67dad1cb675..0e0dac42d91 100644
--- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler_test.cc
@@ -685,22 +685,23 @@ TEST_P(BandwidthSamplerTest, AckHeightRespectBandwidthEstimateUpperBound) {
QuicBandwidth::FromBytesAndTimeDelta(kRegularPacketSize,
time_between_packets);
- // Send and ack packet 1.
+ // Send packets 1 to 4 and ack packet 1.
SendPacket(1);
clock_.AdvanceTime(time_between_packets);
+ SendPacket(2);
+ SendPacket(3);
+ SendPacket(4);
BandwidthSampler::CongestionEventSample sample = OnCongestionEvent({1}, {});
EXPECT_EQ(first_packet_sending_rate, sample.sample_max_bandwidth);
EXPECT_EQ(first_packet_sending_rate, max_bandwidth_);
- // Send and ack packet 2, 3 and 4.
+ // Ack packet 2, 3 and 4, all of which uses S(1) to calculate ack rate since
+ // there were no acks at the time they were sent.
round_trip_count_++;
est_bandwidth_upper_bound_ = first_packet_sending_rate * 0.3;
- SendPacket(2);
- SendPacket(3);
- SendPacket(4);
clock_.AdvanceTime(time_between_packets);
sample = OnCongestionEvent({2, 3, 4}, {});
- EXPECT_EQ(first_packet_sending_rate * 3, sample.sample_max_bandwidth);
+ EXPECT_EQ(first_packet_sending_rate * 2, sample.sample_max_bandwidth);
EXPECT_EQ(max_bandwidth_, sample.sample_max_bandwidth);
EXPECT_LT(2 * kRegularPacketSize, sample.extra_acked);
@@ -710,6 +711,11 @@ class MaxAckHeightTrackerTest : public QuicTest {
protected:
MaxAckHeightTrackerTest() : tracker_(/*initial_filter_window=*/10) {
tracker_.SetAckAggregationBandwidthThreshold(1.8);
+
+ if (GetQuicReloadableFlag(
+ quic_bbr_start_new_aggregation_epoch_after_a_full_round)) {
+ tracker_.SetStartNewAggregationEpochAfterFullRound(true);
+ }
}
// Run a full aggregation episode, which is one or more aggregated acks,
@@ -749,8 +755,9 @@ class MaxAckHeightTrackerTest : public QuicTest {
QuicByteCount last_extra_acked = 0;
for (QuicByteCount bytes = 0; bytes < aggregation_bytes;
bytes += bytes_per_ack) {
- QuicByteCount extra_acked =
- tracker_.Update(bandwidth_, RoundTripCount(), now_, bytes_per_ack);
+ QuicByteCount extra_acked = tracker_.Update(
+ bandwidth_, true, RoundTripCount(), last_sent_packet_number_,
+ last_acked_packet_number_, now_, bytes_per_ack);
QUIC_VLOG(1) << "T" << now_ << ": Update after " << bytes_per_ack
<< " bytes acked, " << extra_acked << " extra bytes acked";
// |extra_acked| should be 0 if either
@@ -784,6 +791,8 @@ class MaxAckHeightTrackerTest : public QuicTest {
QuicBandwidth bandwidth_ = QuicBandwidth::FromBytesPerSecond(10 * 1000);
QuicTime now_ = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(1);
QuicTime::Delta rtt_ = QuicTime::Delta::FromMilliseconds(60);
+ QuicPacketNumber last_sent_packet_number_;
+ QuicPacketNumber last_acked_packet_number_;
};
TEST_F(MaxAckHeightTrackerTest, VeryAggregatedLargeAck) {
@@ -864,5 +873,26 @@ TEST_F(MaxAckHeightTrackerTest, NotAggregated) {
EXPECT_LT(2u, tracker_.num_ack_aggregation_epochs());
}
+TEST_F(MaxAckHeightTrackerTest, StartNewEpochAfterAFullRound) {
+ last_sent_packet_number_ = QuicPacketNumber(10);
+ AggregationEpisode(bandwidth_ * 2, QuicTime::Delta::FromMilliseconds(50), 100,
+ true);
+
+ last_acked_packet_number_ = QuicPacketNumber(11);
+ // Update with a tiny bandwidth causes a very low expected bytes acked, which
+ // in turn causes the current epoch to continue if the |tracker_| doesn't
+ // check the packet numbers.
+ tracker_.Update(bandwidth_ * 0.1, true, RoundTripCount(),
+ last_sent_packet_number_, last_acked_packet_number_, now_,
+ 100);
+
+ if (GetQuicReloadableFlag(
+ quic_bbr_start_new_aggregation_epoch_after_a_full_round)) {
+ EXPECT_EQ(2u, tracker_.num_ack_aggregation_epochs());
+ } else {
+ EXPECT_EQ(1u, tracker_.num_ack_aggregation_epochs());
+ }
+}
+
} // namespace test
} // namespace quic
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 6eb9b2ec940..b67b7df263f 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
@@ -102,6 +102,11 @@ void Bbr2NetworkModel::OnCongestionEventStart(
lost_packets, MaxBandwidth(),
bandwidth_lo(), RoundTripCount());
+ if (sample.extra_acked == 0) {
+ cwnd_limited_before_aggregation_epoch_ =
+ congestion_event->prior_bytes_in_flight >= congestion_event->prior_cwnd;
+ }
+
if (sample.last_packet_send_state.is_valid) {
congestion_event->last_packet_send_state = sample.last_packet_send_state;
congestion_event->last_sample_is_app_limited =
@@ -159,6 +164,10 @@ void Bbr2NetworkModel::OnCongestionEventStart(
congestion_event->last_packet_send_state.total_bytes_acked;
max_bytes_delivered_in_round_ =
std::max(max_bytes_delivered_in_round_, bytes_delivered);
+ if (min_bytes_in_flight_in_round_ == 0 ||
+ congestion_event->bytes_in_flight < min_bytes_in_flight_in_round_) {
+ min_bytes_in_flight_in_round_ = congestion_event->bytes_in_flight;
+ }
}
// |bandwidth_latest_| and |inflight_latest_| only increased within a round.
@@ -325,14 +334,6 @@ bool Bbr2NetworkModel::MaybeExpireMinRtt(
return true;
}
-bool Bbr2NetworkModel::IsCongestionWindowLimited(
- const Bbr2CongestionEvent& congestion_event) const {
- QuicByteCount prior_bytes_in_flight = congestion_event.bytes_in_flight +
- congestion_event.bytes_acked +
- congestion_event.bytes_lost;
- return prior_bytes_in_flight >= congestion_event.prior_cwnd;
-}
-
bool Bbr2NetworkModel::IsInflightTooHigh(
const Bbr2CongestionEvent& congestion_event,
int64_t max_loss_events) const {
@@ -379,6 +380,7 @@ void Bbr2NetworkModel::OnNewRound() {
bytes_lost_in_round_ = 0;
loss_events_in_round_ = 0;
max_bytes_delivered_in_round_ = 0;
+ min_bytes_in_flight_in_round_ = 0;
}
void Bbr2NetworkModel::cap_inflight_lo(QuicByteCount cap) {
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 d28036df543..d017b55b84c 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
@@ -9,6 +9,7 @@
#include <limits>
#include "quic/core/congestion_control/bandwidth_sampler.h"
+#include "quic/core/congestion_control/send_algorithm_interface.h"
#include "quic/core/congestion_control/windowed_filter.h"
#include "quic/core/quic_bandwidth.h"
#include "quic/core/quic_packet_number.h"
@@ -94,6 +95,10 @@ struct QUIC_EXPORT_PRIVATE Bbr2Params {
// If false, exit STARTUP on loss only if bandwidth is below threshold.
bool always_exit_startup_on_excess_loss = false;
+ // If true, inclue extra acked during STARTUP and proactively reduce extra
+ // acked when bandwidth increases.
+ bool startup_include_extra_acked = false;
+
/*
* DRAIN parameters.
*/
@@ -130,6 +135,11 @@ struct QUIC_EXPORT_PRIVATE Bbr2Params {
// Multiplier to get target inflight (as multiple of BDP) for PROBE_UP phase.
float probe_bw_probe_inflight_gain = 1.25;
+ // When attempting to grow inflight_hi in PROBE_UP, check whether we are cwnd
+ // limited before the current aggregation epoch, instead of before the current
+ // ack event.
+ bool probe_bw_check_cwnd_limited_before_aggregation_epoch = false;
+
// Pacing gains.
float probe_bw_probe_up_pacing_gain = 1.25;
float probe_bw_probe_down_pacing_gain = 0.75;
@@ -138,6 +148,13 @@ struct QUIC_EXPORT_PRIVATE Bbr2Params {
float probe_bw_cwnd_gain = 2.0;
/*
+ * PROBE_UP parameters.
+ */
+ bool probe_up_includes_acks_after_cwnd_limited = false;
+ bool probe_up_dont_exit_if_no_queue_ = false;
+ bool probe_up_ignore_inflight_hi = false;
+
+ /*
* PROBE_RTT parameters.
*/
float probe_rtt_inflight_target_bdp_fraction = 0.5;
@@ -386,6 +403,10 @@ class QUIC_EXPORT_PRIVATE Bbr2NetworkModel {
return bandwidth_sampler_.max_ack_height();
}
+ bool cwnd_limited_before_aggregation_epoch() const {
+ return cwnd_limited_before_aggregation_epoch_;
+ }
+
void EnableOverestimateAvoidance() {
bandwidth_sampler_.EnableOverestimateAvoidance();
}
@@ -402,6 +423,22 @@ class QUIC_EXPORT_PRIVATE Bbr2NetworkModel {
return bandwidth_sampler_.num_ack_aggregation_epochs();
}
+ void SetStartNewAggregationEpochAfterFullRound(bool value) {
+ bandwidth_sampler_.SetStartNewAggregationEpochAfterFullRound(value);
+ }
+
+ void SetLimitMaxAckHeightTrackerBySendRate(bool value) {
+ bandwidth_sampler_.SetLimitMaxAckHeightTrackerBySendRate(value);
+ }
+
+ void SetMaxAckHeightTrackerWindowLength(QuicRoundTripCount value) {
+ bandwidth_sampler_.SetMaxAckHeightTrackerWindowLength(value);
+ }
+
+ void SetReduceExtraAckedOnBandwidthIncrease(bool value) {
+ bandwidth_sampler_.SetReduceExtraAckedOnBandwidthIncrease(value);
+ }
+
bool MaybeExpireMinRtt(const Bbr2CongestionEvent& congestion_event);
QuicBandwidth BandwidthEstimate() const {
@@ -412,9 +449,6 @@ class QUIC_EXPORT_PRIVATE Bbr2NetworkModel {
return round_trip_counter_.Count();
}
- bool IsCongestionWindowLimited(
- const Bbr2CongestionEvent& congestion_event) const;
-
// Return true if the number of loss events exceeds max_loss_events and
// fraction of bytes lost exceed the loss threshold.
bool IsInflightTooHigh(const Bbr2CongestionEvent& congestion_event,
@@ -459,6 +493,10 @@ class QUIC_EXPORT_PRIVATE Bbr2NetworkModel {
return max_bytes_delivered_in_round_;
}
+ QuicByteCount min_bytes_in_flight_in_round() const {
+ return min_bytes_in_flight_in_round_;
+ }
+
QuicPacketNumber end_of_app_limited_phase() const {
return bandwidth_sampler_.end_of_app_limited_phase();
}
@@ -529,6 +567,9 @@ class QUIC_EXPORT_PRIVATE Bbr2NetworkModel {
// congestion event) was sent and acked, respectively.
QuicByteCount max_bytes_delivered_in_round_ = 0;
+ // The minimum bytes in flight during this round.
+ QuicByteCount min_bytes_in_flight_in_round_ = 0;
+
// Max bandwidth in the current round. Updated once per congestion event.
QuicBandwidth bandwidth_latest_ = QuicBandwidth::Zero();
// Max bandwidth of recent rounds. Updated once per round.
@@ -546,6 +587,10 @@ class QUIC_EXPORT_PRIVATE Bbr2NetworkModel {
float cwnd_gain_;
float pacing_gain_;
+ // Whether we are cwnd limited prior to the start of the current aggregation
+ // epoch.
+ bool cwnd_limited_before_aggregation_epoch_ = false;
+
// STARTUP-centric fields which experimentally used by PROBE_UP.
bool full_bandwidth_reached_ = false;
QuicBandwidth full_bandwidth_baseline_ = QuicBandwidth::Zero();
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 ce9443f7d1d..fbc7769ef9a 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
@@ -36,8 +36,7 @@ void Bbr2ProbeBwMode::Enter(QuicTime now,
}
Bbr2Mode Bbr2ProbeBwMode::OnCongestionEvent(
- QuicByteCount prior_in_flight,
- QuicTime event_time,
+ QuicByteCount prior_in_flight, QuicTime event_time,
const AckedPacketVector& /*acked_packets*/,
const LostPacketVector& /*lost_packets*/,
const Bbr2CongestionEvent& congestion_event) {
@@ -84,6 +83,11 @@ Limits<QuicByteCount> Bbr2ProbeBwMode::GetCwndLimits() const {
return NoGreaterThan(
std::min(model_->inflight_lo(), model_->inflight_hi_with_headroom()));
}
+ if (Params().probe_up_ignore_inflight_hi &&
+ cycle_.phase == CyclePhase::PROBE_UP) {
+ // Similar to STARTUP.
+ return NoGreaterThan(model_->inflight_lo());
+ }
return NoGreaterThan(std::min(model_->inflight_lo(), model_->inflight_hi()));
}
@@ -187,12 +191,20 @@ Bbr2ProbeBwMode::AdaptUpperBoundsResult Bbr2ProbeBwMode::MaybeAdaptUpperBounds(
<< congestion_event.last_packet_send_state.total_bytes_acked << ")";
}
}
+ // TODO(ianswett): Inflight too high is really checking for loss, not
+ // inflight.
if (model_->IsInflightTooHigh(congestion_event,
Params().probe_bw_full_loss_count)) {
if (cycle_.is_sample_from_probing) {
cycle_.is_sample_from_probing = false;
-
- if (!send_state.is_app_limited) {
+ if (!send_state.is_app_limited ||
+ Params().probe_up_dont_exit_if_no_queue_) {
+ if (send_state.is_app_limited) {
+ // If there's excess loss or a queue is building, exit even if the
+ // last sample was app limited.
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr2_no_probe_up_exit_if_no_queue,
+ 2, 2);
+ }
const QuicByteCount inflight_target =
sender_->GetTargetBytesInflight() * (1.0 - Params().beta);
if (inflight_at_send >= inflight_target) {
@@ -339,12 +351,53 @@ void Bbr2ProbeBwMode::RaiseInflightHighSlope() {
void Bbr2ProbeBwMode::ProbeInflightHighUpward(
const Bbr2CongestionEvent& congestion_event) {
QUICHE_DCHECK_EQ(cycle_.phase, CyclePhase::PROBE_UP);
- if (!model_->IsCongestionWindowLimited(congestion_event)) {
- QUIC_DVLOG(3) << sender_
- << " Raising inflight_hi early return: Not cwnd limited.";
- // Not fully utilizing cwnd, so can't safely grow.
+ if (Params().probe_up_ignore_inflight_hi) {
+ // When inflight_hi is disabled in PROBE_UP, it increases when
+ // the number of bytes delivered in a round is larger inflight_hi.
return;
}
+ if (Params().probe_bw_check_cwnd_limited_before_aggregation_epoch) {
+ if (!model_->cwnd_limited_before_aggregation_epoch()) {
+ QUIC_DVLOG(3) << sender_
+ << " Raising inflight_hi early return: Not cwnd limited "
+ "before aggregation epoch.";
+ // Not fully utilizing cwnd, so can't safely grow.
+ return;
+ }
+ } else if (Params().probe_up_includes_acks_after_cwnd_limited) {
+ QUIC_RELOADABLE_FLAG_COUNT(
+ quic_bbr2_add_bytes_acked_after_inflight_hi_limited);
+ // Don't continue adding bytes to probe_up_acked if the sender was not
+ // app-limited after being inflight_hi limited at least once.
+ if (!cycle_.probe_up_app_limited_since_inflight_hi_limited_ ||
+ congestion_event.last_sample_is_app_limited) {
+ cycle_.probe_up_app_limited_since_inflight_hi_limited_ = false;
+ if (congestion_event.prior_bytes_in_flight <
+ congestion_event.prior_cwnd) {
+ QUIC_DVLOG(3) << sender_
+ << " Raising inflight_hi early return: Not cwnd limited.";
+ // Not fully utilizing cwnd, so can't safely grow.
+ return;
+ }
+
+ if (congestion_event.prior_cwnd < model_->inflight_hi()) {
+ QUIC_DVLOG(3)
+ << sender_
+ << " Raising inflight_hi early return: inflight_hi not fully used.";
+ // Not fully using inflight_hi, so don't grow it.
+ return;
+ }
+ }
+ // Start a new period of adding bytes_acked, because inflight_hi limited.
+ cycle_.probe_up_app_limited_since_inflight_hi_limited_ = true;
+ } else {
+ if (congestion_event.prior_bytes_in_flight < congestion_event.prior_cwnd) {
+ QUIC_DVLOG(3) << sender_
+ << " Raising inflight_hi early return: Not cwnd limited.";
+ // Not fully utilizing cwnd, so can't safely grow.
+ return;
+ }
+ }
if (congestion_event.prior_cwnd < model_->inflight_hi()) {
QUIC_DVLOG(3)
@@ -433,23 +486,32 @@ void Bbr2ProbeBwMode::UpdateProbeUp(
} else if (cycle_.rounds_in_phase > 0) {
const QuicByteCount bdp = model_->BDP();
QuicByteCount queuing_threshold_extra_bytes = 2 * kDefaultTCPMSS;
- if (Params().add_ack_height_to_queueing_threshold) {
- queuing_threshold_extra_bytes += model_->MaxAckHeight();
+ if (Params().probe_up_dont_exit_if_no_queue_) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr2_no_probe_up_exit_if_no_queue, 1,
+ 2);
+ is_queuing = congestion_event.end_of_round_trip &&
+ model_->min_bytes_in_flight_in_round() >
+ (bdp * Params().probe_bw_probe_inflight_gain +
+ queuing_threshold_extra_bytes);
+ } else {
+ if (Params().add_ack_height_to_queueing_threshold) {
+ queuing_threshold_extra_bytes += model_->MaxAckHeight();
+ }
+ QuicByteCount queuing_threshold =
+ (Params().probe_bw_probe_inflight_gain * bdp) +
+ queuing_threshold_extra_bytes;
+
+ is_queuing = congestion_event.bytes_in_flight >= queuing_threshold;
+
+ QUIC_DVLOG(3) << sender_
+ << " Checking if building up a queue. prior_in_flight:"
+ << prior_in_flight
+ << ", post_in_flight:" << congestion_event.bytes_in_flight
+ << ", threshold:" << queuing_threshold
+ << ", is_queuing:" << is_queuing
+ << ", max_bw:" << model_->MaxBandwidth()
+ << ", min_rtt:" << model_->MinRtt();
}
- QuicByteCount queuing_threshold =
- (Params().probe_bw_probe_inflight_gain * bdp) +
- queuing_threshold_extra_bytes;
-
- is_queuing = congestion_event.bytes_in_flight >= queuing_threshold;
-
- QUIC_DVLOG(3) << sender_
- << " Checking if building up a queue. prior_in_flight:"
- << prior_in_flight
- << ", post_in_flight:" << congestion_event.bytes_in_flight
- << ", threshold:" << queuing_threshold
- << ", is_queuing:" << is_queuing
- << ", max_bw:" << model_->MaxBandwidth()
- << ", min_rtt:" << model_->MinRtt();
}
if (is_risky || is_queuing) {
@@ -459,8 +521,7 @@ void Bbr2ProbeBwMode::UpdateProbeUp(
}
void Bbr2ProbeBwMode::EnterProbeDown(bool probed_too_high,
- bool stopped_risky_probe,
- QuicTime now) {
+ bool stopped_risky_probe, QuicTime now) {
QUIC_DVLOG(2) << sender_ << " Phase change: " << cycle_.phase << " ==> "
<< CyclePhase::PROBE_DOWN << " after "
<< now - cycle_.phase_start_time << ", or "
@@ -493,6 +554,7 @@ void Bbr2ProbeBwMode::EnterProbeDown(bool probed_too_high,
Params().probe_bw_probe_max_rand_duration.ToMicroseconds()));
cycle_.probe_up_bytes = std::numeric_limits<QuicByteCount>::max();
+ cycle_.probe_up_app_limited_since_inflight_hi_limited_ = false;
cycle_.has_advanced_max_bw = false;
model_->RestartRoundEarly();
}
@@ -600,9 +662,7 @@ std::ostream& operator<<(std::ostream& os,
return os;
}
-const Bbr2Params& Bbr2ProbeBwMode::Params() const {
- return sender_->Params();
-}
+const Bbr2Params& Bbr2ProbeBwMode::Params() const { return sender_->Params(); }
float Bbr2ProbeBwMode::PacingGainForPhase(
Bbr2ProbeBwMode::CyclePhase phase) const {
diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_bw.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_bw.h
index 45b1df70c5c..832dfa14154 100644
--- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_bw.h
+++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_bw.h
@@ -118,6 +118,7 @@ class QUIC_EXPORT_PRIVATE Bbr2ProbeBwMode final : public Bbr2ModeBase {
uint64_t probe_up_rounds = 0;
QuicByteCount probe_up_bytes = std::numeric_limits<QuicByteCount>::max();
QuicByteCount probe_up_acked = 0;
+ bool probe_up_app_limited_since_inflight_hi_limited_ = false;
// Whether max bandwidth filter window has advanced in this cycle. It is
// advanced once per cycle.
bool has_advanced_max_bw = false;
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 09b920e5759..1e276490eee 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
@@ -120,6 +120,16 @@ void Bbr2Sender::SetFromConfig(const QuicConfig& config,
void Bbr2Sender::ApplyConnectionOptions(
const QuicTagVector& connection_options) {
+ if (GetQuicReloadableFlag(quic_bbr2_extra_acked_window) &&
+ ContainsQuicTag(connection_options, kBBR4)) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr2_extra_acked_window, 1, 2);
+ model_.SetMaxAckHeightTrackerWindowLength(20);
+ }
+ if (GetQuicReloadableFlag(quic_bbr2_extra_acked_window) &&
+ ContainsQuicTag(connection_options, kBBR5)) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr2_extra_acked_window, 2, 2);
+ model_.SetMaxAckHeightTrackerWindowLength(40);
+ }
if (ContainsQuicTag(connection_options, kBBQ2)) {
params_.startup_cwnd_gain = 2.885;
params_.drain_cwnd_gain = 2.885;
@@ -158,6 +168,54 @@ void Bbr2Sender::ApplyConnectionOptions(
if (ContainsQuicTag(connection_options, kBBQ9)) {
params_.bw_lo_mode_ = Bbr2Params::QuicBandwidthLoMode::CWND_REDUCTION;
}
+ if (GetQuicReloadableFlag(
+ quic_bbr2_check_cwnd_limited_before_aggregation_epoch) &&
+ ContainsQuicTag(connection_options, kB201)) {
+ QUIC_RELOADABLE_FLAG_COUNT(
+ quic_bbr2_check_cwnd_limited_before_aggregation_epoch);
+ params_.probe_bw_check_cwnd_limited_before_aggregation_epoch = true;
+ }
+ if (GetQuicReloadableFlag(quic_bbr2_no_probe_up_exit_if_no_queue) &&
+ ContainsQuicTag(connection_options, kB202)) {
+ params_.probe_up_dont_exit_if_no_queue_ = true;
+ }
+ if (GetQuicReloadableFlag(quic_bbr2_ignore_inflight_hi_in_probe_up) &&
+ ContainsQuicTag(connection_options, kB203)) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_bbr2_ignore_inflight_hi_in_probe_up);
+ params_.probe_up_ignore_inflight_hi = true;
+ }
+ if (GetQuicReloadableFlag(quic_bbr2_startup_extra_acked) &&
+ ContainsQuicTag(connection_options, kB204)) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr2_startup_extra_acked, 1, 2);
+ model_.SetReduceExtraAckedOnBandwidthIncrease(true);
+ }
+ if (GetQuicReloadableFlag(quic_bbr2_startup_extra_acked) &&
+ ContainsQuicTag(connection_options, kB205)) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr2_startup_extra_acked, 2, 2);
+ params_.startup_include_extra_acked = true;
+ }
+ if (GetQuicReloadableFlag(
+ quic_bbr_start_new_aggregation_epoch_after_a_full_round) &&
+ ContainsQuicTag(connection_options, kBBRA)) {
+ model_.SetStartNewAggregationEpochAfterFullRound(true);
+ }
+ if (GetQuicReloadableFlag(quic_bbr_use_send_rate_in_max_ack_height_tracker) &&
+ ContainsQuicTag(connection_options, kBBRB)) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(
+ quic_bbr_use_send_rate_in_max_ack_height_tracker, 2, 2);
+ model_.SetLimitMaxAckHeightTrackerBySendRate(true);
+ }
+ if (GetQuicReloadableFlag(
+ quic_bbr2_add_bytes_acked_after_inflight_hi_limited) &&
+ ContainsQuicTag(connection_options, kBBQ0)) {
+ params_.probe_up_includes_acks_after_cwnd_limited = true;
+ }
+
+ if (GetQuicReloadableFlag(quic_bbr2_startup_probe_up_loss_events) &&
+ ContainsQuicTag(connection_options, kB206)) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_bbr2_startup_probe_up_loss_events);
+ params_.startup_full_loss_count = params_.probe_bw_full_loss_count;
+ }
}
Limits<QuicByteCount> Bbr2Sender::GetCwndLimitsByMode() const {
@@ -344,7 +402,7 @@ void Bbr2Sender::UpdateCongestionWindow(QuicByteCount bytes_acked) {
QuicByteCount target_cwnd = GetTargetCongestionWindow(model_.cwnd_gain());
const QuicByteCount prior_cwnd = cwnd_;
- if (model_.full_bandwidth_reached()) {
+ if (model_.full_bandwidth_reached() || Params().startup_include_extra_acked) {
target_cwnd += model_.MaxAckHeight();
cwnd_ = std::min(prior_cwnd + bytes_acked, target_cwnd);
} else if (prior_cwnd < target_cwnd || prior_cwnd < 2 * initial_cwnd_) {
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 ae0c8842c8e..490996bb087 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
@@ -202,6 +202,8 @@ class Bbr2DefaultTopologyTest : public Bbr2SimulatorTest {
GetQuicFlag(FLAGS_quic_max_congestion_window), &random_,
QuicConnectionPeer::GetStats(endpoint->connection()), old_sender);
QuicConnectionPeer::SetSendAlgorithm(endpoint->connection(), sender);
+ const int kTestMaxPacketSize = 1350;
+ endpoint->connection()->SetMaxPacketLength(kTestMaxPacketSize);
endpoint->RecordTrace();
return sender;
}
@@ -308,11 +310,15 @@ class Bbr2DefaultTopologyTest : public Bbr2SimulatorTest {
}
void SetConnectionOption(QuicTag option) {
+ SetConnectionOption(std::move(option), sender_);
+ }
+
+ void SetConnectionOption(QuicTag option, Bbr2Sender* sender) {
QuicConfig config;
QuicTagVector options;
options.push_back(option);
QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
- sender_->SetFromConfig(config, Perspective::IS_SERVER);
+ sender->SetFromConfig(config, Perspective::IS_SERVER);
}
bool Bbr2ModeIsOneOf(const std::vector<Bbr2Mode>& expected_modes) const {
@@ -436,6 +442,107 @@ TEST_F(Bbr2DefaultTopologyTest, SimpleTransferB2RC) {
EXPECT_APPROX_EQ(params.RTT(), rtt_stats()->min_rtt(), 0.2f);
}
+TEST_F(Bbr2DefaultTopologyTest, SimpleTransferB201) {
+ SetQuicReloadableFlag(quic_bbr2_check_cwnd_limited_before_aggregation_epoch,
+ true);
+ SetConnectionOption(kB201);
+ DefaultTopologyParams params;
+ CreateNetwork(params);
+
+ // Transfer 12MB.
+ DoSimpleTransfer(12 * 1024 * 1024, QuicTime::Delta::FromSeconds(35));
+ EXPECT_TRUE(Bbr2ModeIsOneOf({Bbr2Mode::PROBE_BW, Bbr2Mode::PROBE_RTT}));
+
+ EXPECT_APPROX_EQ(params.BottleneckBandwidth(),
+ sender_->ExportDebugState().bandwidth_hi, 0.01f);
+
+ EXPECT_LE(sender_loss_rate_in_packets(), 0.05);
+ // The margin here is high, because the aggregation greatly increases
+ // smoothed rtt.
+ EXPECT_GE(params.RTT() * 4, rtt_stats()->smoothed_rtt());
+ EXPECT_APPROX_EQ(params.RTT(), rtt_stats()->min_rtt(), 0.2f);
+}
+
+TEST_F(Bbr2DefaultTopologyTest, SimpleTransferB206) {
+ SetQuicReloadableFlag(quic_bbr2_startup_probe_up_loss_events, true);
+ SetConnectionOption(kB206);
+ DefaultTopologyParams params;
+ CreateNetwork(params);
+
+ // Transfer 12MB.
+ DoSimpleTransfer(12 * 1024 * 1024, QuicTime::Delta::FromSeconds(35));
+ EXPECT_TRUE(Bbr2ModeIsOneOf({Bbr2Mode::PROBE_BW, Bbr2Mode::PROBE_RTT}));
+
+ EXPECT_APPROX_EQ(params.BottleneckBandwidth(),
+ sender_->ExportDebugState().bandwidth_hi, 0.01f);
+
+ EXPECT_LE(sender_loss_rate_in_packets(), 0.05);
+ // The margin here is high, because the aggregation greatly increases
+ // smoothed rtt.
+ EXPECT_GE(params.RTT() * 4, rtt_stats()->smoothed_rtt());
+ EXPECT_APPROX_EQ(params.RTT(), rtt_stats()->min_rtt(), 0.2f);
+}
+
+TEST_F(Bbr2DefaultTopologyTest, SimpleTransferBBRB) {
+ SetQuicReloadableFlag(quic_bbr_use_send_rate_in_max_ack_height_tracker, true);
+ SetConnectionOption(kBBRB);
+ DefaultTopologyParams params;
+ CreateNetwork(params);
+
+ // Transfer 12MB.
+ DoSimpleTransfer(12 * 1024 * 1024, QuicTime::Delta::FromSeconds(35));
+ EXPECT_TRUE(Bbr2ModeIsOneOf({Bbr2Mode::PROBE_BW, Bbr2Mode::PROBE_RTT}));
+
+ EXPECT_APPROX_EQ(params.BottleneckBandwidth(),
+ sender_->ExportDebugState().bandwidth_hi, 0.01f);
+
+ EXPECT_LE(sender_loss_rate_in_packets(), 0.05);
+ // The margin here is high, because the aggregation greatly increases
+ // smoothed rtt.
+ EXPECT_GE(params.RTT() * 4, rtt_stats()->smoothed_rtt());
+ EXPECT_APPROX_EQ(params.RTT(), rtt_stats()->min_rtt(), 0.2f);
+}
+
+TEST_F(Bbr2DefaultTopologyTest, SimpleTransferBBR4) {
+ SetQuicReloadableFlag(quic_bbr2_extra_acked_window, true);
+ SetConnectionOption(kBBR4);
+ DefaultTopologyParams params;
+ CreateNetwork(params);
+
+ // Transfer 12MB.
+ DoSimpleTransfer(12 * 1024 * 1024, QuicTime::Delta::FromSeconds(35));
+ EXPECT_TRUE(Bbr2ModeIsOneOf({Bbr2Mode::PROBE_BW, Bbr2Mode::PROBE_RTT}));
+
+ EXPECT_APPROX_EQ(params.BottleneckBandwidth(),
+ sender_->ExportDebugState().bandwidth_hi, 0.01f);
+
+ EXPECT_LE(sender_loss_rate_in_packets(), 0.05);
+ // The margin here is high, because the aggregation greatly increases
+ // smoothed rtt.
+ EXPECT_GE(params.RTT() * 4, rtt_stats()->smoothed_rtt());
+ EXPECT_APPROX_EQ(params.RTT(), rtt_stats()->min_rtt(), 0.2f);
+}
+
+TEST_F(Bbr2DefaultTopologyTest, SimpleTransferBBR5) {
+ SetQuicReloadableFlag(quic_bbr2_extra_acked_window, true);
+ SetConnectionOption(kBBR5);
+ DefaultTopologyParams params;
+ CreateNetwork(params);
+
+ // Transfer 12MB.
+ DoSimpleTransfer(12 * 1024 * 1024, QuicTime::Delta::FromSeconds(35));
+ EXPECT_TRUE(Bbr2ModeIsOneOf({Bbr2Mode::PROBE_BW, Bbr2Mode::PROBE_RTT}));
+
+ EXPECT_APPROX_EQ(params.BottleneckBandwidth(),
+ sender_->ExportDebugState().bandwidth_hi, 0.01f);
+
+ EXPECT_LE(sender_loss_rate_in_packets(), 0.05);
+ // The margin here is high, because the aggregation greatly increases
+ // smoothed rtt.
+ EXPECT_GE(params.RTT() * 4, rtt_stats()->smoothed_rtt());
+ EXPECT_APPROX_EQ(params.RTT(), rtt_stats()->min_rtt(), 0.2f);
+}
+
TEST_F(Bbr2DefaultTopologyTest, SimpleTransferSmallBuffer) {
DefaultTopologyParams params;
params.switch_queue_capacity_in_bdp = 0.5;
@@ -488,6 +595,34 @@ TEST_F(Bbr2DefaultTopologyTest, SimpleTransfer2RTTAggregationBytes) {
EXPECT_APPROX_EQ(params.RTT(), rtt_stats()->min_rtt(), 0.2f);
}
+TEST_F(Bbr2DefaultTopologyTest, SimpleTransfer2RTTAggregationBytesB201) {
+ SetQuicReloadableFlag(quic_bbr2_check_cwnd_limited_before_aggregation_epoch,
+ true);
+ SetConnectionOption(kB201);
+ DefaultTopologyParams params;
+ CreateNetwork(params);
+ // 2 RTTs of aggregation, with a max of 10kb.
+ EnableAggregation(10 * 1024, 2 * params.RTT());
+
+ // Transfer 12MB.
+ DoSimpleTransfer(12 * 1024 * 1024, QuicTime::Delta::FromSeconds(35));
+ EXPECT_TRUE(Bbr2ModeIsOneOf({Bbr2Mode::PROBE_BW, Bbr2Mode::PROBE_RTT}));
+
+ // TODO(wub): Tighten the error bound once BSAO is default enabled.
+ EXPECT_APPROX_EQ(params.BottleneckBandwidth(),
+ sender_->ExportDebugState().bandwidth_hi, 0.5f);
+
+ if (GetQuicReloadableFlag(quic_fix_pacing_sender_bursts)) {
+ EXPECT_LE(sender_loss_rate_in_packets(), 0.01);
+ } else {
+ EXPECT_LE(sender_loss_rate_in_packets(), 0.05);
+ }
+ // The margin here is high, because both link level aggregation and ack
+ // decimation can greatly increase smoothed rtt.
+ EXPECT_GE(params.RTT() * 5, rtt_stats()->smoothed_rtt());
+ EXPECT_APPROX_EQ(params.RTT(), rtt_stats()->min_rtt(), 0.2f);
+}
+
TEST_F(Bbr2DefaultTopologyTest, SimpleTransferAckDecimation) {
SetConnectionOption(kBSAO);
DefaultTopologyParams params;
@@ -567,6 +702,371 @@ TEST_F(Bbr2DefaultTopologyTest, QUIC_SLOW_TEST(BandwidthIncrease)) {
sender_->ExportDebugState().bandwidth_hi, 0.02f);
}
+// Test Bbr2's reaction to a 100x bandwidth increase during a transfer with BBQ0
+TEST_F(Bbr2DefaultTopologyTest, QUIC_SLOW_TEST(BandwidthIncreaseBBQ0)) {
+ SetQuicReloadableFlag(quic_bbr2_add_bytes_acked_after_inflight_hi_limited,
+ true);
+ SetConnectionOption(kBBQ0);
+ DefaultTopologyParams params;
+ params.local_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(15000);
+ params.test_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(100);
+ CreateNetwork(params);
+
+ sender_endpoint_.AddBytesToTransfer(10 * 1024 * 1024);
+
+ simulator_.RunFor(QuicTime::Delta::FromSeconds(15));
+ EXPECT_TRUE(Bbr2ModeIsOneOf({Bbr2Mode::PROBE_BW, Bbr2Mode::PROBE_RTT}));
+ QUIC_LOG(INFO) << "Bandwidth increasing at time " << SimulatedNow();
+
+ EXPECT_APPROX_EQ(params.test_link.bandwidth,
+ sender_->ExportDebugState().bandwidth_est, 0.1f);
+ EXPECT_LE(sender_loss_rate_in_packets(), 0.30);
+
+ // Now increase the bottleneck bandwidth from 100Kbps to 10Mbps.
+ params.test_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(10000);
+ TestLink()->set_bandwidth(params.test_link.bandwidth);
+
+ bool simulator_result = simulator_.RunUntilOrTimeout(
+ [this]() { return sender_endpoint_.bytes_to_transfer() == 0; },
+ QuicTime::Delta::FromSeconds(50));
+ EXPECT_TRUE(simulator_result);
+ // Ensure the full bandwidth is discovered.
+ EXPECT_APPROX_EQ(params.test_link.bandwidth,
+ sender_->ExportDebugState().bandwidth_hi, 0.02f);
+}
+
+// Test Bbr2's reaction to a 100x bandwidth increase during a transfer with BBQ0
+// in the presence of ACK aggregation.
+TEST_F(Bbr2DefaultTopologyTest,
+ QUIC_SLOW_TEST(BandwidthIncreaseBBQ0Aggregation)) {
+ SetQuicReloadableFlag(quic_bbr2_add_bytes_acked_after_inflight_hi_limited,
+ true);
+ SetConnectionOption(kBBQ0);
+ DefaultTopologyParams params;
+ params.local_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(15000);
+ params.test_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(100);
+ CreateNetwork(params);
+
+ // 2 RTTs of aggregation, with a max of 10kb.
+ EnableAggregation(10 * 1024, 2 * params.RTT());
+
+ // Reduce the payload to 2MB because 10MB takes too long.
+ sender_endpoint_.AddBytesToTransfer(2 * 1024 * 1024);
+
+ simulator_.RunFor(QuicTime::Delta::FromSeconds(15));
+ EXPECT_TRUE(Bbr2ModeIsOneOf({Bbr2Mode::PROBE_BW, Bbr2Mode::PROBE_RTT}));
+ QUIC_LOG(INFO) << "Bandwidth increasing at time " << SimulatedNow();
+
+ // This is much farther off when aggregation is present,
+ // Ideally BSAO or another option would fix this.
+ // TODO(ianswett) Make these bound tighter once overestimation is reduced.
+ EXPECT_APPROX_EQ(params.test_link.bandwidth,
+ sender_->ExportDebugState().bandwidth_est, 0.6f);
+ EXPECT_LE(sender_loss_rate_in_packets(), 0.35);
+
+ // Now increase the bottleneck bandwidth from 100Kbps to 10Mbps.
+ params.test_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(10000);
+ TestLink()->set_bandwidth(params.test_link.bandwidth);
+
+ bool simulator_result = simulator_.RunUntilOrTimeout(
+ [this]() { return sender_endpoint_.bytes_to_transfer() == 0; },
+ QuicTime::Delta::FromSeconds(50));
+ EXPECT_TRUE(simulator_result);
+ // Ensure at least 10% of full bandwidth is discovered.
+ EXPECT_APPROX_EQ(params.test_link.bandwidth,
+ sender_->ExportDebugState().bandwidth_hi, 0.90f);
+}
+
+// Test Bbr2's reaction to a 100x bandwidth increase during a transfer with B202
+TEST_F(Bbr2DefaultTopologyTest, QUIC_SLOW_TEST(BandwidthIncreaseB202)) {
+ SetQuicReloadableFlag(quic_bbr2_no_probe_up_exit_if_no_queue, true);
+ SetConnectionOption(kB202);
+ DefaultTopologyParams params;
+ params.local_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(15000);
+ params.test_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(100);
+ CreateNetwork(params);
+
+ sender_endpoint_.AddBytesToTransfer(10 * 1024 * 1024);
+
+ simulator_.RunFor(QuicTime::Delta::FromSeconds(15));
+ EXPECT_TRUE(Bbr2ModeIsOneOf({Bbr2Mode::PROBE_BW, Bbr2Mode::PROBE_RTT}));
+ QUIC_LOG(INFO) << "Bandwidth increasing at time " << SimulatedNow();
+
+ EXPECT_APPROX_EQ(params.test_link.bandwidth,
+ sender_->ExportDebugState().bandwidth_est, 0.1f);
+ EXPECT_LE(sender_loss_rate_in_packets(), 0.30);
+
+ // Now increase the bottleneck bandwidth from 100Kbps to 10Mbps.
+ params.test_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(10000);
+ TestLink()->set_bandwidth(params.test_link.bandwidth);
+
+ bool simulator_result = simulator_.RunUntilOrTimeout(
+ [this]() { return sender_endpoint_.bytes_to_transfer() == 0; },
+ QuicTime::Delta::FromSeconds(50));
+ EXPECT_TRUE(simulator_result);
+ // Ensure the full bandwidth is discovered.
+ EXPECT_APPROX_EQ(params.test_link.bandwidth,
+ sender_->ExportDebugState().bandwidth_hi, 0.1f);
+}
+
+// Test Bbr2's reaction to a 100x bandwidth increase during a transfer with B202
+// in the presence of ACK aggregation.
+TEST_F(Bbr2DefaultTopologyTest, DISABLED_BandwidthIncreaseB202Aggregation) {
+ // TODO(b/201532297) Reenable this test.
+ SetQuicReloadableFlag(quic_bbr2_no_probe_up_exit_if_no_queue, true);
+ SetConnectionOption(kB202);
+ DefaultTopologyParams params;
+ params.local_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(15000);
+ params.test_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(100);
+ CreateNetwork(params);
+
+ // 2 RTTs of aggregation, with a max of 10kb.
+ EnableAggregation(10 * 1024, 2 * params.RTT());
+
+ // Reduce the payload to 2MB because 10MB takes too long.
+ sender_endpoint_.AddBytesToTransfer(2 * 1024 * 1024);
+
+ simulator_.RunFor(QuicTime::Delta::FromSeconds(15));
+ EXPECT_TRUE(Bbr2ModeIsOneOf({Bbr2Mode::PROBE_BW, Bbr2Mode::PROBE_RTT}));
+ QUIC_LOG(INFO) << "Bandwidth increasing at time " << SimulatedNow();
+
+ // This is much farther off when aggregation is present,
+ // Ideally BSAO or another option would fix this.
+ EXPECT_APPROX_EQ(params.test_link.bandwidth,
+ sender_->ExportDebugState().bandwidth_est, 0.45f);
+ EXPECT_LE(sender_loss_rate_in_packets(), 0.35);
+
+ // Now increase the bottleneck bandwidth from 100Kbps to 10Mbps.
+ params.test_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(10000);
+ TestLink()->set_bandwidth(params.test_link.bandwidth);
+
+ bool simulator_result = simulator_.RunUntilOrTimeout(
+ [this]() { return sender_endpoint_.bytes_to_transfer() == 0; },
+ QuicTime::Delta::FromSeconds(50));
+ EXPECT_TRUE(simulator_result);
+ // Ensure at least 10% of full bandwidth is discovered.
+ EXPECT_APPROX_EQ(params.test_link.bandwidth,
+ sender_->ExportDebugState().bandwidth_hi, 0.92f);
+}
+
+// Test Bbr2's reaction to a 100x bandwidth increase during a transfer with B203
+TEST_F(Bbr2DefaultTopologyTest, QUIC_SLOW_TEST(BandwidthIncreaseB203)) {
+ SetQuicReloadableFlag(quic_bbr2_ignore_inflight_hi_in_probe_up, true);
+ SetConnectionOption(kB203);
+ DefaultTopologyParams params;
+ params.local_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(15000);
+ params.test_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(100);
+ CreateNetwork(params);
+
+ sender_endpoint_.AddBytesToTransfer(10 * 1024 * 1024);
+
+ simulator_.RunFor(QuicTime::Delta::FromSeconds(15));
+ EXPECT_TRUE(Bbr2ModeIsOneOf({Bbr2Mode::PROBE_BW, Bbr2Mode::PROBE_RTT}));
+ QUIC_LOG(INFO) << "Bandwidth increasing at time " << SimulatedNow();
+
+ EXPECT_APPROX_EQ(params.test_link.bandwidth,
+ sender_->ExportDebugState().bandwidth_est, 0.1f);
+ EXPECT_LE(sender_loss_rate_in_packets(), 0.30);
+
+ // Now increase the bottleneck bandwidth from 100Kbps to 10Mbps.
+ params.test_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(10000);
+ TestLink()->set_bandwidth(params.test_link.bandwidth);
+
+ bool simulator_result = simulator_.RunUntilOrTimeout(
+ [this]() { return sender_endpoint_.bytes_to_transfer() == 0; },
+ QuicTime::Delta::FromSeconds(50));
+ EXPECT_TRUE(simulator_result);
+ // Ensure the full bandwidth is discovered.
+ EXPECT_APPROX_EQ(params.test_link.bandwidth,
+ sender_->ExportDebugState().bandwidth_hi, 0.02f);
+}
+
+// Test Bbr2's reaction to a 100x bandwidth increase during a transfer with B203
+// in the presence of ACK aggregation.
+TEST_F(Bbr2DefaultTopologyTest,
+ QUIC_SLOW_TEST(BandwidthIncreaseB203Aggregation)) {
+ SetQuicReloadableFlag(quic_bbr2_ignore_inflight_hi_in_probe_up, true);
+ SetConnectionOption(kB203);
+ DefaultTopologyParams params;
+ params.local_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(15000);
+ params.test_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(100);
+ CreateNetwork(params);
+
+ // 2 RTTs of aggregation, with a max of 10kb.
+ EnableAggregation(10 * 1024, 2 * params.RTT());
+
+ // Reduce the payload to 2MB because 10MB takes too long.
+ sender_endpoint_.AddBytesToTransfer(2 * 1024 * 1024);
+
+ simulator_.RunFor(QuicTime::Delta::FromSeconds(15));
+ EXPECT_TRUE(Bbr2ModeIsOneOf({Bbr2Mode::PROBE_BW, Bbr2Mode::PROBE_RTT}));
+ QUIC_LOG(INFO) << "Bandwidth increasing at time " << SimulatedNow();
+
+ // This is much farther off when aggregation is present,
+ // Ideally BSAO or another option would fix this.
+ EXPECT_APPROX_EQ(params.test_link.bandwidth,
+ sender_->ExportDebugState().bandwidth_est, 0.60f);
+ EXPECT_LE(sender_loss_rate_in_packets(), 0.35);
+
+ // Now increase the bottleneck bandwidth from 100Kbps to 10Mbps.
+ params.test_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(10000);
+ TestLink()->set_bandwidth(params.test_link.bandwidth);
+
+ bool simulator_result = simulator_.RunUntilOrTimeout(
+ [this]() { return sender_endpoint_.bytes_to_transfer() == 0; },
+ QuicTime::Delta::FromSeconds(50));
+ EXPECT_TRUE(simulator_result);
+ // Ensure at least 10% of full bandwidth is discovered.
+ EXPECT_APPROX_EQ(params.test_link.bandwidth,
+ sender_->ExportDebugState().bandwidth_hi, 0.91f);
+}
+
+// Test Bbr2's reaction to a 100x bandwidth increase during a transfer with B204
+TEST_F(Bbr2DefaultTopologyTest, QUIC_SLOW_TEST(BandwidthIncreaseB204)) {
+ SetQuicReloadableFlag(quic_bbr2_startup_extra_acked, true);
+ SetConnectionOption(kB204);
+ DefaultTopologyParams params;
+ params.local_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(15000);
+ params.test_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(100);
+ CreateNetwork(params);
+
+ sender_endpoint_.AddBytesToTransfer(10 * 1024 * 1024);
+
+ simulator_.RunFor(QuicTime::Delta::FromSeconds(15));
+ EXPECT_TRUE(Bbr2ModeIsOneOf({Bbr2Mode::PROBE_BW, Bbr2Mode::PROBE_RTT}));
+ QUIC_LOG(INFO) << "Bandwidth increasing at time " << SimulatedNow();
+
+ EXPECT_APPROX_EQ(params.test_link.bandwidth,
+ sender_->ExportDebugState().bandwidth_est, 0.1f);
+ EXPECT_LE(sender_loss_rate_in_packets(), 0.25);
+ EXPECT_LE(sender_->ExportDebugState().max_ack_height, 2000u);
+
+ // Now increase the bottleneck bandwidth from 100Kbps to 10Mbps.
+ params.test_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(10000);
+ TestLink()->set_bandwidth(params.test_link.bandwidth);
+
+ bool simulator_result = simulator_.RunUntilOrTimeout(
+ [this]() { return sender_endpoint_.bytes_to_transfer() == 0; },
+ QuicTime::Delta::FromSeconds(50));
+ EXPECT_TRUE(simulator_result);
+ // Ensure the full bandwidth is discovered.
+ EXPECT_APPROX_EQ(params.test_link.bandwidth,
+ sender_->ExportDebugState().bandwidth_hi, 0.02f);
+}
+
+// Test Bbr2's reaction to a 100x bandwidth increase during a transfer with B204
+// in the presence of ACK aggregation.
+TEST_F(Bbr2DefaultTopologyTest,
+ QUIC_SLOW_TEST(BandwidthIncreaseB204Aggregation)) {
+ SetQuicReloadableFlag(quic_bbr2_startup_extra_acked, true);
+ SetConnectionOption(kB204);
+ DefaultTopologyParams params;
+ params.local_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(15000);
+ params.test_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(100);
+ CreateNetwork(params);
+
+ // 2 RTTs of aggregation, with a max of 10kb.
+ EnableAggregation(10 * 1024, 2 * params.RTT());
+
+ // Reduce the payload to 2MB because 10MB takes too long.
+ sender_endpoint_.AddBytesToTransfer(2 * 1024 * 1024);
+
+ simulator_.RunFor(QuicTime::Delta::FromSeconds(15));
+ EXPECT_TRUE(Bbr2ModeIsOneOf({Bbr2Mode::PROBE_BW, Bbr2Mode::PROBE_RTT}));
+ QUIC_LOG(INFO) << "Bandwidth increasing at time " << SimulatedNow();
+
+ // This is much farther off when aggregation is present,
+ // Ideally BSAO or another option would fix this.
+ EXPECT_APPROX_EQ(params.test_link.bandwidth,
+ sender_->ExportDebugState().bandwidth_est, 0.55f);
+ EXPECT_LE(sender_loss_rate_in_packets(), 0.35);
+ EXPECT_LE(sender_->ExportDebugState().max_ack_height, 10000u);
+
+ // Now increase the bottleneck bandwidth from 100Kbps to 10Mbps.
+ params.test_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(10000);
+ TestLink()->set_bandwidth(params.test_link.bandwidth);
+
+ bool simulator_result = simulator_.RunUntilOrTimeout(
+ [this]() { return sender_endpoint_.bytes_to_transfer() == 0; },
+ QuicTime::Delta::FromSeconds(50));
+ EXPECT_TRUE(simulator_result);
+ // Ensure at least 10% of full bandwidth is discovered.
+ EXPECT_APPROX_EQ(params.test_link.bandwidth,
+ sender_->ExportDebugState().bandwidth_hi, 0.95f);
+}
+
+// Test Bbr2's reaction to a 100x bandwidth increase during a transfer with B205
+TEST_F(Bbr2DefaultTopologyTest, QUIC_SLOW_TEST(BandwidthIncreaseB205)) {
+ SetQuicReloadableFlag(quic_bbr2_startup_extra_acked, true);
+ SetConnectionOption(kB205);
+ DefaultTopologyParams params;
+ params.local_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(15000);
+ params.test_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(100);
+ CreateNetwork(params);
+
+ sender_endpoint_.AddBytesToTransfer(10 * 1024 * 1024);
+
+ simulator_.RunFor(QuicTime::Delta::FromSeconds(15));
+ EXPECT_TRUE(Bbr2ModeIsOneOf({Bbr2Mode::PROBE_BW, Bbr2Mode::PROBE_RTT}));
+ QUIC_LOG(INFO) << "Bandwidth increasing at time " << SimulatedNow();
+
+ EXPECT_APPROX_EQ(params.test_link.bandwidth,
+ sender_->ExportDebugState().bandwidth_est, 0.1f);
+ EXPECT_LE(sender_loss_rate_in_packets(), 0.10);
+
+ // Now increase the bottleneck bandwidth from 100Kbps to 10Mbps.
+ params.test_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(10000);
+ TestLink()->set_bandwidth(params.test_link.bandwidth);
+
+ bool simulator_result = simulator_.RunUntilOrTimeout(
+ [this]() { return sender_endpoint_.bytes_to_transfer() == 0; },
+ QuicTime::Delta::FromSeconds(50));
+ EXPECT_TRUE(simulator_result);
+ // Ensure the full bandwidth is discovered.
+ EXPECT_APPROX_EQ(params.test_link.bandwidth,
+ sender_->ExportDebugState().bandwidth_hi, 0.1f);
+}
+
+// Test Bbr2's reaction to a 100x bandwidth increase during a transfer with B205
+// in the presence of ACK aggregation.
+TEST_F(Bbr2DefaultTopologyTest,
+ QUIC_SLOW_TEST(BandwidthIncreaseB205Aggregation)) {
+ SetQuicReloadableFlag(quic_bbr2_startup_extra_acked, true);
+ SetConnectionOption(kB205);
+ DefaultTopologyParams params;
+ params.local_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(15000);
+ params.test_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(100);
+ CreateNetwork(params);
+
+ // 2 RTTs of aggregation, with a max of 10kb.
+ EnableAggregation(10 * 1024, 2 * params.RTT());
+
+ // Reduce the payload to 2MB because 10MB takes too long.
+ sender_endpoint_.AddBytesToTransfer(2 * 1024 * 1024);
+
+ simulator_.RunFor(QuicTime::Delta::FromSeconds(15));
+ EXPECT_TRUE(Bbr2ModeIsOneOf({Bbr2Mode::PROBE_BW, Bbr2Mode::PROBE_RTT}));
+ QUIC_LOG(INFO) << "Bandwidth increasing at time " << SimulatedNow();
+
+ // This is much farther off when aggregation is present,
+ // Ideally BSAO or another option would fix this.
+ EXPECT_APPROX_EQ(params.test_link.bandwidth,
+ sender_->ExportDebugState().bandwidth_est, 0.45f);
+ EXPECT_LE(sender_loss_rate_in_packets(), 0.15);
+
+ // Now increase the bottleneck bandwidth from 100Kbps to 10Mbps.
+ params.test_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(10000);
+ TestLink()->set_bandwidth(params.test_link.bandwidth);
+
+ bool simulator_result = simulator_.RunUntilOrTimeout(
+ [this]() { return sender_endpoint_.bytes_to_transfer() == 0; },
+ QuicTime::Delta::FromSeconds(50));
+ EXPECT_TRUE(simulator_result);
+ // Ensure at least 5% of full bandwidth is discovered.
+ EXPECT_APPROX_EQ(params.test_link.bandwidth,
+ sender_->ExportDebugState().bandwidth_hi, 0.9f);
+}
+
// Test the number of losses incurred by the startup phase in a situation when
// the buffer is less than BDP.
TEST_F(Bbr2DefaultTopologyTest, PacketLossOnSmallBufferStartup) {
@@ -911,7 +1411,10 @@ TEST_F(Bbr2DefaultTopologyTest, StartupStats) {
ASSERT_FALSE(sender_->InSlowStart());
const QuicConnectionStats& stats = sender_connection_stats();
- EXPECT_EQ(1u, stats.slowstart_count);
+ // The test explicitly replaces the default-created send algorithm with the
+ // one created by the test. slowstart_count increaments every time a BBR
+ // sender is created.
+ EXPECT_GE(stats.slowstart_count, 1u);
EXPECT_FALSE(stats.slowstart_duration.IsRunning());
EXPECT_THAT(stats.slowstart_duration.GetTotalElapsedTime(),
AllOf(Ge(QuicTime::Delta::FromMilliseconds(500)),
@@ -1381,6 +1884,12 @@ class Bbr2MultiSenderTest : public Bbr2SimulatorTest {
kDefaultInitialCwndPackets,
GetQuicFlag(FLAGS_quic_max_congestion_window), &random_,
QuicConnectionPeer::GetStats(endpoint->connection()), nullptr);
+ if (GetQuicReloadableFlag(
+ quic_bbr_start_new_aggregation_epoch_after_a_full_round)) {
+ // TODO(ianswett): Add dedicated tests for this option until it becomes
+ // the default behavior.
+ SetConnectionOption(sender, kBBRA);
+ }
QuicConnectionPeer::SetSendAlgorithm(endpoint->connection(), sender);
endpoint->RecordTrace();
return sender;
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 1bd89c6024f..f882c02f599 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
@@ -17,12 +17,12 @@ Bbr2StartupMode::Bbr2StartupMode(const Bbr2Sender* sender,
Bbr2NetworkModel* model,
QuicTime now)
: Bbr2ModeBase(sender, model) {
- // Clear some startup stats if |sender_->connection_stats_| has been used by
- // another sender, which happens e.g. when QuicConnection switch send
- // algorithms.
- sender_->connection_stats_->slowstart_count = 1;
- sender_->connection_stats_->slowstart_duration = QuicTimeAccumulator();
- sender_->connection_stats_->slowstart_duration.Start(now);
+ // Increment, instead of reset startup stats, so we don't lose data recorded
+ // before QuicConnection switched send algorithm to BBRv2.
+ ++sender_->connection_stats_->slowstart_count;
+ if (!sender_->connection_stats_->slowstart_duration.IsRunning()) {
+ sender_->connection_stats_->slowstart_duration.Start(now);
+ }
// Enter() is never called for Startup, so the gains needs to be set here.
model_->set_pacing_gain(Params().startup_pacing_gain);
model_->set_cwnd_gain(Params().startup_cwnd_gain);
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 940fe260731..ba7a35716a7 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
@@ -278,6 +278,17 @@ void BbrSender::ApplyConnectionOptions(
if (ContainsQuicTag(connection_options, kBSAO)) {
sampler_.EnableOverestimateAvoidance();
}
+ if (GetQuicReloadableFlag(
+ quic_bbr_start_new_aggregation_epoch_after_a_full_round) &&
+ ContainsQuicTag(connection_options, kBBRA)) {
+ sampler_.SetStartNewAggregationEpochAfterFullRound(true);
+ }
+ if (GetQuicReloadableFlag(quic_bbr_use_send_rate_in_max_ack_height_tracker) &&
+ ContainsQuicTag(connection_options, kBBRB)) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(
+ quic_bbr_use_send_rate_in_max_ack_height_tracker, 1, 2);
+ sampler_.SetLimitMaxAckHeightTrackerBySendRate(true);
+ }
}
void BbrSender::AdjustNetworkParameters(const NetworkParams& params) {
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 c1dbd22216e..ea6410ff753 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
@@ -185,16 +185,10 @@ class QUIC_EXPORT_PRIVATE BbrSender : public SendAlgorithmInterface {
QuicRoundTripCount,
QuicRoundTripCount>;
- // Returns whether the connection has achieved full bandwidth required to exit
- // the slow start.
- bool IsAtFullBandwidth() const;
// Computes the target congestion window using the specified gain.
QuicByteCount GetTargetCongestionWindow(float gain) const;
// The target congestion window during PROBE_RTT.
QuicByteCount ProbeRttCongestionWindow() const;
- // Returns true if the current min_rtt should be kept and we should not enter
- // PROBE_RTT immediately.
- bool ShouldExtendMinRttExpiry() const;
bool MaybeUpdateMinRtt(QuicTime now, QuicTime::Delta sample_min_rtt);
// Enters the STARTUP mode.
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 4a5cb0f0092..754cf20dfa7 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
@@ -10,6 +10,7 @@
#include <utility>
#include "quic/core/congestion_control/rtt_stats.h"
+#include "quic/core/crypto/crypto_protocol.h"
#include "quic/core/quic_bandwidth.h"
#include "quic/core/quic_packets.h"
#include "quic/core/quic_types.h"
@@ -109,7 +110,13 @@ class BbrSenderTest : public QuicTest {
receiver_multiplexer_("Receiver multiplexer",
{&receiver_, &competing_receiver_}) {
rtt_stats_ = bbr_sender_.connection()->sent_packet_manager().GetRttStats();
+ const int kTestMaxPacketSize = 1350;
+ bbr_sender_.connection()->SetMaxPacketLength(kTestMaxPacketSize);
sender_ = SetupBbrSender(&bbr_sender_);
+ if (GetQuicReloadableFlag(
+ quic_bbr_start_new_aggregation_epoch_after_a_full_round)) {
+ SetConnectionOption(kBBRA);
+ }
clock_ = simulator_.GetClock();
}
@@ -322,6 +329,39 @@ TEST_F(BbrSenderTest, SimpleTransfer) {
EXPECT_APPROX_EQ(kTestRtt, rtt_stats_->smoothed_rtt(), 0.2f);
}
+TEST_F(BbrSenderTest, SimpleTransferBBRB) {
+ SetQuicReloadableFlag(quic_bbr_use_send_rate_in_max_ack_height_tracker, true);
+ SetConnectionOption(kBBRB);
+ CreateDefaultSetup();
+
+ // At startup make sure we are at the default.
+ EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow());
+ // At startup make sure we can send.
+ EXPECT_TRUE(sender_->CanSend(0));
+ // And that window is un-affected.
+ EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow());
+
+ // Verify that Sender is in slow start.
+ EXPECT_TRUE(sender_->InSlowStart());
+
+ // Verify that pacing rate is based on the initial RTT.
+ QuicBandwidth expected_pacing_rate = QuicBandwidth::FromBytesAndTimeDelta(
+ 2.885 * kDefaultWindowTCP, rtt_stats_->initial_rtt());
+ EXPECT_APPROX_EQ(expected_pacing_rate.ToBitsPerSecond(),
+ sender_->PacingRate(0).ToBitsPerSecond(), 0.01f);
+
+ ASSERT_GE(kTestBdp, kDefaultWindowTCP + kDefaultTCPMSS);
+
+ DoSimpleTransfer(12 * 1024 * 1024, QuicTime::Delta::FromSeconds(30));
+ EXPECT_EQ(BbrSender::PROBE_BW, sender_->ExportDebugState().mode);
+ EXPECT_EQ(0u, bbr_sender_.connection()->GetStats().packets_lost);
+ EXPECT_FALSE(sender_->ExportDebugState().last_sample_is_app_limited);
+
+ // The margin here is quite high, since there exists a possibility that the
+ // connection just exited high gain cycle.
+ EXPECT_APPROX_EQ(kTestRtt, rtt_stats_->smoothed_rtt(), 0.2f);
+}
+
// Test a simple transfer in a situation when the buffer is less than BDP.
TEST_F(BbrSenderTest, SimpleTransferSmallBuffer) {
CreateSmallBufferSetup();
diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/pacing_sender.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/pacing_sender.cc
index 265a422817d..e4b6534e6fc 100644
--- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/pacing_sender.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/pacing_sender.cc
@@ -97,7 +97,8 @@ void PacingSender::OnPacketSent(
GetQuicFlag(FLAGS_quic_lumpy_pacing_cwnd_fraction)) /
kDefaultTCPMSS)));
if (sender_->BandwidthEstimate() <
- QuicBandwidth::FromKBitsPerSecond(1200)) {
+ QuicBandwidth::FromKBitsPerSecond(
+ GetQuicFlag(FLAGS_quic_lumpy_pacing_min_bandwidth_kbps))) {
// Below 1.2Mbps, send 1 packet at once, because one full-sized packet
// is about 10ms of queueing.
lumpy_tokens_ = 1u;
diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_test.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_test.cc
index 4272c0bb173..d4c607063ac 100644
--- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_test.cc
@@ -175,6 +175,8 @@ class SendAlgorithmTest : public QuicTestWithParam<TestParams> {
quic_sender_.RecordTrace();
QuicConnectionPeer::SetSendAlgorithm(quic_sender_.connection(), sender_);
+ const int kTestMaxPacketSize = 1350;
+ quic_sender_.connection()->SetMaxPacketLength(kTestMaxPacketSize);
clock_ = simulator_.GetClock();
simulator_.set_random_generator(&random_);
diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/windowed_filter.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/windowed_filter.h
index 8949a9cab9a..a777ac5fc74 100644
--- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/windowed_filter.h
+++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/windowed_filter.h
@@ -71,6 +71,7 @@ class QUIC_EXPORT_PRIVATE WindowedFilter {
WindowedFilter(TimeDeltaT window_length, T zero_value, TimeT zero_time)
: window_length_(window_length),
zero_value_(zero_value),
+ zero_time_(zero_time),
estimates_{Sample(zero_value_, zero_time),
Sample(zero_value_, zero_time),
Sample(zero_value_, zero_time)} {}
@@ -138,6 +139,8 @@ class QUIC_EXPORT_PRIVATE WindowedFilter {
Sample(new_sample, new_time);
}
+ void Clear() { Reset(zero_value_, zero_time_); }
+
T GetBest() const { return estimates_[0].sample; }
T GetSecondBest() const { return estimates_[1].sample; }
T GetThirdBest() const { return estimates_[2].sample; }
@@ -152,6 +155,7 @@ class QUIC_EXPORT_PRIVATE WindowedFilter {
TimeDeltaT window_length_; // Time length of window.
T zero_value_; // Uninitialized value of T.
+ TimeT zero_time_; // Uninitialized value of TimeT.
Sample estimates_[3]; // Best estimate is element 0.
};
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 d594f487549..f0bcd7f723e 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h
@@ -28,7 +28,8 @@ using ServerConfigID = std::string;
// The following tags have been deprecated and should not be reused:
// "1CON", "BBQ4", "NCON", "RCID", "SREJ", "TBKP", "TB10", "SCLS", "SMHL",
-// "QNZR", "B2HI", "H2PR", "FIFO", "LIFO", "RRWS", "QNSP", "B2CL"
+// "QNZR", "B2HI", "H2PR", "FIFO", "LIFO", "RRWS", "QNSP", "B2CL", "CHSP",
+// "BPTE", "ACKD", "AKD2", "AKD4", "MAD1", "MAD4", "MAD5", "ACD0", "ACKQ"
// clang-format off
const QuicTag kCHLO = TAG('C', 'H', 'L', 'O'); // Client hello
@@ -98,6 +99,11 @@ const QuicTag kBBR3 = TAG('B', 'B', 'R', '3'); // Fully drain the queue once
const QuicTag kBBR4 = TAG('B', 'B', 'R', '4'); // 20 RTT ack aggregation
const QuicTag kBBR5 = TAG('B', 'B', 'R', '5'); // 40 RTT ack aggregation
const QuicTag kBBR9 = TAG('B', 'B', 'R', '9'); // DEPRECATED
+const QuicTag kBBRA = TAG('B', 'B', 'R', 'A'); // Starts a new ack aggregation
+ // epoch if a full round has
+ // passed
+const QuicTag kBBRB = TAG('B', 'B', 'R', 'B'); // Use send rate in BBR's
+ // MaxAckHeightTracker
const QuicTag kBBRS = TAG('B', 'B', 'R', 'S'); // DEPRECATED
const QuicTag kBBQ1 = TAG('B', 'B', 'Q', '1'); // BBR with lower 2.77 STARTUP
// pacing and CWND gain.
@@ -115,6 +121,8 @@ const QuicTag kBBQ7 = TAG('B', 'B', 'Q', '7'); // Reduce bw_lo by
const QuicTag kBBQ8 = TAG('B', 'B', 'Q', '8'); // Reduce bw_lo by
// bw_lo * bytes_lost/inflight
const QuicTag kBBQ9 = TAG('B', 'B', 'Q', '9'); // Reduce bw_lo by
+const QuicTag kBBQ0 = TAG('B', 'B', 'Q', '0'); // Increase bytes_acked in
+ // PROBE_UP when app limited.
// bw_lo * bytes_lost/cwnd
const QuicTag kRENO = TAG('R', 'E', 'N', 'O'); // Reno Congestion Control
const QuicTag kTPCC = TAG('P', 'C', 'C', '\0'); // Performance-Oriented
@@ -150,6 +158,18 @@ const QuicTag kBSAO = TAG('B', 'S', 'A', 'O'); // Avoid Overestimation in
// aggregation
const QuicTag kB2DL = TAG('B', '2', 'D', 'L'); // Increase inflight_hi based
// on delievered, not inflight.
+const QuicTag kB201 = TAG('B', '2', '0', '1'); // In PROBE_UP, check if cwnd
+ // limited before aggregation
+ // epoch, instead of ack event.
+const QuicTag kB202 = TAG('B', '2', '0', '2'); // Do not exit PROBE_UP if
+ // inflight dips below 1.25*BW.
+const QuicTag kB203 = TAG('B', '2', '0', '3'); // Ignore inflight_hi until
+ // PROBE_UP is exited.
+const QuicTag kB206 = TAG('B', '2', '0', '6'); // Exit STARTUP after 2 losses.
+const QuicTag kB204 = TAG('B', '2', '0', '4'); // Reduce extra acked when
+ // MaxBW incrases.
+const QuicTag kB205 = TAG('B', '2', '0', '5'); // Add extra acked to CWND in
+ // STARTUP.
const QuicTag kNTLP = TAG('N', 'T', 'L', 'P'); // No tail loss probe
const QuicTag k1TLP = TAG('1', 'T', 'L', 'P'); // 1 tail loss probe
const QuicTag k1RTO = TAG('1', 'R', 'T', 'O'); // Send 1 packet upon RTO
@@ -162,24 +182,13 @@ const QuicTag kMIN4 = TAG('M', 'I', 'N', '4'); // Min CWND of 4 packets,
const QuicTag kTLPR = TAG('T', 'L', 'P', 'R'); // Tail loss probe delay of
// 0.5RTT.
const QuicTag kMAD0 = TAG('M', 'A', 'D', '0'); // Ignore ack delay
-const QuicTag kMAD1 = TAG('M', 'A', 'D', '1'); // 25ms initial max ack delay
const QuicTag kMAD2 = TAG('M', 'A', 'D', '2'); // No min TLP
const QuicTag kMAD3 = TAG('M', 'A', 'D', '3'); // No min RTO
-const QuicTag kMAD4 = TAG('M', 'A', 'D', '4'); // IETF style TLP
-const QuicTag kMAD5 = TAG('M', 'A', 'D', '5'); // IETF style TLP with 2x mult
const QuicTag k1ACK = TAG('1', 'A', 'C', 'K'); // 1 fast ack for reordering
-const QuicTag kACD0 = TAG('A', 'D', 'D', '0'); // Disable ack decimation
-const QuicTag kACKD = TAG('A', 'C', 'K', 'D'); // Ack decimation style acking.
-const QuicTag kAKD2 = TAG('A', 'K', 'D', '2'); // Ack decimation tolerating
- // out of order packets.
const QuicTag kAKD3 = TAG('A', 'K', 'D', '3'); // Ack decimation style acking
// with 1/8 RTT acks.
-const QuicTag kAKD4 = TAG('A', 'K', 'D', '4'); // Ack decimation with 1/8 RTT
- // tolerating out of order.
const QuicTag kAKDU = TAG('A', 'K', 'D', 'U'); // Unlimited number of packets
// received before acking
-const QuicTag kACKQ = TAG('A', 'C', 'K', 'Q'); // Send an immediate ack after
- // 1 RTT of not receiving.
const QuicTag kAFFE = TAG('A', 'F', 'F', 'E'); // Enable client receiving
// AckFrequencyFrame.
const QuicTag kAFF1 = TAG('A', 'F', 'F', '1'); // Use SRTT in building
@@ -265,6 +274,8 @@ const QuicTag kAPTO = TAG('A', 'P', 'T', 'O'); // Use 1.5 * initial RTT before
const QuicTag kELDT = TAG('E', 'L', 'D', 'T'); // Enable Loss Detection Tuning
+// TODO(haoyuewang) Remove RVCM option once
+// --quic_remove_connection_migration_connection_option is deprecated.
const QuicTag kRVCM = TAG('R', 'V', 'C', 'M'); // Validate the new address
// upon client address change.
@@ -340,8 +351,8 @@ const QuicTag kMTUL = TAG('M', 'T', 'U', 'L'); // Low-target MTU discovery.
const QuicTag kNSLC = TAG('N', 'S', 'L', 'C'); // Always send connection close
// for idle timeout.
-const QuicTag kCHSP = TAG('C', 'H', 'S', 'P'); // Chaos protection.
-const QuicTag kBPTE = TAG('B', 'P', 'T', 'E'); // BoringSSL Permutes
+const QuicTag kNCHP = TAG('N', 'C', 'H', 'P'); // No chaos protection.
+const QuicTag kNBPE = TAG('N', 'B', 'P', 'E'); // No BoringSSL Permutes
// TLS Extensions.
// Proof types (i.e. certificate types)
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils.cc
index 9c12d8cf309..2f1fa3480c2 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils.cc
@@ -542,35 +542,6 @@ bool CryptoUtils::DeriveKeys(const ParsedQuicVersion& version,
}
// static
-bool CryptoUtils::ExportKeyingMaterial(absl::string_view subkey_secret,
- absl::string_view label,
- absl::string_view context,
- size_t result_len,
- std::string* result) {
- for (size_t i = 0; i < label.length(); i++) {
- if (label[i] == '\0') {
- QUIC_LOG(ERROR) << "ExportKeyingMaterial label may not contain NULs";
- return false;
- }
- }
- // Create HKDF info input: null-terminated label + length-prefixed context
- if (context.length() >= std::numeric_limits<uint32_t>::max()) {
- QUIC_LOG(ERROR) << "Context value longer than 2^32";
- return false;
- }
- uint32_t context_length = static_cast<uint32_t>(context.length());
- std::string info = std::string(label);
- info.push_back('\0');
- info.append(reinterpret_cast<char*>(&context_length), sizeof(context_length));
- info.append(context.data(), context.length());
-
- QuicHKDF hkdf(subkey_secret, absl::string_view() /* no salt */, info,
- result_len, 0 /* no fixed IV */, 0 /* no subkey secret */);
- *result = std::string(hkdf.client_write_key());
- return true;
-}
-
-// static
uint64_t CryptoUtils::ComputeLeafCertHash(absl::string_view cert) {
return QuicUtils::FNV1a_64_Hash(cert);
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils.h b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils.h
index 7aa32e1445a..15ffe064ea6 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils.h
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils.h
@@ -166,16 +166,6 @@ class QUIC_EXPORT_PRIVATE CryptoUtils {
CrypterPair* crypters,
std::string* subkey_secret);
- // Performs key extraction to derive a new secret of |result_len| bytes
- // dependent on |subkey_secret|, |label|, and |context|. Returns false if the
- // parameters are invalid (e.g. |label| contains null bytes); returns true on
- // success.
- static bool ExportKeyingMaterial(absl::string_view subkey_secret,
- absl::string_view label,
- absl::string_view context,
- size_t result_len,
- std::string* result);
-
// Computes the FNV-1a hash of the provided DER-encoded cert for use in the
// XLCT tag.
static uint64_t ComputeLeafCertHash(absl::string_view cert);
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils_test.cc
index 0f2df3a7f90..6c3d3846f82 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils_test.cc
@@ -19,63 +19,6 @@ namespace {
class CryptoUtilsTest : public QuicTest {};
-TEST_F(CryptoUtilsTest, TestExportKeyingMaterial) {
- const struct TestVector {
- // Input (strings of hexadecimal digits):
- const char* subkey_secret;
- const char* label;
- const char* context;
- size_t result_len;
-
- // Expected output (string of hexadecimal digits):
- const char* expected; // Null if it should fail.
- } test_vector[] = {
- // Try a typical input
- {"4823c1189ecc40fce888fbb4cf9ae6254f19ba12e6d9af54788f195a6f509ca3",
- "e934f78d7a71dd85420fceeb8cea0317",
- "b8d766b5d3c8aba0009c7ed3de553eba53b4de1030ea91383dcdf724cd8b7217", 32,
- "a9979da0d5f1c1387d7cbe68f5c4163ddb445a03c4ad6ee72cb49d56726d679e"},
- // Don't let the label contain nulls
- {"14fe51e082ffee7d1b4d8d4ab41f8c55", "3132333435363700",
- "58585858585858585858585858585858", 16, nullptr},
- // Make sure nulls in the context are fine
- {"d862c2e36b0a42f7827c67ebc8d44df7", "7a5b95e4e8378123",
- "4142434445464700", 16, "12d418c6d0738a2e4d85b2d0170f76e1"},
- // ... and give a different result than without
- {"d862c2e36b0a42f7827c67ebc8d44df7", "7a5b95e4e8378123", "41424344454647",
- 16, "abfa1c479a6e3ffb98a11dee7d196408"},
- // Try weird lengths
- {"d0ec8a34f6cc9a8c96", "49711798cc6251",
- "933d4a2f30d22f089cfba842791116adc121e0", 23,
- "c9a46ed0757bd1812f1f21b4d41e62125fec8364a21db7"},
- };
-
- for (size_t i = 0; i < ABSL_ARRAYSIZE(test_vector); i++) {
- // Decode the test vector.
- std::string subkey_secret =
- absl::HexStringToBytes(test_vector[i].subkey_secret);
- std::string label = absl::HexStringToBytes(test_vector[i].label);
- std::string context = absl::HexStringToBytes(test_vector[i].context);
- size_t result_len = test_vector[i].result_len;
- bool expect_ok = test_vector[i].expected != nullptr;
- std::string expected;
- if (expect_ok) {
- expected = absl::HexStringToBytes(test_vector[i].expected);
- }
-
- std::string result;
- bool ok = CryptoUtils::ExportKeyingMaterial(subkey_secret, label, context,
- result_len, &result);
- EXPECT_EQ(expect_ok, ok);
- if (expect_ok) {
- EXPECT_EQ(result_len, result.length());
- quiche::test::CompareCharArraysWithHexError(
- "HKDF output", result.data(), result.length(), expected.data(),
- expected.length());
- }
- }
-}
-
TEST_F(CryptoUtilsTest, HandshakeFailureReasonToString) {
EXPECT_STREQ("HANDSHAKE_OK",
CryptoUtils::HandshakeFailureReasonToString(HANDSHAKE_OK));
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 b0a24468a23..c4a1f2c53dc 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
@@ -145,10 +145,13 @@ class QUIC_EXPORT_PRIVATE ProofSource {
std::unique_ptr<Callback> callback) = 0;
// Returns the certificate chain for |hostname| in leaf-first order.
+ //
+ // Sets *cert_matched_sni to true if the certificate matched the given
+ // hostname, false if a default cert not matching the hostname was used.
virtual QuicReferenceCountedPointer<Chain> GetCertChain(
const QuicSocketAddress& server_address,
- const QuicSocketAddress& client_address,
- const std::string& hostname) = 0;
+ const QuicSocketAddress& client_address, const std::string& hostname,
+ bool* cert_matched_sni) = 0;
// Computes a signature using the private key of the certificate for
// |hostname|. The value in |in| is signed using the algorithm specified by
@@ -247,13 +250,16 @@ class QUIC_EXPORT_PRIVATE ProofSourceHandleCallback {
// SSL_set_handshake_hints.
// |ticket_encryption_key| (optional) encryption key to be used for minting
// TLS resumption tickets.
+ // |cert_matched_sni| is true if the certificate matched the SNI hostname,
+ // false if a non-matching default cert was used.
//
// When called asynchronously(is_sync=false), this method will be responsible
// to continue the handshake from where it left off.
- virtual void OnSelectCertificateDone(
- bool ok, bool is_sync, const ProofSource::Chain* chain,
- absl::string_view handshake_hints,
- absl::string_view ticket_encryption_key) = 0;
+ virtual void OnSelectCertificateDone(bool ok, bool is_sync,
+ const ProofSource::Chain* chain,
+ absl::string_view handshake_hints,
+ absl::string_view ticket_encryption_key,
+ bool cert_matched_sni) = 0;
// Called when a ProofSourceHandle::ComputeSignature operation completes.
virtual void OnComputeSignatureDone(
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
index c7acd0056bc..986ee32ae05 100644
--- 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
@@ -53,7 +53,7 @@ void ProofSourceX509::GetProof(
return;
}
- Certificate* certificate = GetCertificate(hostname);
+ Certificate* certificate = GetCertificate(hostname, &proof.cert_matched_sni);
proof.signature =
certificate->key.Sign(absl::string_view(payload.get(), payload_size),
SSL_SIGN_RSA_PSS_RSAE_SHA256);
@@ -63,9 +63,9 @@ void ProofSourceX509::GetProof(
QuicReferenceCountedPointer<ProofSource::Chain> ProofSourceX509::GetCertChain(
const QuicSocketAddress& /*server_address*/,
- const QuicSocketAddress& /*client_address*/,
- const std::string& hostname) {
- return GetCertificate(hostname)->chain;
+ const QuicSocketAddress& /*client_address*/, const std::string& hostname,
+ bool* cert_matched_sni) {
+ return GetCertificate(hostname, cert_matched_sni)->chain;
}
void ProofSourceX509::ComputeTlsSignature(
@@ -75,8 +75,9 @@ void ProofSourceX509::ComputeTlsSignature(
uint16_t signature_algorithm,
absl::string_view in,
std::unique_ptr<ProofSource::SignatureCallback> callback) {
- std::string signature =
- GetCertificate(hostname)->key.Sign(in, signature_algorithm);
+ bool cert_matched_sni;
+ std::string signature = GetCertificate(hostname, &cert_matched_sni)
+ ->key.Sign(in, signature_algorithm);
callback->Run(/*ok=*/!signature.empty(), signature, nullptr);
}
@@ -125,9 +126,10 @@ bool ProofSourceX509::AddCertificateChain(
}
ProofSourceX509::Certificate* ProofSourceX509::GetCertificate(
- const std::string& hostname) const {
+ const std::string& hostname, bool* cert_matched_sni) const {
auto it = certificate_map_.find(hostname);
if (it != certificate_map_.end()) {
+ *cert_matched_sni = true;
return it->second;
}
auto dot_pos = hostname.find('.');
@@ -135,9 +137,11 @@ ProofSourceX509::Certificate* ProofSourceX509::GetCertificate(
std::string wildcard = absl::StrCat("*", hostname.substr(dot_pos));
it = certificate_map_.find(wildcard);
if (it != certificate_map_.end()) {
+ *cert_matched_sni = true;
return it->second;
}
}
+ *cert_matched_sni = false;
return default_certificate_;
}
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
index 9ac676939a3..4b7ae51c83b 100644
--- 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
@@ -37,8 +37,8 @@ class QUIC_EXPORT_PRIVATE ProofSourceX509 : public ProofSource {
std::unique_ptr<Callback> callback) override;
QuicReferenceCountedPointer<Chain> GetCertChain(
const QuicSocketAddress& server_address,
- const QuicSocketAddress& client_address,
- const std::string& hostname) override;
+ const QuicSocketAddress& client_address, const std::string& hostname,
+ bool* cert_matched_sni) override;
void ComputeTlsSignature(
const QuicSocketAddress& server_address,
const QuicSocketAddress& client_address, const std::string& hostname,
@@ -65,7 +65,8 @@ class QUIC_EXPORT_PRIVATE ProofSourceX509 : public ProofSource {
// Looks up certficiate for hostname, returns the default if no certificate is
// found.
- Certificate* GetCertificate(const std::string& hostname) const;
+ Certificate* GetCertificate(const std::string& hostname,
+ bool* cert_matched_sni) const;
std::forward_list<Certificate> certificates_;
Certificate* default_certificate_;
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
index 75a60993e15..1a9462f7dc3 100644
--- 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
@@ -58,8 +58,7 @@ TEST_F(ProofSourceX509Test, AddCertificateKeyMismatch) {
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(
+ EXPECT_QUIC_BUG((void)proof_source->AddCertificateChain(
wildcard_chain_, std::move(*test_key_)),
"Private key does not match");
}
@@ -72,40 +71,47 @@ TEST_F(ProofSourceX509Test, CertificateSelection) {
std::move(*wildcard_key_)));
// Default certificate.
+ bool cert_matched_sni;
EXPECT_EQ(proof_source
->GetCertChain(QuicSocketAddress(), QuicSocketAddress(),
- "unknown.test")
+ "unknown.test", &cert_matched_sni)
->certs[0],
kTestCertificate);
+ EXPECT_FALSE(cert_matched_sni);
// mail.example.org is explicitly a SubjectAltName in kTestCertificate.
EXPECT_EQ(proof_source
->GetCertChain(QuicSocketAddress(), QuicSocketAddress(),
- "mail.example.org")
+ "mail.example.org", &cert_matched_sni)
->certs[0],
kTestCertificate);
+ EXPECT_TRUE(cert_matched_sni);
// www.foo.test is in kWildcardCertificate.
EXPECT_EQ(proof_source
->GetCertChain(QuicSocketAddress(), QuicSocketAddress(),
- "www.foo.test")
+ "www.foo.test", &cert_matched_sni)
->certs[0],
kWildcardCertificate);
+ EXPECT_TRUE(cert_matched_sni);
// *.wildcard.test is in kWildcardCertificate.
EXPECT_EQ(proof_source
->GetCertChain(QuicSocketAddress(), QuicSocketAddress(),
- "www.wildcard.test")
+ "www.wildcard.test", &cert_matched_sni)
->certs[0],
kWildcardCertificate);
+ EXPECT_TRUE(cert_matched_sni);
EXPECT_EQ(proof_source
->GetCertChain(QuicSocketAddress(), QuicSocketAddress(),
- "etc.wildcard.test")
+ "etc.wildcard.test", &cert_matched_sni)
->certs[0],
kWildcardCertificate);
+ EXPECT_TRUE(cert_matched_sni);
// wildcard.test itself is not in kWildcardCertificate.
EXPECT_EQ(proof_source
->GetCertChain(QuicSocketAddress(), QuicSocketAddress(),
- "wildcard.test")
+ "wildcard.test", &cert_matched_sni)
->certs[0],
kTestCertificate);
+ EXPECT_FALSE(cert_matched_sni);
}
TEST_F(ProofSourceX509Test, TlsSignature) {
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_proof.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_proof.cc
index 033ef3292b0..1e5f3c4a965 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_proof.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_proof.cc
@@ -6,6 +6,7 @@
namespace quic {
-QuicCryptoProof::QuicCryptoProof() : send_expect_ct_header(false) {}
+QuicCryptoProof::QuicCryptoProof()
+ : send_expect_ct_header(false), cert_matched_sni(false) {}
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_proof.h b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_proof.h
index 6ca87fb0a33..53e09612857 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_proof.h
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_proof.h
@@ -22,6 +22,9 @@ struct QUIC_EXPORT_PRIVATE QuicCryptoProof {
// Should the Expect-CT header be sent on the connection where the
// certificate is used.
bool send_expect_ct_header;
+ // Did the selected leaf certificate contain a SubjectAltName that included
+ // the requested SNI.
+ bool cert_matched_sni;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.cc
index f2a88095aac..e2b4b93ef27 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
@@ -29,12 +29,10 @@
#include "quic/core/crypto/key_exchange.h"
#include "quic/core/crypto/p256_key_exchange.h"
#include "quic/core/crypto/proof_source.h"
-#include "quic/core/crypto/proof_verifier.h"
#include "quic/core/crypto/quic_decrypter.h"
#include "quic/core/crypto/quic_encrypter.h"
#include "quic/core/crypto/quic_hkdf.h"
#include "quic/core/crypto/quic_random.h"
-#include "quic/core/crypto/server_proof_verifier.h"
#include "quic/core/crypto/tls_server_connection.h"
#include "quic/core/proto/crypto_server_config_proto.h"
#include "quic/core/proto/source_address_token_proto.h"
@@ -244,7 +242,6 @@ QuicCryptoServerConfig::QuicCryptoServerConfig(
primary_config_(nullptr),
next_config_promotion_time_(QuicWallTime::Zero()),
proof_source_(std::move(proof_source)),
- client_cert_mode_(ClientCertMode::kNone),
key_exchange_source_(std::move(key_exchange_source)),
ssl_ctx_(TlsServerConnection::CreateSslCtx(proof_source_.get())),
source_address_token_future_secs_(3600),
@@ -1628,15 +1625,6 @@ QuicCryptoServerConfig::ParseConfigProtobuf(
static_assert(sizeof(config->orbit) == kOrbitSize, "incorrect orbit size");
memcpy(config->orbit, orbit.data(), sizeof(config->orbit));
- if ((kexs_tags.size() != static_cast<size_t>(protobuf.key_size())) &&
- (!GetQuicRestartFlag(dont_fetch_quic_private_keys_from_leto) &&
- protobuf.key_size() == 0)) {
- QUIC_LOG(WARNING) << "Server config has " << kexs_tags.size()
- << " key exchange methods configured, but "
- << protobuf.key_size() << " private keys";
- return nullptr;
- }
-
QuicTagVector proof_demand_tags;
if (msg->GetTaglist(kPDMD, &proof_demand_tags) == QUIC_NO_ERROR) {
for (QuicTag tag : proof_demand_tags) {
@@ -1761,23 +1749,6 @@ ProofSource* QuicCryptoServerConfig::proof_source() const {
return proof_source_.get();
}
-ServerProofVerifier* QuicCryptoServerConfig::proof_verifier() const {
- return proof_verifier_.get();
-}
-
-void QuicCryptoServerConfig::set_proof_verifier(
- std::unique_ptr<ServerProofVerifier> proof_verifier) {
- proof_verifier_ = std::move(proof_verifier);
-}
-
-ClientCertMode QuicCryptoServerConfig::client_cert_mode() const {
- return client_cert_mode_;
-}
-
-void QuicCryptoServerConfig::set_client_cert_mode(ClientCertMode mode) {
- client_cert_mode_ = mode;
-}
-
SSL_CTX* QuicCryptoServerConfig::ssl_ctx() const {
return ssl_ctx_.get();
}
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 15ce0f276d7..d8e77e6d6de 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
@@ -20,10 +20,8 @@
#include "quic/core/crypto/crypto_secret_boxer.h"
#include "quic/core/crypto/key_exchange.h"
#include "quic/core/crypto/proof_source.h"
-#include "quic/core/crypto/proof_verifier.h"
#include "quic/core/crypto/quic_compressed_certs_cache.h"
#include "quic/core/crypto/quic_crypto_proof.h"
-#include "quic/core/crypto/server_proof_verifier.h"
#include "quic/core/proto/cached_network_parameters_proto.h"
#include "quic/core/proto/source_address_token_proto.h"
#include "quic/core/quic_time.h"
@@ -455,11 +453,6 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerConfig {
}
ProofSource* proof_source() const;
- ServerProofVerifier* proof_verifier() const;
- void set_proof_verifier(std::unique_ptr<ServerProofVerifier> proof_verifier);
-
- ClientCertMode client_cert_mode() const;
- void set_client_cert_mode(ClientCertMode client_cert_mode);
SSL_CTX* ssl_ctx() const;
@@ -920,8 +913,6 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerConfig {
// proof_source_ contains an object that can provide certificate chains and
// signatures.
std::unique_ptr<ProofSource> proof_source_;
- std::unique_ptr<ServerProofVerifier> proof_verifier_;
- ClientCertMode client_cert_mode_;
// key_exchange_source_ contains an object that can provide key exchange
// objects.
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/tls_client_connection.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/tls_client_connection.cc
index dd53ee7037c..bfd20b26c3b 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/tls_client_connection.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/tls_client_connection.cc
@@ -17,9 +17,9 @@ TlsClientConnection::TlsClientConnection(SSL_CTX* ssl_ctx,
// static
bssl::UniquePtr<SSL_CTX> TlsClientConnection::CreateSslCtx(
bool enable_early_data) {
- bssl::UniquePtr<SSL_CTX> ssl_ctx =
- TlsConnection::CreateSslCtx(SSL_VERIFY_PEER);
+ bssl::UniquePtr<SSL_CTX> ssl_ctx = TlsConnection::CreateSslCtx();
// Configure certificate verification.
+ SSL_CTX_set_custom_verify(ssl_ctx.get(), SSL_VERIFY_PEER, &VerifyCallback);
int reverify_on_resume_enabled = 1;
SSL_CTX_set_reverify_on_resume(ssl_ctx.get(), reverify_on_resume_enabled);
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 7a66e2f8f8d..fa9be976f69 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
@@ -106,6 +106,11 @@ TlsConnection::TlsConnection(SSL_CTX* ssl_ctx,
ssl(), ssl_config_.signing_algorithm_prefs->data(),
ssl_config_.signing_algorithm_prefs->size());
}
+ if (ssl_config.disable_ticket_support.has_value()) {
+ if (*ssl_config.disable_ticket_support) {
+ SSL_set_options(ssl(), SSL_OP_NO_TICKET);
+ }
+ }
}
void TlsConnection::EnableInfoCallback() {
@@ -116,15 +121,12 @@ void TlsConnection::EnableInfoCallback() {
}
// static
-bssl::UniquePtr<SSL_CTX> TlsConnection::CreateSslCtx(int cert_verify_mode) {
+bssl::UniquePtr<SSL_CTX> TlsConnection::CreateSslCtx() {
CRYPTO_library_init();
bssl::UniquePtr<SSL_CTX> ssl_ctx(SSL_CTX_new(TLS_with_buffers_method()));
SSL_CTX_set_min_proto_version(ssl_ctx.get(), TLS1_3_VERSION);
SSL_CTX_set_max_proto_version(ssl_ctx.get(), TLS1_3_VERSION);
SSL_CTX_set_quic_method(ssl_ctx.get(), &kSslQuicMethod);
- if (cert_verify_mode != SSL_VERIFY_NONE) {
- SSL_CTX_set_custom_verify(ssl_ctx.get(), cert_verify_mode, &VerifyCallback);
- }
return ssl_ctx;
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/tls_connection.h b/chromium/net/third_party/quiche/src/quic/core/crypto/tls_connection.h
index f59eaa13150..c8d377e1745 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/tls_connection.h
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/tls_connection.h
@@ -108,12 +108,7 @@ class QUIC_EXPORT_PRIVATE TlsConnection {
// Creates an SSL_CTX and configures it with the options that are appropriate
// for both client and server. The caller is responsible for ownership of the
// newly created struct.
- //
- // The provided |cert_verify_mode| is passed in as the |mode| argument for
- // |SSL_CTX_set_verify|. See
- // https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#SSL_VERIFY_NONE
- // for a description of possible values.
- static bssl::UniquePtr<SSL_CTX> CreateSslCtx(int cert_verify_mode);
+ static bssl::UniquePtr<SSL_CTX> CreateSslCtx();
// From a given SSL* |ssl|, returns a pointer to the TlsConnection that it
// belongs to. This helper method allows the callbacks set in BoringSSL to be
@@ -121,11 +116,11 @@ class QUIC_EXPORT_PRIVATE TlsConnection {
// callback.
static TlsConnection* ConnectionFromSsl(const SSL* ssl);
- private:
- // Registered as the callback for SSL_CTX_set_custom_verify. The
+ // Registered as the callback for SSL(_CTX)_set_custom_verify. The
// implementation is delegated to Delegate::VerifyCert.
static enum ssl_verify_result_t VerifyCallback(SSL* ssl, uint8_t* out_alert);
+ private:
// TlsConnection implements SSL_QUIC_METHOD, which provides the interface
// between BoringSSL's TLS stack and a QUIC implementation.
static const SSL_QUIC_METHOD kSslQuicMethod;
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 2042c15aaf2..0da9bbc3e94 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
@@ -23,8 +23,12 @@ TlsServerConnection::TlsServerConnection(SSL_CTX* ssl_ctx,
// static
bssl::UniquePtr<SSL_CTX> TlsServerConnection::CreateSslCtx(
ProofSource* proof_source) {
- bssl::UniquePtr<SSL_CTX> ssl_ctx =
- TlsConnection::CreateSslCtx(SSL_VERIFY_NONE);
+ bssl::UniquePtr<SSL_CTX> ssl_ctx = TlsConnection::CreateSslCtx();
+
+ // Server does not request/verify client certs by default. Individual server
+ // connections may call SSL_set_custom_verify on their SSL object to request
+ // client certs.
+
SSL_CTX_set_tlsext_servername_callback(ssl_ctx.get(),
&TlsExtServernameCallback);
SSL_CTX_set_alpn_select_cb(ssl_ctx.get(), &SelectAlpnCallback, nullptr);
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 14df9c3a27c..75d4323bad4 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
@@ -22,6 +22,7 @@
#include "quic/core/quic_utils.h"
#include "quic/core/quic_versions.h"
#include "quic/platform/api/quic_bug_tracker.h"
+#include "quic/platform/api/quic_flag_utils.h"
namespace quic {
@@ -609,15 +610,25 @@ bool SerializeTransportParameters(ParsedQuicVersion /*version*/,
std::vector<uint8_t>* out) {
std::string error_details;
if (!in.AreValid(&error_details)) {
- QUIC_BUG(quic_bug_10743_5)
+ QUIC_BUG(invalid transport parameters)
<< "Not serializing invalid transport parameters: " << error_details;
return false;
}
if (in.version == 0 || (in.perspective == Perspective::IS_SERVER &&
in.supported_versions.empty())) {
- QUIC_BUG(quic_bug_10743_6) << "Refusing to serialize without versions";
+ QUIC_BUG(missing versions) << "Refusing to serialize without versions";
return false;
}
+ TransportParameters::ParameterMap custom_parameters = in.custom_parameters;
+ for (const auto& kv : custom_parameters) {
+ if (kv.first % 31 == 27) {
+ // See the "Reserved Transport Parameters" section of RFC 9000.
+ QUIC_BUG(custom_parameters with GREASE)
+ << "Serializing custom_parameters with GREASE ID " << kv.first
+ << " is not allowed";
+ return false;
+ }
+ }
// Maximum length of the GREASE transport parameter (see below).
static constexpr size_t kMaxGreaseLength = 16;
@@ -637,8 +648,6 @@ bool SerializeTransportParameters(ParsedQuicVersion /*version*/,
kTypeAndValueLength + 4 /*IPv4 address */ + 2 /* IPv4 port */ +
16 /* IPv6 address */ + 1 /* Connection ID length */ +
255 /* maximum connection ID length */ + 16 /* stateless reset token */;
- static constexpr size_t kGreaseParameterLength =
- kTypeAndValueLength + kMaxGreaseLength;
static constexpr size_t kKnownTransportParamLength =
kConnectionIdParameterLength + // original_destination_connection_id
kIntegerParameterLength + // max_idle_timeout
@@ -663,8 +672,34 @@ bool SerializeTransportParameters(ParsedQuicVersion /*version*/,
kTypeAndValueLength + // google_connection_options
kTypeAndValueLength + // user_agent_id
kTypeAndValueLength + // key_update_not_yet_supported
- kTypeAndValueLength + // google-version
- kGreaseParameterLength; // GREASE
+ kTypeAndValueLength; // google-version
+
+ std::vector<TransportParameters::TransportParameterId> parameter_ids = {
+ TransportParameters::kOriginalDestinationConnectionId,
+ TransportParameters::kMaxIdleTimeout,
+ TransportParameters::kStatelessResetToken,
+ TransportParameters::kMaxPacketSize,
+ TransportParameters::kInitialMaxData,
+ TransportParameters::kInitialMaxStreamDataBidiLocal,
+ TransportParameters::kInitialMaxStreamDataBidiRemote,
+ TransportParameters::kInitialMaxStreamDataUni,
+ TransportParameters::kInitialMaxStreamsBidi,
+ TransportParameters::kInitialMaxStreamsUni,
+ TransportParameters::kAckDelayExponent,
+ TransportParameters::kMaxAckDelay,
+ TransportParameters::kMinAckDelay,
+ TransportParameters::kActiveConnectionIdLimit,
+ TransportParameters::kMaxDatagramFrameSize,
+ TransportParameters::kInitialRoundTripTime,
+ TransportParameters::kDisableActiveMigration,
+ TransportParameters::kPreferredAddress,
+ TransportParameters::kInitialSourceConnectionId,
+ TransportParameters::kRetrySourceConnectionId,
+ TransportParameters::kGoogleConnectionOptions,
+ TransportParameters::kGoogleUserAgentId,
+ TransportParameters::kGoogleKeyUpdateNotYetSupported,
+ TransportParameters::kGoogleQuicVersion,
+ };
size_t max_transport_param_length = kKnownTransportParamLength;
// google_connection_options.
@@ -680,269 +715,386 @@ bool SerializeTransportParameters(ParsedQuicVersion /*version*/,
max_transport_param_length +=
sizeof(in.version) + 1 /* versions length */ +
in.supported_versions.size() * sizeof(QuicVersionLabel);
- // Custom parameters.
- for (const auto& kv : in.custom_parameters) {
- max_transport_param_length += kTypeAndValueLength + kv.second.length();
- }
-
- out->resize(max_transport_param_length);
- QuicDataWriter writer(out->size(), reinterpret_cast<char*>(out->data()));
-
- // original_destination_connection_id
- if (in.original_destination_connection_id.has_value()) {
- QUICHE_DCHECK_EQ(Perspective::IS_SERVER, in.perspective);
- QuicConnectionId original_destination_connection_id =
- in.original_destination_connection_id.value();
- if (!writer.WriteVarInt62(
- TransportParameters::kOriginalDestinationConnectionId) ||
- !writer.WriteStringPieceVarInt62(
- absl::string_view(original_destination_connection_id.data(),
- original_destination_connection_id.length()))) {
- QUIC_BUG(quic_bug_10743_7)
- << "Failed to write original_destination_connection_id "
- << original_destination_connection_id << " for " << in;
- return false;
- }
- }
-
- if (!in.max_idle_timeout_ms.Write(&writer)) {
- QUIC_BUG(quic_bug_10743_8) << "Failed to write idle_timeout for " << in;
- return false;
- }
-
- // stateless_reset_token
- if (!in.stateless_reset_token.empty()) {
- QUICHE_DCHECK_EQ(kStatelessResetTokenLength,
- in.stateless_reset_token.size());
- QUICHE_DCHECK_EQ(Perspective::IS_SERVER, in.perspective);
- if (!writer.WriteVarInt62(TransportParameters::kStatelessResetToken) ||
- !writer.WriteStringPieceVarInt62(absl::string_view(
- reinterpret_cast<const char*>(in.stateless_reset_token.data()),
- in.stateless_reset_token.size()))) {
- QUIC_BUG(quic_bug_10743_9)
- << "Failed to write stateless_reset_token of length "
- << in.stateless_reset_token.size() << " for " << in;
- return false;
- }
- }
-
- if (!in.max_udp_payload_size.Write(&writer) ||
- !in.initial_max_data.Write(&writer) ||
- !in.initial_max_stream_data_bidi_local.Write(&writer) ||
- !in.initial_max_stream_data_bidi_remote.Write(&writer) ||
- !in.initial_max_stream_data_uni.Write(&writer) ||
- !in.initial_max_streams_bidi.Write(&writer) ||
- !in.initial_max_streams_uni.Write(&writer) ||
- !in.ack_delay_exponent.Write(&writer) ||
- !in.max_ack_delay.Write(&writer) || !in.min_ack_delay_us.Write(&writer) ||
- !in.active_connection_id_limit.Write(&writer) ||
- !in.max_datagram_frame_size.Write(&writer) ||
- !in.initial_round_trip_time_us.Write(&writer)) {
- QUIC_BUG(quic_bug_10743_10) << "Failed to write integers for " << in;
- return false;
- }
-
- // disable_active_migration
- if (in.disable_active_migration) {
- if (!writer.WriteVarInt62(TransportParameters::kDisableActiveMigration) ||
- !writer.WriteVarInt62(/* transport parameter length */ 0)) {
- QUIC_BUG(quic_bug_10743_11)
- << "Failed to write disable_active_migration for " << in;
- return false;
- }
- }
- // preferred_address
- if (in.preferred_address) {
- std::string v4_address_bytes =
- in.preferred_address->ipv4_socket_address.host().ToPackedString();
- std::string v6_address_bytes =
- in.preferred_address->ipv6_socket_address.host().ToPackedString();
- if (v4_address_bytes.length() != 4 || v6_address_bytes.length() != 16 ||
- in.preferred_address->stateless_reset_token.size() !=
- kStatelessResetTokenLength) {
- QUIC_BUG(quic_bug_10743_12) << "Bad lengths " << *in.preferred_address;
- return false;
- }
- const uint64_t preferred_address_length =
- v4_address_bytes.length() + /* IPv4 port */ sizeof(uint16_t) +
- v6_address_bytes.length() + /* IPv6 port */ sizeof(uint16_t) +
- /* connection ID length byte */ sizeof(uint8_t) +
- in.preferred_address->connection_id.length() +
- in.preferred_address->stateless_reset_token.size();
- if (!writer.WriteVarInt62(TransportParameters::kPreferredAddress) ||
- !writer.WriteVarInt62(
- /* transport parameter length */ preferred_address_length) ||
- !writer.WriteStringPiece(v4_address_bytes) ||
- !writer.WriteUInt16(in.preferred_address->ipv4_socket_address.port()) ||
- !writer.WriteStringPiece(v6_address_bytes) ||
- !writer.WriteUInt16(in.preferred_address->ipv6_socket_address.port()) ||
- !writer.WriteUInt8(in.preferred_address->connection_id.length()) ||
- !writer.WriteBytes(in.preferred_address->connection_id.data(),
- in.preferred_address->connection_id.length()) ||
- !writer.WriteBytes(
- in.preferred_address->stateless_reset_token.data(),
- in.preferred_address->stateless_reset_token.size())) {
- QUIC_BUG(quic_bug_10743_13)
- << "Failed to write preferred_address for " << in;
- return false;
- }
- }
+ // Add a random GREASE transport parameter, as defined in the
+ // "Reserved Transport Parameters" section of RFC 9000.
+ // This forces receivers to support unexpected input.
+ QuicRandom* random = QuicRandom::GetInstance();
+ // Transport parameter identifiers are 62 bits long so we need to
+ // ensure that the output of the computation below fits in 62 bits.
+ uint64_t grease_id64 = random->RandUint64() % ((1ULL << 62) - 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;
+ TransportParameters::TransportParameterId grease_id =
+ static_cast<TransportParameters::TransportParameterId>(grease_id64);
+ const size_t grease_length = random->RandUint64() % kMaxGreaseLength;
+ QUICHE_DCHECK_GE(kMaxGreaseLength, grease_length);
+ char grease_contents[kMaxGreaseLength];
+ random->RandBytes(grease_contents, grease_length);
+ custom_parameters[grease_id] = std::string(grease_contents, grease_length);
- // initial_source_connection_id
- if (in.initial_source_connection_id.has_value()) {
- QuicConnectionId initial_source_connection_id =
- in.initial_source_connection_id.value();
- if (!writer.WriteVarInt62(
- TransportParameters::kInitialSourceConnectionId) ||
- !writer.WriteStringPieceVarInt62(
- absl::string_view(initial_source_connection_id.data(),
- initial_source_connection_id.length()))) {
- QUIC_BUG(quic_bug_10743_14)
- << "Failed to write initial_source_connection_id "
- << initial_source_connection_id << " for " << in;
- return false;
- }
- }
-
- // retry_source_connection_id
- if (in.retry_source_connection_id.has_value()) {
- QUICHE_DCHECK_EQ(Perspective::IS_SERVER, in.perspective);
- QuicConnectionId retry_source_connection_id =
- in.retry_source_connection_id.value();
- if (!writer.WriteVarInt62(TransportParameters::kRetrySourceConnectionId) ||
- !writer.WriteStringPieceVarInt62(
- absl::string_view(retry_source_connection_id.data(),
- retry_source_connection_id.length()))) {
- QUIC_BUG(quic_bug_10743_15)
- << "Failed to write retry_source_connection_id "
- << retry_source_connection_id << " for " << in;
- return false;
- }
- }
-
- // 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 (!writer.WriteVarInt62(TransportParameters::kGoogleConnectionOptions) ||
- !writer.WriteVarInt62(
- /* transport parameter length */ connection_options_length)) {
- QUIC_BUG(quic_bug_10743_16)
- << "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(quic_bug_10743_17)
- << "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 (!writer.WriteVarInt62(TransportParameters::kGoogleUserAgentId) ||
- !writer.WriteStringPieceVarInt62(in.user_agent_id.value())) {
- QUIC_BUG(quic_bug_10743_18)
- << "Failed to write Google user agent ID \""
- << in.user_agent_id.value() << "\" for " << in;
- return false;
- }
- }
-
- // Google-specific indicator for key update not yet supported.
- if (in.key_update_not_yet_supported) {
- if (!writer.WriteVarInt62(
- TransportParameters::kGoogleKeyUpdateNotYetSupported) ||
- !writer.WriteVarInt62(/* transport parameter length */ 0)) {
- QUIC_BUG(quic_bug_10743_19)
- << "Failed to write key_update_not_yet_supported for " << in;
- return false;
- }
+ // Custom parameters.
+ for (const auto& kv : custom_parameters) {
+ max_transport_param_length += kTypeAndValueLength + kv.second.length();
+ parameter_ids.push_back(kv.first);
}
- // Google-specific version extension.
- static_assert(sizeof(QuicVersionLabel) == sizeof(uint32_t), "bad length");
- uint64_t google_version_length = sizeof(in.version);
- if (in.perspective == Perspective::IS_SERVER) {
- google_version_length +=
- /* versions length */ sizeof(uint8_t) +
- sizeof(QuicVersionLabel) * in.supported_versions.size();
- }
- if (!writer.WriteVarInt62(TransportParameters::kGoogleQuicVersion) ||
- !writer.WriteVarInt62(
- /* transport parameter length */ google_version_length) ||
- !writer.WriteUInt32(in.version)) {
- QUIC_BUG(quic_bug_10743_20)
- << "Failed to write Google version extension for " << in;
- return false;
- }
- if (in.perspective == Perspective::IS_SERVER) {
- if (!writer.WriteUInt8(sizeof(QuicVersionLabel) *
- in.supported_versions.size())) {
- QUIC_BUG(quic_bug_10743_21)
- << "Failed to write versions length for " << in;
- return false;
- }
- for (QuicVersionLabel version_label : in.supported_versions) {
- if (!writer.WriteUInt32(version_label)) {
- QUIC_BUG(quic_bug_10743_22)
- << "Failed to write supported version for " << in;
- return false;
- }
- }
+ // Randomize order of sent transport parameters by walking the array
+ // backwards and swapping each element with a random earlier one.
+ for (size_t i = parameter_ids.size() - 1; i > 0; i--) {
+ std::swap(parameter_ids[i],
+ parameter_ids[random->InsecureRandUint64() % (i + 1)]);
}
- for (const auto& kv : in.custom_parameters) {
- 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(quic_bug_10743_23)
- << "Serializing custom_parameters with GREASE ID " << param_id
- << " is not allowed";
- return false;
- }
- if (!writer.WriteVarInt62(param_id) ||
- !writer.WriteStringPieceVarInt62(kv.second)) {
- QUIC_BUG(quic_bug_10743_24)
- << "Failed to write custom parameter " << param_id;
- return false;
- }
- }
+ out->resize(max_transport_param_length);
+ QuicDataWriter writer(out->size(), reinterpret_cast<char*>(out->data()));
- {
- // 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();
- // Transport parameter identifiers are 62 bits long so we need to ensure
- // that the output of the computation below fits in 62 bits.
- uint64_t grease_id64 = random->RandUint64() % ((1ULL << 62) - 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;
- TransportParameters::TransportParameterId grease_id =
- static_cast<TransportParameters::TransportParameterId>(grease_id64);
- const size_t grease_length = random->RandUint64() % kMaxGreaseLength;
- QUICHE_DCHECK_GE(kMaxGreaseLength, grease_length);
- char grease_contents[kMaxGreaseLength];
- random->RandBytes(grease_contents, grease_length);
- if (!writer.WriteVarInt62(grease_id) ||
- !writer.WriteStringPieceVarInt62(
- absl::string_view(grease_contents, grease_length))) {
- QUIC_BUG(quic_bug_10743_25) << "Failed to write GREASE parameter "
- << TransportParameterIdToString(grease_id);
- return false;
+ for (TransportParameters::TransportParameterId parameter_id : parameter_ids) {
+ switch (parameter_id) {
+ // original_destination_connection_id
+ case TransportParameters::kOriginalDestinationConnectionId: {
+ if (in.original_destination_connection_id.has_value()) {
+ QUICHE_DCHECK_EQ(Perspective::IS_SERVER, in.perspective);
+ QuicConnectionId original_destination_connection_id =
+ in.original_destination_connection_id.value();
+ if (!writer.WriteVarInt62(
+ TransportParameters::kOriginalDestinationConnectionId) ||
+ !writer.WriteStringPieceVarInt62(absl::string_view(
+ original_destination_connection_id.data(),
+ original_destination_connection_id.length()))) {
+ QUIC_BUG(Failed to write original_destination_connection_id)
+ << "Failed to write original_destination_connection_id "
+ << original_destination_connection_id << " for " << in;
+ return false;
+ }
+ }
+ } break;
+ // max_idle_timeout
+ case TransportParameters::kMaxIdleTimeout: {
+ if (!in.max_idle_timeout_ms.Write(&writer)) {
+ QUIC_BUG(Failed to write idle_timeout)
+ << "Failed to write idle_timeout for " << in;
+ return false;
+ }
+ } break;
+ // stateless_reset_token
+ case TransportParameters::kStatelessResetToken: {
+ if (!in.stateless_reset_token.empty()) {
+ QUICHE_DCHECK_EQ(kStatelessResetTokenLength,
+ in.stateless_reset_token.size());
+ QUICHE_DCHECK_EQ(Perspective::IS_SERVER, in.perspective);
+ if (!writer.WriteVarInt62(
+ TransportParameters::kStatelessResetToken) ||
+ !writer.WriteStringPieceVarInt62(
+ absl::string_view(reinterpret_cast<const char*>(
+ in.stateless_reset_token.data()),
+ in.stateless_reset_token.size()))) {
+ QUIC_BUG(Failed to write stateless_reset_token)
+ << "Failed to write stateless_reset_token of length "
+ << in.stateless_reset_token.size() << " for " << in;
+ return false;
+ }
+ }
+ } break;
+ // max_udp_payload_size
+ case TransportParameters::kMaxPacketSize: {
+ if (!in.max_udp_payload_size.Write(&writer)) {
+ QUIC_BUG(Failed to write max_udp_payload_size)
+ << "Failed to write max_udp_payload_size for " << in;
+ return false;
+ }
+ } break;
+ // initial_max_data
+ case TransportParameters::kInitialMaxData: {
+ if (!in.initial_max_data.Write(&writer)) {
+ QUIC_BUG(Failed to write initial_max_data)
+ << "Failed to write initial_max_data for " << in;
+ return false;
+ }
+ } break;
+ // initial_max_stream_data_bidi_local
+ case TransportParameters::kInitialMaxStreamDataBidiLocal: {
+ if (!in.initial_max_stream_data_bidi_local.Write(&writer)) {
+ QUIC_BUG(Failed to write initial_max_stream_data_bidi_local)
+ << "Failed to write initial_max_stream_data_bidi_local for "
+ << in;
+ return false;
+ }
+ } break;
+ // initial_max_stream_data_bidi_remote
+ case TransportParameters::kInitialMaxStreamDataBidiRemote: {
+ if (!in.initial_max_stream_data_bidi_remote.Write(&writer)) {
+ QUIC_BUG(Failed to write initial_max_stream_data_bidi_remote)
+ << "Failed to write initial_max_stream_data_bidi_remote for "
+ << in;
+ return false;
+ }
+ } break;
+ // initial_max_stream_data_uni
+ case TransportParameters::kInitialMaxStreamDataUni: {
+ if (!in.initial_max_stream_data_uni.Write(&writer)) {
+ QUIC_BUG(Failed to write initial_max_stream_data_uni)
+ << "Failed to write initial_max_stream_data_uni for " << in;
+ return false;
+ }
+ } break;
+ // initial_max_streams_bidi
+ case TransportParameters::kInitialMaxStreamsBidi: {
+ if (!in.initial_max_streams_bidi.Write(&writer)) {
+ QUIC_BUG(Failed to write initial_max_streams_bidi)
+ << "Failed to write initial_max_streams_bidi for " << in;
+ return false;
+ }
+ } break;
+ // initial_max_streams_uni
+ case TransportParameters::kInitialMaxStreamsUni: {
+ if (!in.initial_max_streams_uni.Write(&writer)) {
+ QUIC_BUG(Failed to write initial_max_streams_uni)
+ << "Failed to write initial_max_streams_uni for " << in;
+ return false;
+ }
+ } break;
+ // ack_delay_exponent
+ case TransportParameters::kAckDelayExponent: {
+ if (!in.ack_delay_exponent.Write(&writer)) {
+ QUIC_BUG(Failed to write ack_delay_exponent)
+ << "Failed to write ack_delay_exponent for " << in;
+ return false;
+ }
+ } break;
+ // max_ack_delay
+ case TransportParameters::kMaxAckDelay: {
+ if (!in.max_ack_delay.Write(&writer)) {
+ QUIC_BUG(Failed to write max_ack_delay)
+ << "Failed to write max_ack_delay for " << in;
+ return false;
+ }
+ } break;
+ // min_ack_delay_us
+ case TransportParameters::kMinAckDelay: {
+ if (!in.min_ack_delay_us.Write(&writer)) {
+ QUIC_BUG(Failed to write min_ack_delay_us)
+ << "Failed to write min_ack_delay_us for " << in;
+ return false;
+ }
+ } break;
+ // active_connection_id_limit
+ case TransportParameters::kActiveConnectionIdLimit: {
+ if (!in.active_connection_id_limit.Write(&writer)) {
+ QUIC_BUG(Failed to write active_connection_id_limit)
+ << "Failed to write active_connection_id_limit for " << in;
+ return false;
+ }
+ } break;
+ // max_datagram_frame_size
+ case TransportParameters::kMaxDatagramFrameSize: {
+ if (!in.max_datagram_frame_size.Write(&writer)) {
+ QUIC_BUG(Failed to write max_datagram_frame_size)
+ << "Failed to write max_datagram_frame_size for " << in;
+ return false;
+ }
+ } break;
+ // initial_round_trip_time_us
+ case TransportParameters::kInitialRoundTripTime: {
+ if (!in.initial_round_trip_time_us.Write(&writer)) {
+ QUIC_BUG(Failed to write initial_round_trip_time_us)
+ << "Failed to write initial_round_trip_time_us for " << in;
+ return false;
+ }
+ } break;
+ // disable_active_migration
+ case TransportParameters::kDisableActiveMigration: {
+ if (in.disable_active_migration) {
+ if (!writer.WriteVarInt62(
+ TransportParameters::kDisableActiveMigration) ||
+ !writer.WriteVarInt62(/* transport parameter length */ 0)) {
+ QUIC_BUG(Failed to write disable_active_migration)
+ << "Failed to write disable_active_migration for " << in;
+ return false;
+ }
+ }
+ } break;
+ // preferred_address
+ case TransportParameters::kPreferredAddress: {
+ if (in.preferred_address) {
+ std::string v4_address_bytes =
+ in.preferred_address->ipv4_socket_address.host().ToPackedString();
+ std::string v6_address_bytes =
+ in.preferred_address->ipv6_socket_address.host().ToPackedString();
+ if (v4_address_bytes.length() != 4 ||
+ v6_address_bytes.length() != 16 ||
+ in.preferred_address->stateless_reset_token.size() !=
+ kStatelessResetTokenLength) {
+ QUIC_BUG(quic_bug_10743_12)
+ << "Bad lengths " << *in.preferred_address;
+ return false;
+ }
+ const uint64_t preferred_address_length =
+ v4_address_bytes.length() + /* IPv4 port */ sizeof(uint16_t) +
+ v6_address_bytes.length() + /* IPv6 port */ sizeof(uint16_t) +
+ /* connection ID length byte */ sizeof(uint8_t) +
+ in.preferred_address->connection_id.length() +
+ in.preferred_address->stateless_reset_token.size();
+ if (!writer.WriteVarInt62(TransportParameters::kPreferredAddress) ||
+ !writer.WriteVarInt62(
+ /* transport parameter length */ preferred_address_length) ||
+ !writer.WriteStringPiece(v4_address_bytes) ||
+ !writer.WriteUInt16(
+ in.preferred_address->ipv4_socket_address.port()) ||
+ !writer.WriteStringPiece(v6_address_bytes) ||
+ !writer.WriteUInt16(
+ in.preferred_address->ipv6_socket_address.port()) ||
+ !writer.WriteUInt8(
+ in.preferred_address->connection_id.length()) ||
+ !writer.WriteBytes(
+ in.preferred_address->connection_id.data(),
+ in.preferred_address->connection_id.length()) ||
+ !writer.WriteBytes(
+ in.preferred_address->stateless_reset_token.data(),
+ in.preferred_address->stateless_reset_token.size())) {
+ QUIC_BUG(Failed to write preferred_address)
+ << "Failed to write preferred_address for " << in;
+ return false;
+ }
+ }
+ } break;
+ // initial_source_connection_id
+ case TransportParameters::kInitialSourceConnectionId: {
+ if (in.initial_source_connection_id.has_value()) {
+ QuicConnectionId initial_source_connection_id =
+ in.initial_source_connection_id.value();
+ if (!writer.WriteVarInt62(
+ TransportParameters::kInitialSourceConnectionId) ||
+ !writer.WriteStringPieceVarInt62(
+ absl::string_view(initial_source_connection_id.data(),
+ initial_source_connection_id.length()))) {
+ QUIC_BUG(Failed to write initial_source_connection_id)
+ << "Failed to write initial_source_connection_id "
+ << initial_source_connection_id << " for " << in;
+ return false;
+ }
+ }
+ } break;
+ // retry_source_connection_id
+ case TransportParameters::kRetrySourceConnectionId: {
+ if (in.retry_source_connection_id.has_value()) {
+ QUICHE_DCHECK_EQ(Perspective::IS_SERVER, in.perspective);
+ QuicConnectionId retry_source_connection_id =
+ in.retry_source_connection_id.value();
+ if (!writer.WriteVarInt62(
+ TransportParameters::kRetrySourceConnectionId) ||
+ !writer.WriteStringPieceVarInt62(
+ absl::string_view(retry_source_connection_id.data(),
+ retry_source_connection_id.length()))) {
+ QUIC_BUG(Failed to write retry_source_connection_id)
+ << "Failed to write retry_source_connection_id "
+ << retry_source_connection_id << " for " << in;
+ return false;
+ }
+ }
+ } break;
+ // Google-specific connection options.
+ case TransportParameters::kGoogleConnectionOptions: {
+ 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 (!writer.WriteVarInt62(
+ TransportParameters::kGoogleConnectionOptions) ||
+ !writer.WriteVarInt62(
+ /* transport parameter length */ connection_options_length)) {
+ QUIC_BUG(Failed to write google_connection_options)
+ << "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)
+ << "Failed to write google_connection_option "
+ << QuicTagToString(connection_option) << " for " << in;
+ return false;
+ }
+ }
+ }
+ } break;
+ // Google-specific user agent identifier.
+ case TransportParameters::kGoogleUserAgentId: {
+ if (in.user_agent_id.has_value()) {
+ if (!writer.WriteVarInt62(TransportParameters::kGoogleUserAgentId) ||
+ !writer.WriteStringPieceVarInt62(in.user_agent_id.value())) {
+ QUIC_BUG(Failed to write Google user agent ID)
+ << "Failed to write Google user agent ID \""
+ << in.user_agent_id.value() << "\" for " << in;
+ return false;
+ }
+ }
+ } break;
+ // Google-specific indicator for key update not yet supported.
+ case TransportParameters::kGoogleKeyUpdateNotYetSupported: {
+ if (in.key_update_not_yet_supported) {
+ if (!writer.WriteVarInt62(
+ TransportParameters::kGoogleKeyUpdateNotYetSupported) ||
+ !writer.WriteVarInt62(/* transport parameter length */ 0)) {
+ QUIC_BUG(Failed to write key_update_not_yet_supported)
+ << "Failed to write key_update_not_yet_supported for " << in;
+ return false;
+ }
+ }
+ } break;
+ // Google-specific version extension.
+ case TransportParameters::kGoogleQuicVersion: {
+ static_assert(sizeof(QuicVersionLabel) == sizeof(uint32_t),
+ "bad length");
+ uint64_t google_version_length = sizeof(in.version);
+ if (in.perspective == Perspective::IS_SERVER) {
+ google_version_length +=
+ /* versions length */ sizeof(uint8_t) +
+ sizeof(QuicVersionLabel) * in.supported_versions.size();
+ }
+ if (!writer.WriteVarInt62(TransportParameters::kGoogleQuicVersion) ||
+ !writer.WriteVarInt62(
+ /* transport parameter length */ google_version_length) ||
+ !writer.WriteUInt32(in.version)) {
+ QUIC_BUG(Failed to write Google version extension)
+ << "Failed to write Google version extension for " << in;
+ return false;
+ }
+ if (in.perspective == Perspective::IS_SERVER) {
+ if (!writer.WriteUInt8(sizeof(QuicVersionLabel) *
+ in.supported_versions.size())) {
+ QUIC_BUG(Failed to write versions length)
+ << "Failed to write versions length for " << in;
+ return false;
+ }
+ for (QuicVersionLabel version_label : in.supported_versions) {
+ if (!writer.WriteUInt32(version_label)) {
+ QUIC_BUG(Failed to write supported version)
+ << "Failed to write supported version for " << in;
+ return false;
+ }
+ }
+ }
+ } break;
+ // Custom parameters and GREASE.
+ default: {
+ auto it = custom_parameters.find(parameter_id);
+ if (it == custom_parameters.end()) {
+ QUIC_BUG(Unknown parameter) << "Unknown parameter " << parameter_id;
+ return false;
+ }
+ if (!writer.WriteVarInt62(parameter_id) ||
+ !writer.WriteStringPieceVarInt62(it->second)) {
+ QUIC_BUG(Failed to write custom parameter)
+ << "Failed to write custom parameter " << parameter_id;
+ return false;
+ }
+ } break;
}
}
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 81707c51885..48af1c4223a 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
@@ -932,6 +932,52 @@ TEST_P(TransportParametersTest, VeryLongCustomParameter) {
EXPECT_EQ(new_params, orig_params);
}
+TEST_P(TransportParametersTest, SerializationOrderIsRandom) {
+ TransportParameters orig_params;
+ orig_params.perspective = Perspective::IS_CLIENT;
+ orig_params.version = kFakeVersionLabel;
+ orig_params.max_idle_timeout_ms.set_value(kFakeIdleTimeoutMilliseconds);
+ orig_params.max_udp_payload_size.set_value(kMaxPacketSizeForTest);
+ 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(kAckDelayExponentForTest);
+ orig_params.max_ack_delay.set_value(kMaxAckDelayForTest);
+ orig_params.min_ack_delay_us.set_value(kMinAckDelayUsForTest);
+ orig_params.disable_active_migration = kFakeDisableMigration;
+ orig_params.active_connection_id_limit.set_value(
+ kActiveConnectionIdLimitForTest);
+ orig_params.initial_source_connection_id =
+ CreateFakeInitialSourceConnectionId();
+ orig_params.initial_round_trip_time_us.set_value(kFakeInitialRoundTripTime);
+ orig_params.google_connection_options = CreateFakeGoogleConnectionOptions();
+ orig_params.user_agent_id = CreateFakeUserAgentId();
+ orig_params.key_update_not_yet_supported = kFakeKeyUpdateNotYetSupported;
+ orig_params.custom_parameters[kCustomParameter1] = kCustomParameter1Value;
+ orig_params.custom_parameters[kCustomParameter2] = kCustomParameter2Value;
+
+ std::vector<uint8_t> first_serialized;
+ ASSERT_TRUE(
+ SerializeTransportParameters(version_, orig_params, &first_serialized));
+ // Test that a subsequent serialization is different from the first.
+ // Run in a loop to avoid a failure in the unlikely event that randomization
+ // produces the same result multiple times.
+ for (int i = 0; i < 1000; i++) {
+ std::vector<uint8_t> serialized;
+ ASSERT_TRUE(
+ SerializeTransportParameters(version_, orig_params, &serialized));
+ if (serialized != first_serialized) {
+ return;
+ }
+ }
+}
+
class TransportParametersTicketSerializationTest : public QuicTest {
protected:
void SetUp() override {
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 038924e2165..43eabf7ef79 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
@@ -85,7 +85,8 @@ TEST_F(QuicFramesTest, RstStreamFrameToString) {
std::ostringstream stream;
stream << rst_stream;
EXPECT_EQ(
- "{ control_frame_id: 1, stream_id: 1, byte_offset: 3, error_code: 6 }\n",
+ "{ control_frame_id: 1, stream_id: 1, byte_offset: 3, error_code: 6, "
+ "ietf_error_code: 0 }\n",
stream.str());
EXPECT_TRUE(IsControlFrame(frame.type));
}
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 d70f217bc14..873868c3d5c 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
@@ -18,12 +18,23 @@ QuicRstStreamFrame::QuicRstStreamFrame(QuicControlFrameId control_frame_id,
ietf_error_code(RstStreamErrorCodeToIetfResetStreamErrorCode(error_code)),
byte_offset(bytes_written) {}
+QuicRstStreamFrame::QuicRstStreamFrame(QuicControlFrameId control_frame_id,
+ QuicStreamId stream_id,
+ QuicResetStreamError error,
+ QuicStreamOffset bytes_written)
+ : control_frame_id(control_frame_id),
+ stream_id(stream_id),
+ error_code(error.internal_code()),
+ ietf_error_code(error.ietf_application_code()),
+ byte_offset(bytes_written) {}
+
std::ostream& operator<<(std::ostream& os,
const QuicRstStreamFrame& rst_frame) {
os << "{ control_frame_id: " << rst_frame.control_frame_id
<< ", stream_id: " << rst_frame.stream_id
<< ", byte_offset: " << rst_frame.byte_offset
- << ", error_code: " << rst_frame.error_code << " }\n";
+ << ", error_code: " << rst_frame.error_code
+ << ", ietf_error_code: " << rst_frame.ietf_error_code << " }\n";
return 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 9c9e42e4d38..744a227c8ff 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
@@ -16,13 +16,14 @@ namespace quic {
struct QUIC_EXPORT_PRIVATE QuicRstStreamFrame {
QuicRstStreamFrame() = default;
QuicRstStreamFrame(QuicControlFrameId control_frame_id,
- QuicStreamId stream_id,
- QuicRstStreamErrorCode error_code,
+ QuicStreamId stream_id, QuicRstStreamErrorCode error_code,
+ QuicStreamOffset bytes_written);
+ QuicRstStreamFrame(QuicControlFrameId control_frame_id,
+ QuicStreamId stream_id, QuicResetStreamError error,
QuicStreamOffset bytes_written);
friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(
- std::ostream& os,
- const QuicRstStreamFrame& r);
+ std::ostream& os, const QuicRstStreamFrame& r);
// A unique identifier of this control frame. 0 when this frame is received,
// and non-zero when sent.
@@ -45,6 +46,11 @@ struct QUIC_EXPORT_PRIVATE QuicRstStreamFrame {
// that stream. This can be done through normal termination (data packet with
// FIN) or through a RST.
QuicStreamOffset byte_offset = 0;
+
+ // Returns a tuple of both |error_code| and |ietf_error_code|.
+ QuicResetStreamError error() const {
+ return QuicResetStreamError(error_code, ietf_error_code);
+ }
};
} // 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 93eed75ccc4..396288ead41 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
@@ -11,11 +11,16 @@ namespace quic {
QuicStopSendingFrame::QuicStopSendingFrame(QuicControlFrameId control_frame_id,
QuicStreamId stream_id,
QuicRstStreamErrorCode error_code)
+ : QuicStopSendingFrame(control_frame_id, stream_id,
+ QuicResetStreamError::FromInternal(error_code)) {}
+
+QuicStopSendingFrame::QuicStopSendingFrame(QuicControlFrameId control_frame_id,
+ QuicStreamId stream_id,
+ QuicResetStreamError error)
: control_frame_id(control_frame_id),
stream_id(stream_id),
- error_code(error_code),
- ietf_error_code(
- RstStreamErrorCodeToIetfResetStreamErrorCode(error_code)) {}
+ error_code(error.internal_code()),
+ ietf_error_code(error.ietf_application_code()) {}
std::ostream& operator<<(std::ostream& os, const QuicStopSendingFrame& frame) {
os << "{ control_frame_id: " << frame.control_frame_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 60158b221d8..b575e756cb7 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
@@ -18,6 +18,8 @@ struct QUIC_EXPORT_PRIVATE QuicStopSendingFrame {
QuicStopSendingFrame(QuicControlFrameId control_frame_id,
QuicStreamId stream_id,
QuicRstStreamErrorCode error_code);
+ QuicStopSendingFrame(QuicControlFrameId control_frame_id,
+ QuicStreamId stream_id, QuicResetStreamError error);
friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(
std::ostream& os,
@@ -35,6 +37,11 @@ struct QUIC_EXPORT_PRIVATE QuicStopSendingFrame {
// On-the-wire application error code of the frame.
uint64_t ietf_error_code = 0;
+
+ // Returns a tuple of both |error_code| and |ietf_error_code|.
+ QuicResetStreamError error() const {
+ return QuicResetStreamError(error_code, ietf_error_code);
+ }
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/capsule.cc b/chromium/net/third_party/quiche/src/quic/core/http/capsule.cc
new file mode 100644
index 00000000000..c811bb84287
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/http/capsule.cc
@@ -0,0 +1,629 @@
+// Copyright (c) 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "quic/core/http/capsule.h"
+
+#include <type_traits>
+
+#include "absl/strings/escaping.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/string_view.h"
+#include "quic/core/http/http_frames.h"
+#include "quic/core/quic_data_reader.h"
+#include "quic/core/quic_data_writer.h"
+#include "quic/core/quic_types.h"
+#include "quic/platform/api/quic_bug_tracker.h"
+#include "common/platform/api/quiche_logging.h"
+
+namespace quic {
+
+std::string CapsuleTypeToString(CapsuleType capsule_type) {
+ switch (capsule_type) {
+ case CapsuleType::REGISTER_DATAGRAM_CONTEXT:
+ return "REGISTER_DATAGRAM_CONTEXT";
+ case CapsuleType::CLOSE_DATAGRAM_CONTEXT:
+ return "CLOSE_DATAGRAM_CONTEXT";
+ case CapsuleType::DATAGRAM:
+ return "DATAGRAM";
+ case CapsuleType::REGISTER_DATAGRAM_NO_CONTEXT:
+ return "REGISTER_DATAGRAM_NO_CONTEXT";
+ case CapsuleType::CLOSE_WEBTRANSPORT_SESSION:
+ return "CLOSE_WEBTRANSPORT_SESSION";
+ }
+ return absl::StrCat("Unknown(", static_cast<uint64_t>(capsule_type), ")");
+}
+
+std::ostream& operator<<(std::ostream& os, const CapsuleType& capsule_type) {
+ os << CapsuleTypeToString(capsule_type);
+ return os;
+}
+
+std::string DatagramFormatTypeToString(
+ DatagramFormatType datagram_format_type) {
+ switch (datagram_format_type) {
+ case DatagramFormatType::UDP_PAYLOAD:
+ return "UDP_PAYLOAD";
+ case DatagramFormatType::WEBTRANSPORT:
+ return "WEBTRANSPORT";
+ }
+ return absl::StrCat("Unknown(", static_cast<uint64_t>(datagram_format_type),
+ ")");
+}
+
+std::ostream& operator<<(std::ostream& os,
+ const DatagramFormatType& datagram_format_type) {
+ os << DatagramFormatTypeToString(datagram_format_type);
+ return os;
+}
+
+std::string ContextCloseCodeToString(ContextCloseCode context_close_code) {
+ switch (context_close_code) {
+ case ContextCloseCode::CLOSE_NO_ERROR:
+ return "NO_ERROR";
+ case ContextCloseCode::UNKNOWN_FORMAT:
+ return "UNKNOWN_FORMAT";
+ case ContextCloseCode::DENIED:
+ return "DENIED";
+ case ContextCloseCode::RESOURCE_LIMIT:
+ return "RESOURCE_LIMIT";
+ }
+ return absl::StrCat("Unknown(", static_cast<uint64_t>(context_close_code),
+ ")");
+}
+
+std::ostream& operator<<(std::ostream& os,
+ const ContextCloseCode& context_close_code) {
+ os << ContextCloseCodeToString(context_close_code);
+ return os;
+}
+
+Capsule::Capsule(CapsuleType capsule_type) : capsule_type_(capsule_type) {
+ switch (capsule_type) {
+ case CapsuleType::DATAGRAM:
+ static_assert(std::is_standard_layout<DatagramCapsule>::value &&
+ std::is_trivially_destructible<DatagramCapsule>::value,
+ "All capsule structs must have these properties");
+ datagram_capsule_ = DatagramCapsule();
+ break;
+ case CapsuleType::REGISTER_DATAGRAM_CONTEXT:
+ static_assert(
+ std::is_standard_layout<RegisterDatagramContextCapsule>::value &&
+ std::is_trivially_destructible<
+ RegisterDatagramContextCapsule>::value,
+ "All capsule structs must have these properties");
+ register_datagram_context_capsule_ = RegisterDatagramContextCapsule();
+ break;
+ case CapsuleType::REGISTER_DATAGRAM_NO_CONTEXT:
+ static_assert(
+ std::is_standard_layout<RegisterDatagramNoContextCapsule>::value &&
+ std::is_trivially_destructible<
+ RegisterDatagramNoContextCapsule>::value,
+ "All capsule structs must have these properties");
+ register_datagram_no_context_capsule_ =
+ RegisterDatagramNoContextCapsule();
+ break;
+ case CapsuleType::CLOSE_DATAGRAM_CONTEXT:
+ static_assert(
+ std::is_standard_layout<CloseDatagramContextCapsule>::value &&
+ std::is_trivially_destructible<
+ CloseDatagramContextCapsule>::value,
+ "All capsule structs must have these properties");
+ close_datagram_context_capsule_ = CloseDatagramContextCapsule();
+ break;
+ case CapsuleType::CLOSE_WEBTRANSPORT_SESSION:
+ static_assert(
+ std::is_standard_layout<CloseWebTransportSessionCapsule>::value &&
+ std::is_trivially_destructible<
+ CloseWebTransportSessionCapsule>::value,
+ "All capsule structs must have these properties");
+ close_web_transport_session_capsule_ = CloseWebTransportSessionCapsule();
+ break;
+ default:
+ unknown_capsule_data_ = absl::string_view();
+ break;
+ }
+}
+
+// static
+Capsule Capsule::Datagram(absl::optional<QuicDatagramContextId> context_id,
+ absl::string_view http_datagram_payload) {
+ Capsule capsule(CapsuleType::DATAGRAM);
+ capsule.datagram_capsule().context_id = context_id;
+ capsule.datagram_capsule().http_datagram_payload = http_datagram_payload;
+ return capsule;
+}
+
+// static
+Capsule Capsule::RegisterDatagramContext(
+ QuicDatagramContextId context_id, DatagramFormatType format_type,
+ absl::string_view format_additional_data) {
+ Capsule capsule(CapsuleType::REGISTER_DATAGRAM_CONTEXT);
+ capsule.register_datagram_context_capsule().context_id = context_id;
+ capsule.register_datagram_context_capsule().format_type = format_type;
+ capsule.register_datagram_context_capsule().format_additional_data =
+ format_additional_data;
+ return capsule;
+}
+
+// static
+Capsule Capsule::RegisterDatagramNoContext(
+ DatagramFormatType format_type, absl::string_view format_additional_data) {
+ Capsule capsule(CapsuleType::REGISTER_DATAGRAM_NO_CONTEXT);
+ capsule.register_datagram_no_context_capsule().format_type = format_type;
+ capsule.register_datagram_no_context_capsule().format_additional_data =
+ format_additional_data;
+ return capsule;
+}
+
+// static
+Capsule Capsule::CloseDatagramContext(QuicDatagramContextId context_id,
+ ContextCloseCode close_code,
+ absl::string_view close_details) {
+ Capsule capsule(CapsuleType::CLOSE_DATAGRAM_CONTEXT);
+ capsule.close_datagram_context_capsule().context_id = context_id;
+ capsule.close_datagram_context_capsule().close_code = close_code;
+ capsule.close_datagram_context_capsule().close_details = close_details;
+ return capsule;
+}
+
+// static
+Capsule Capsule::CloseWebTransportSession(WebTransportSessionError error_code,
+ absl::string_view error_message) {
+ Capsule capsule(CapsuleType::CLOSE_WEBTRANSPORT_SESSION);
+ capsule.close_web_transport_session_capsule().error_code = error_code;
+ capsule.close_web_transport_session_capsule().error_message = error_message;
+ return capsule;
+}
+
+// static
+Capsule Capsule::Unknown(uint64_t capsule_type,
+ absl::string_view unknown_capsule_data) {
+ Capsule capsule(static_cast<CapsuleType>(capsule_type));
+ capsule.unknown_capsule_data() = unknown_capsule_data;
+ return capsule;
+}
+
+Capsule& Capsule::operator=(const Capsule& other) {
+ capsule_type_ = other.capsule_type_;
+ switch (capsule_type_) {
+ case CapsuleType::DATAGRAM:
+ datagram_capsule_ = other.datagram_capsule_;
+ break;
+ case CapsuleType::REGISTER_DATAGRAM_CONTEXT:
+ register_datagram_context_capsule_ =
+ other.register_datagram_context_capsule_;
+ break;
+ case CapsuleType::REGISTER_DATAGRAM_NO_CONTEXT:
+ register_datagram_no_context_capsule_ =
+ other.register_datagram_no_context_capsule_;
+ break;
+ case CapsuleType::CLOSE_DATAGRAM_CONTEXT:
+ close_datagram_context_capsule_ = other.close_datagram_context_capsule_;
+ break;
+ case CapsuleType::CLOSE_WEBTRANSPORT_SESSION:
+ close_web_transport_session_capsule_ =
+ other.close_web_transport_session_capsule_;
+ break;
+ default:
+ unknown_capsule_data_ = other.unknown_capsule_data_;
+ break;
+ }
+ return *this;
+}
+
+Capsule::Capsule(const Capsule& other) : Capsule(other.capsule_type_) {
+ *this = other;
+}
+
+bool Capsule::operator==(const Capsule& other) const {
+ if (capsule_type_ != other.capsule_type_) {
+ return false;
+ }
+ switch (capsule_type_) {
+ case CapsuleType::DATAGRAM:
+ return datagram_capsule_.context_id ==
+ other.datagram_capsule_.context_id &&
+ datagram_capsule_.http_datagram_payload ==
+ other.datagram_capsule_.http_datagram_payload;
+ case CapsuleType::REGISTER_DATAGRAM_CONTEXT:
+ return register_datagram_context_capsule_.context_id ==
+ other.register_datagram_context_capsule_.context_id &&
+ register_datagram_context_capsule_.format_type ==
+ other.register_datagram_context_capsule_.format_type &&
+ register_datagram_context_capsule_.format_additional_data ==
+ other.register_datagram_context_capsule_
+ .format_additional_data;
+ case CapsuleType::REGISTER_DATAGRAM_NO_CONTEXT:
+ return register_datagram_no_context_capsule_.format_type ==
+ other.register_datagram_no_context_capsule_.format_type &&
+ register_datagram_no_context_capsule_.format_additional_data ==
+ other.register_datagram_no_context_capsule_
+ .format_additional_data;
+ case CapsuleType::CLOSE_DATAGRAM_CONTEXT:
+ return close_datagram_context_capsule_.context_id ==
+ other.close_datagram_context_capsule_.context_id &&
+ close_datagram_context_capsule_.close_code ==
+ other.close_datagram_context_capsule_.close_code &&
+ close_datagram_context_capsule_.close_details ==
+ other.close_datagram_context_capsule_.close_details;
+ case CapsuleType::CLOSE_WEBTRANSPORT_SESSION:
+ return close_web_transport_session_capsule_.error_code ==
+ other.close_web_transport_session_capsule_.error_code &&
+ close_web_transport_session_capsule_.error_message ==
+ other.close_web_transport_session_capsule_.error_message;
+ default:
+ return unknown_capsule_data_ == other.unknown_capsule_data_;
+ }
+}
+
+std::string Capsule::ToString() const {
+ std::string rv = CapsuleTypeToString(capsule_type_);
+ switch (capsule_type_) {
+ case CapsuleType::DATAGRAM:
+ if (datagram_capsule_.context_id.has_value()) {
+ absl::StrAppend(&rv, "(", datagram_capsule_.context_id.value(), ")");
+ }
+ absl::StrAppend(
+ &rv, "[",
+ absl::BytesToHexString(datagram_capsule_.http_datagram_payload), "]");
+ break;
+ case CapsuleType::REGISTER_DATAGRAM_CONTEXT:
+ absl::StrAppend(
+ &rv, "(context_id=", register_datagram_context_capsule_.context_id,
+ ",format_type=",
+ DatagramFormatTypeToString(
+ register_datagram_context_capsule_.format_type),
+ "){",
+ absl::BytesToHexString(
+ register_datagram_context_capsule_.format_additional_data),
+ "}");
+ break;
+ case CapsuleType::REGISTER_DATAGRAM_NO_CONTEXT:
+ absl::StrAppend(
+ &rv, "(format_type=",
+ DatagramFormatTypeToString(
+ register_datagram_no_context_capsule_.format_type),
+ "){",
+ absl::BytesToHexString(
+ register_datagram_no_context_capsule_.format_additional_data),
+ "}");
+ break;
+ case CapsuleType::CLOSE_DATAGRAM_CONTEXT:
+ absl::StrAppend(
+ &rv, "(context_id=", close_datagram_context_capsule_.context_id,
+ ",close_code=",
+ ContextCloseCodeToString(close_datagram_context_capsule_.close_code),
+ ",close_details=\"",
+ absl::BytesToHexString(close_datagram_context_capsule_.close_details),
+ "\")");
+ break;
+ case CapsuleType::CLOSE_WEBTRANSPORT_SESSION:
+ absl::StrAppend(
+ &rv, "(error_code=", close_web_transport_session_capsule_.error_code,
+ ",error_message=\"",
+ close_web_transport_session_capsule_.error_message, "\")");
+ break;
+ default:
+ absl::StrAppend(&rv, "[", absl::BytesToHexString(unknown_capsule_data_),
+ "]");
+ break;
+ }
+ return rv;
+}
+
+std::ostream& operator<<(std::ostream& os, const Capsule& capsule) {
+ os << capsule.ToString();
+ return os;
+}
+
+CapsuleParser::CapsuleParser(Visitor* visitor) : visitor_(visitor) {
+ QUICHE_DCHECK_NE(visitor_, nullptr);
+}
+
+QuicBuffer SerializeCapsule(const Capsule& capsule,
+ QuicBufferAllocator* allocator) {
+ QuicByteCount capsule_type_length = QuicDataWriter::GetVarInt62Len(
+ static_cast<uint64_t>(capsule.capsule_type()));
+ QuicByteCount capsule_data_length;
+ switch (capsule.capsule_type()) {
+ case CapsuleType::DATAGRAM:
+ capsule_data_length =
+ capsule.datagram_capsule().http_datagram_payload.length();
+ if (capsule.datagram_capsule().context_id.has_value()) {
+ capsule_data_length += QuicDataWriter::GetVarInt62Len(
+ capsule.datagram_capsule().context_id.value());
+ }
+ break;
+ case CapsuleType::REGISTER_DATAGRAM_CONTEXT:
+ capsule_data_length =
+ QuicDataWriter::GetVarInt62Len(
+ capsule.register_datagram_context_capsule().context_id) +
+ QuicDataWriter::GetVarInt62Len(static_cast<uint64_t>(
+ capsule.register_datagram_context_capsule().format_type)) +
+ capsule.register_datagram_context_capsule()
+ .format_additional_data.length();
+ break;
+ case CapsuleType::REGISTER_DATAGRAM_NO_CONTEXT:
+ capsule_data_length =
+ QuicDataWriter::GetVarInt62Len(static_cast<uint64_t>(
+ capsule.register_datagram_no_context_capsule().format_type)) +
+ capsule.register_datagram_no_context_capsule()
+ .format_additional_data.length();
+ break;
+ case CapsuleType::CLOSE_DATAGRAM_CONTEXT:
+ capsule_data_length =
+ QuicDataWriter::GetVarInt62Len(
+ capsule.close_datagram_context_capsule().context_id) +
+ QuicDataWriter::GetVarInt62Len(static_cast<uint64_t>(
+ capsule.close_datagram_context_capsule().close_code)) +
+ capsule.close_datagram_context_capsule().close_details.length();
+ break;
+ case CapsuleType::CLOSE_WEBTRANSPORT_SESSION:
+ capsule_data_length =
+ sizeof(WebTransportSessionError) +
+ capsule.close_web_transport_session_capsule().error_message.size();
+ break;
+ default:
+ capsule_data_length = capsule.unknown_capsule_data().length();
+ break;
+ }
+ QuicByteCount capsule_length_length =
+ QuicDataWriter::GetVarInt62Len(capsule_data_length);
+ QuicByteCount total_capsule_length =
+ capsule_type_length + capsule_length_length + capsule_data_length;
+ QuicBuffer buffer(allocator, total_capsule_length);
+ QuicDataWriter writer(buffer.size(), buffer.data());
+ if (!writer.WriteVarInt62(static_cast<uint64_t>(capsule.capsule_type()))) {
+ QUIC_BUG(capsule type write fail) << "Failed to write CAPSULE type";
+ return QuicBuffer();
+ }
+ if (!writer.WriteVarInt62(capsule_data_length)) {
+ QUIC_BUG(capsule length write fail) << "Failed to write CAPSULE length";
+ return QuicBuffer();
+ }
+ switch (capsule.capsule_type()) {
+ case CapsuleType::DATAGRAM:
+ if (capsule.datagram_capsule().context_id.has_value()) {
+ if (!writer.WriteVarInt62(
+ capsule.datagram_capsule().context_id.value())) {
+ QUIC_BUG(datagram capsule context ID write fail)
+ << "Failed to write DATAGRAM CAPSULE context ID";
+ return QuicBuffer();
+ }
+ }
+ if (!writer.WriteStringPiece(
+ capsule.datagram_capsule().http_datagram_payload)) {
+ QUIC_BUG(datagram capsule payload write fail)
+ << "Failed to write DATAGRAM CAPSULE payload";
+ return QuicBuffer();
+ }
+ break;
+ case CapsuleType::REGISTER_DATAGRAM_CONTEXT:
+ if (!writer.WriteVarInt62(
+ capsule.register_datagram_context_capsule().context_id)) {
+ QUIC_BUG(register context capsule context ID write fail)
+ << "Failed to write REGISTER_DATAGRAM_CONTEXT CAPSULE context ID";
+ return QuicBuffer();
+ }
+ if (!writer.WriteVarInt62(static_cast<uint64_t>(
+ capsule.register_datagram_context_capsule().format_type))) {
+ QUIC_BUG(register context capsule format type write fail)
+ << "Failed to write REGISTER_DATAGRAM_CONTEXT CAPSULE format type";
+ return QuicBuffer();
+ }
+ if (!writer.WriteStringPiece(capsule.register_datagram_context_capsule()
+ .format_additional_data)) {
+ QUIC_BUG(register context capsule additional data write fail)
+ << "Failed to write REGISTER_DATAGRAM_CONTEXT CAPSULE additional "
+ "data";
+ return QuicBuffer();
+ }
+ break;
+ case CapsuleType::REGISTER_DATAGRAM_NO_CONTEXT:
+ if (!writer.WriteVarInt62(static_cast<uint64_t>(
+ capsule.register_datagram_no_context_capsule().format_type))) {
+ QUIC_BUG(register no context capsule format type write fail)
+ << "Failed to write REGISTER_DATAGRAM_NO_CONTEXT CAPSULE format "
+ "type";
+ return QuicBuffer();
+ }
+ if (!writer.WriteStringPiece(
+ capsule.register_datagram_no_context_capsule()
+ .format_additional_data)) {
+ QUIC_BUG(register no context capsule additional data write fail)
+ << "Failed to write REGISTER_DATAGRAM_NO_CONTEXT CAPSULE "
+ "additional data";
+ return QuicBuffer();
+ }
+ break;
+ case CapsuleType::CLOSE_DATAGRAM_CONTEXT:
+ if (!writer.WriteVarInt62(
+ capsule.close_datagram_context_capsule().context_id)) {
+ QUIC_BUG(close context capsule context ID write fail)
+ << "Failed to write CLOSE_DATAGRAM_CONTEXT CAPSULE context ID";
+ return QuicBuffer();
+ }
+ if (!writer.WriteVarInt62(static_cast<uint64_t>(
+ capsule.close_datagram_context_capsule().close_code))) {
+ QUIC_BUG(close context capsule close code write fail)
+ << "Failed to write CLOSE_DATAGRAM_CONTEXT CAPSULE close code";
+ return QuicBuffer();
+ }
+ if (!writer.WriteStringPiece(
+ capsule.close_datagram_context_capsule().close_details)) {
+ QUIC_BUG(close context capsule close details write fail)
+ << "Failed to write CLOSE_DATAGRAM_CONTEXT CAPSULE close details";
+ return QuicBuffer();
+ }
+ break;
+ case CapsuleType::CLOSE_WEBTRANSPORT_SESSION:
+ if (!writer.WriteUInt32(
+ capsule.close_web_transport_session_capsule().error_code)) {
+ QUIC_BUG(close webtransport session capsule error code write fail)
+ << "Failed to write CLOSE_WEBTRANSPORT_SESSION error code";
+ return QuicBuffer();
+ }
+ if (!writer.WriteStringPiece(
+ capsule.close_web_transport_session_capsule().error_message)) {
+ QUIC_BUG(close webtransport session capsule error message write fail)
+ << "Failed to write CLOSE_WEBTRANSPORT_SESSION error message";
+ return QuicBuffer();
+ }
+ break;
+ default:
+ if (!writer.WriteStringPiece(capsule.unknown_capsule_data())) {
+ QUIC_BUG(capsule data write fail) << "Failed to write CAPSULE data";
+ return QuicBuffer();
+ }
+ break;
+ }
+ if (writer.remaining() != 0) {
+ QUIC_BUG(capsule write length mismatch)
+ << "CAPSULE serialization wrote " << writer.length() << " instead of "
+ << writer.capacity();
+ return QuicBuffer();
+ }
+ return buffer;
+}
+
+bool CapsuleParser::IngestCapsuleFragment(absl::string_view capsule_fragment) {
+ if (parsing_error_occurred_) {
+ return false;
+ }
+ absl::StrAppend(&buffered_data_, capsule_fragment);
+ while (true) {
+ const size_t buffered_data_read = AttemptParseCapsule();
+ if (parsing_error_occurred_) {
+ QUICHE_DCHECK_EQ(buffered_data_read, 0u);
+ buffered_data_.clear();
+ return false;
+ }
+ if (buffered_data_read == 0) {
+ break;
+ }
+ buffered_data_.erase(0, buffered_data_read);
+ }
+ static constexpr size_t kMaxCapsuleBufferSize = 1024 * 1024;
+ if (buffered_data_.size() > kMaxCapsuleBufferSize) {
+ buffered_data_.clear();
+ ReportParseFailure("Refusing to buffer too much capsule data");
+ return false;
+ }
+ return true;
+}
+
+size_t CapsuleParser::AttemptParseCapsule() {
+ QUICHE_DCHECK(!parsing_error_occurred_);
+ if (buffered_data_.empty()) {
+ return 0;
+ }
+ QuicDataReader capsule_fragment_reader(buffered_data_);
+ uint64_t capsule_type64;
+ if (!capsule_fragment_reader.ReadVarInt62(&capsule_type64)) {
+ QUIC_DVLOG(2) << "Partial read: not enough data to read capsule type";
+ return 0;
+ }
+ absl::string_view capsule_data;
+ if (!capsule_fragment_reader.ReadStringPieceVarInt62(&capsule_data)) {
+ QUIC_DVLOG(2) << "Partial read: not enough data to read capsule length or "
+ "full capsule data";
+ return 0;
+ }
+ QuicDataReader capsule_data_reader(capsule_data);
+ Capsule capsule(static_cast<CapsuleType>(capsule_type64));
+ switch (capsule.capsule_type()) {
+ case CapsuleType::DATAGRAM:
+ if (datagram_context_id_present_) {
+ uint64_t context_id;
+ if (!capsule_data_reader.ReadVarInt62(&context_id)) {
+ ReportParseFailure("Unable to parse capsule DATAGRAM context ID");
+ return 0;
+ }
+ capsule.datagram_capsule().context_id = context_id;
+ }
+ capsule.datagram_capsule().http_datagram_payload =
+ capsule_data_reader.ReadRemainingPayload();
+ break;
+ case CapsuleType::REGISTER_DATAGRAM_CONTEXT:
+ if (!capsule_data_reader.ReadVarInt62(
+ &capsule.register_datagram_context_capsule().context_id)) {
+ ReportParseFailure(
+ "Unable to parse capsule REGISTER_DATAGRAM_CONTEXT context ID");
+ return 0;
+ }
+ if (!capsule_data_reader.ReadVarInt62(reinterpret_cast<uint64_t*>(
+ &capsule.register_datagram_context_capsule().format_type))) {
+ ReportParseFailure(
+ "Unable to parse capsule REGISTER_DATAGRAM_CONTEXT format type");
+ return 0;
+ }
+ capsule.register_datagram_context_capsule().format_additional_data =
+ capsule_data_reader.ReadRemainingPayload();
+ break;
+ case CapsuleType::REGISTER_DATAGRAM_NO_CONTEXT:
+ if (!capsule_data_reader.ReadVarInt62(reinterpret_cast<uint64_t*>(
+ &capsule.register_datagram_no_context_capsule().format_type))) {
+ ReportParseFailure(
+ "Unable to parse capsule REGISTER_DATAGRAM_NO_CONTEXT format type");
+ return 0;
+ }
+ capsule.register_datagram_no_context_capsule().format_additional_data =
+ capsule_data_reader.ReadRemainingPayload();
+ break;
+ case CapsuleType::CLOSE_DATAGRAM_CONTEXT:
+ if (!capsule_data_reader.ReadVarInt62(
+ &capsule.close_datagram_context_capsule().context_id)) {
+ ReportParseFailure(
+ "Unable to parse capsule CLOSE_DATAGRAM_CONTEXT context ID");
+ return 0;
+ }
+ if (!capsule_data_reader.ReadVarInt62(reinterpret_cast<uint64_t*>(
+ &capsule.close_datagram_context_capsule().close_code))) {
+ ReportParseFailure(
+ "Unable to parse capsule CLOSE_DATAGRAM_CONTEXT close code");
+ return 0;
+ }
+ capsule.close_datagram_context_capsule().close_details =
+ capsule_data_reader.ReadRemainingPayload();
+ break;
+ case CapsuleType::CLOSE_WEBTRANSPORT_SESSION:
+ if (!capsule_data_reader.ReadUInt32(
+ &capsule.close_web_transport_session_capsule().error_code)) {
+ ReportParseFailure(
+ "Unable to parse capsule CLOSE_WEBTRANSPORT_SESSION error code");
+ return 0;
+ }
+ capsule.close_web_transport_session_capsule().error_message =
+ capsule_data_reader.ReadRemainingPayload();
+ break;
+ default:
+ capsule.unknown_capsule_data() =
+ capsule_data_reader.ReadRemainingPayload();
+ }
+ if (!visitor_->OnCapsule(capsule)) {
+ ReportParseFailure("Visitor failed to process capsule");
+ return 0;
+ }
+ return capsule_fragment_reader.PreviouslyReadPayload().length();
+}
+
+void CapsuleParser::ReportParseFailure(const std::string& error_message) {
+ if (parsing_error_occurred_) {
+ QUIC_BUG(multiple parse errors) << "Experienced multiple parse failures";
+ return;
+ }
+ parsing_error_occurred_ = true;
+ visitor_->OnCapsuleParseFailure(error_message);
+}
+
+void CapsuleParser::ErrorIfThereIsRemainingBufferedData() {
+ if (parsing_error_occurred_) {
+ return;
+ }
+ if (!buffered_data_.empty()) {
+ ReportParseFailure("Incomplete capsule left at the end of the stream");
+ }
+}
+
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/capsule.h b/chromium/net/third_party/quiche/src/quic/core/http/capsule.h
new file mode 100644
index 00000000000..5198b4670d4
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/http/capsule.h
@@ -0,0 +1,254 @@
+// Copyright (c) 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_CORE_HTTP_CAPSULE_H_
+#define QUICHE_QUIC_CORE_HTTP_CAPSULE_H_
+
+#include <cstdint>
+#include <string>
+
+#include "absl/strings/str_cat.h"
+#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
+#include "quic/core/quic_buffer_allocator.h"
+#include "quic/core/quic_data_reader.h"
+#include "quic/core/quic_types.h"
+#include "common/platform/api/quiche_logging.h"
+
+namespace quic {
+
+enum class CapsuleType : uint64_t {
+ // Casing in this enum matches the IETF specification.
+ DATAGRAM = 0xff37a0,
+ REGISTER_DATAGRAM_CONTEXT = 0xff37a1,
+ REGISTER_DATAGRAM_NO_CONTEXT = 0xff37a2,
+ CLOSE_DATAGRAM_CONTEXT = 0xff37a3,
+ CLOSE_WEBTRANSPORT_SESSION = 0x2843,
+};
+
+QUIC_EXPORT_PRIVATE std::string CapsuleTypeToString(CapsuleType capsule_type);
+QUIC_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
+ const CapsuleType& capsule_type);
+
+enum class DatagramFormatType : uint64_t {
+ // Casing in this enum matches the IETF specification.
+ UDP_PAYLOAD = 0xff6f00,
+ WEBTRANSPORT = 0xff7c00,
+};
+
+QUIC_EXPORT_PRIVATE std::string DatagramFormatTypeToString(
+ DatagramFormatType datagram_format_type);
+QUIC_EXPORT_PRIVATE std::ostream& operator<<(
+ std::ostream& os, const DatagramFormatType& datagram_format_type);
+
+enum class ContextCloseCode : uint64_t {
+ // Casing in this enum matches the IETF specification.
+ CLOSE_NO_ERROR = 0xff78a0, // NO_ERROR already exists in winerror.h.
+ UNKNOWN_FORMAT = 0xff78a1,
+ DENIED = 0xff78a2,
+ RESOURCE_LIMIT = 0xff78a3,
+};
+
+QUIC_EXPORT_PRIVATE std::string ContextCloseCodeToString(
+ ContextCloseCode context_close_code);
+QUIC_EXPORT_PRIVATE std::ostream& operator<<(
+ std::ostream& os, const ContextCloseCode& context_close_code);
+
+struct QUIC_EXPORT_PRIVATE DatagramCapsule {
+ absl::optional<QuicDatagramContextId> context_id;
+ absl::string_view http_datagram_payload;
+};
+struct QUIC_EXPORT_PRIVATE RegisterDatagramContextCapsule {
+ QuicDatagramContextId context_id;
+ DatagramFormatType format_type;
+ absl::string_view format_additional_data;
+};
+struct QUIC_EXPORT_PRIVATE RegisterDatagramNoContextCapsule {
+ DatagramFormatType format_type;
+ absl::string_view format_additional_data;
+};
+struct QUIC_EXPORT_PRIVATE CloseDatagramContextCapsule {
+ QuicDatagramContextId context_id;
+ ContextCloseCode close_code;
+ absl::string_view close_details;
+};
+struct QUIC_EXPORT_PRIVATE CloseWebTransportSessionCapsule {
+ WebTransportSessionError error_code;
+ absl::string_view error_message;
+};
+
+// Capsule from draft-ietf-masque-h3-datagram.
+// IMPORTANT NOTE: Capsule does not own any of the absl::string_view memory it
+// points to. Strings saved into a capsule must outlive the capsule object. Any
+// code that sees a capsule in a callback needs to either process it immediately
+// or perform its own deep copy.
+class QUIC_EXPORT_PRIVATE Capsule {
+ public:
+ static Capsule Datagram(
+ absl::optional<QuicDatagramContextId> context_id = absl::nullopt,
+ absl::string_view http_datagram_payload = absl::string_view());
+ static Capsule RegisterDatagramContext(
+ QuicDatagramContextId context_id, DatagramFormatType format_type,
+ absl::string_view format_additional_data = absl::string_view());
+ static Capsule RegisterDatagramNoContext(
+ DatagramFormatType format_type,
+ absl::string_view format_additional_data = absl::string_view());
+ static Capsule CloseDatagramContext(
+ QuicDatagramContextId context_id,
+ ContextCloseCode close_code = ContextCloseCode::CLOSE_NO_ERROR,
+ absl::string_view close_details = absl::string_view());
+ static Capsule CloseWebTransportSession(
+ WebTransportSessionError error_code = 0,
+ absl::string_view error_message = "");
+ static Capsule Unknown(
+ uint64_t capsule_type,
+ absl::string_view unknown_capsule_data = absl::string_view());
+
+ explicit Capsule(CapsuleType capsule_type);
+ Capsule(const Capsule& other);
+ Capsule& operator=(const Capsule& other);
+ bool operator==(const Capsule& other) const;
+
+ // Human-readable information string for debugging purposes.
+ std::string ToString() const;
+ friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
+ const Capsule& capsule);
+
+ CapsuleType capsule_type() const { return capsule_type_; }
+ DatagramCapsule& datagram_capsule() {
+ QUICHE_DCHECK_EQ(capsule_type_, CapsuleType::DATAGRAM);
+ return datagram_capsule_;
+ }
+ const DatagramCapsule& datagram_capsule() const {
+ QUICHE_DCHECK_EQ(capsule_type_, CapsuleType::DATAGRAM);
+ return datagram_capsule_;
+ }
+ RegisterDatagramContextCapsule& register_datagram_context_capsule() {
+ QUICHE_DCHECK_EQ(capsule_type_, CapsuleType::REGISTER_DATAGRAM_CONTEXT);
+ return register_datagram_context_capsule_;
+ }
+ const RegisterDatagramContextCapsule& register_datagram_context_capsule()
+ const {
+ QUICHE_DCHECK_EQ(capsule_type_, CapsuleType::REGISTER_DATAGRAM_CONTEXT);
+ return register_datagram_context_capsule_;
+ }
+ RegisterDatagramNoContextCapsule& register_datagram_no_context_capsule() {
+ QUICHE_DCHECK_EQ(capsule_type_, CapsuleType::REGISTER_DATAGRAM_NO_CONTEXT);
+ return register_datagram_no_context_capsule_;
+ }
+ const RegisterDatagramNoContextCapsule& register_datagram_no_context_capsule()
+ const {
+ QUICHE_DCHECK_EQ(capsule_type_, CapsuleType::REGISTER_DATAGRAM_NO_CONTEXT);
+ return register_datagram_no_context_capsule_;
+ }
+ CloseDatagramContextCapsule& close_datagram_context_capsule() {
+ QUICHE_DCHECK_EQ(capsule_type_, CapsuleType::CLOSE_DATAGRAM_CONTEXT);
+ return close_datagram_context_capsule_;
+ }
+ const CloseDatagramContextCapsule& close_datagram_context_capsule() const {
+ QUICHE_DCHECK_EQ(capsule_type_, CapsuleType::CLOSE_DATAGRAM_CONTEXT);
+ return close_datagram_context_capsule_;
+ }
+ CloseWebTransportSessionCapsule& close_web_transport_session_capsule() {
+ QUICHE_DCHECK_EQ(capsule_type_, CapsuleType::CLOSE_WEBTRANSPORT_SESSION);
+ return close_web_transport_session_capsule_;
+ }
+ const CloseWebTransportSessionCapsule& close_web_transport_session_capsule()
+ const {
+ QUICHE_DCHECK_EQ(capsule_type_, CapsuleType::CLOSE_WEBTRANSPORT_SESSION);
+ return close_web_transport_session_capsule_;
+ }
+ absl::string_view& unknown_capsule_data() {
+ QUICHE_DCHECK(capsule_type_ != CapsuleType::DATAGRAM &&
+ capsule_type_ != CapsuleType::REGISTER_DATAGRAM_CONTEXT &&
+ capsule_type_ != CapsuleType::REGISTER_DATAGRAM_NO_CONTEXT &&
+ capsule_type_ != CapsuleType::CLOSE_DATAGRAM_CONTEXT &&
+ capsule_type_ != CapsuleType::CLOSE_WEBTRANSPORT_SESSION)
+ << capsule_type_;
+ return unknown_capsule_data_;
+ }
+ const absl::string_view& unknown_capsule_data() const {
+ QUICHE_DCHECK(capsule_type_ != CapsuleType::DATAGRAM &&
+ capsule_type_ != CapsuleType::REGISTER_DATAGRAM_CONTEXT &&
+ capsule_type_ != CapsuleType::REGISTER_DATAGRAM_NO_CONTEXT &&
+ capsule_type_ != CapsuleType::CLOSE_DATAGRAM_CONTEXT &&
+ capsule_type_ != CapsuleType::CLOSE_WEBTRANSPORT_SESSION)
+ << capsule_type_;
+ return unknown_capsule_data_;
+ }
+
+ private:
+ CapsuleType capsule_type_;
+ union {
+ DatagramCapsule datagram_capsule_;
+ RegisterDatagramContextCapsule register_datagram_context_capsule_;
+ RegisterDatagramNoContextCapsule register_datagram_no_context_capsule_;
+ CloseDatagramContextCapsule close_datagram_context_capsule_;
+ CloseWebTransportSessionCapsule close_web_transport_session_capsule_;
+ absl::string_view unknown_capsule_data_;
+ };
+};
+
+namespace test {
+class CapsuleParserPeer;
+} // namespace test
+
+class QUIC_EXPORT_PRIVATE CapsuleParser {
+ public:
+ class QUIC_EXPORT_PRIVATE Visitor {
+ public:
+ virtual ~Visitor() {}
+
+ // Called when a capsule has been successfully parsed. The return value
+ // indicates whether the contents of the capsule are valid: if false is
+ // returned, the parse operation will be considered failed and
+ // OnCapsuleParseFailure will be called. Note that since Capsule does not
+ // own the memory backing its string_views, that memory is only valid until
+ // this callback returns. Visitors that wish to access the capsule later
+ // MUST make a deep copy before this returns.
+ virtual bool OnCapsule(const Capsule& capsule) = 0;
+
+ virtual void OnCapsuleParseFailure(const std::string& error_message) = 0;
+ };
+
+ // |visitor| must be non-null, and must outlive CapsuleParser.
+ explicit CapsuleParser(Visitor* visitor);
+
+ void set_datagram_context_id_present(bool datagram_context_id_present) {
+ datagram_context_id_present_ = datagram_context_id_present;
+ }
+
+ // Ingests a capsule fragment (any fragment of bytes from the capsule data
+ // stream) and parses and complete capsules it encounters. Returns false if a
+ // parsing error occurred.
+ bool IngestCapsuleFragment(absl::string_view capsule_fragment);
+
+ void ErrorIfThereIsRemainingBufferedData();
+
+ friend class test::CapsuleParserPeer;
+
+ private:
+ // Attempts to parse a single capsule from |buffered_data_|. If a full capsule
+ // is not available, returns 0. If a parsing error occurs, returns 0.
+ // Otherwise, returns the number of bytes in the parsed capsule.
+ size_t AttemptParseCapsule();
+ void ReportParseFailure(const std::string& error_message);
+
+ // Whether HTTP Datagram Context IDs are present.
+ bool datagram_context_id_present_ = false;
+ // Whether a parsing error has occurred.
+ bool parsing_error_occurred_ = false;
+ // Visitor which will receive callbacks, unowned.
+ Visitor* visitor_;
+
+ std::string buffered_data_;
+};
+
+// Serializes |capsule| into a newly allocated buffer.
+QUIC_EXPORT_PRIVATE QuicBuffer SerializeCapsule(const Capsule& capsule,
+ QuicBufferAllocator* allocator);
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_CORE_HTTP_CAPSULE_H_
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/capsule_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/capsule_test.cc
new file mode 100644
index 00000000000..66cb3d07691
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/http/capsule_test.cc
@@ -0,0 +1,330 @@
+// Copyright (c) 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "quic/core/http/capsule.h"
+
+#include <cstddef>
+#include <deque>
+#include <string>
+#include <vector>
+
+#include "absl/strings/escaping.h"
+#include "absl/strings/string_view.h"
+#include "quic/platform/api/quic_test.h"
+#include "quic/test_tools/quic_test_utils.h"
+#include "common/test_tools/quiche_test_utils.h"
+
+using ::testing::_;
+using ::testing::InSequence;
+using ::testing::Return;
+
+namespace quic {
+namespace test {
+
+class CapsuleParserPeer {
+ public:
+ static std::string* buffered_data(CapsuleParser* capsule_parser) {
+ return &capsule_parser->buffered_data_;
+ }
+};
+
+namespace {
+
+constexpr DatagramFormatType kFakeFormatType =
+ static_cast<DatagramFormatType>(0x123456);
+constexpr ContextCloseCode kFakeCloseCode =
+ static_cast<ContextCloseCode>(0x654321);
+
+class MockCapsuleParserVisitor : public CapsuleParser::Visitor {
+ public:
+ MockCapsuleParserVisitor() {
+ ON_CALL(*this, OnCapsule(_)).WillByDefault(Return(true));
+ }
+ ~MockCapsuleParserVisitor() override = default;
+ MOCK_METHOD(bool, OnCapsule, (const Capsule& capsule), (override));
+ MOCK_METHOD(void, OnCapsuleParseFailure, (const std::string& error_message),
+ (override));
+};
+
+class CapsuleTest : public QuicTest {
+ public:
+ CapsuleTest() : capsule_parser_(&visitor_) {}
+
+ void ValidateParserIsEmpty() {
+ EXPECT_CALL(visitor_, OnCapsule(_)).Times(0);
+ EXPECT_CALL(visitor_, OnCapsuleParseFailure(_)).Times(0);
+ capsule_parser_.ErrorIfThereIsRemainingBufferedData();
+ EXPECT_TRUE(CapsuleParserPeer::buffered_data(&capsule_parser_)->empty());
+ }
+
+ void TestSerialization(const Capsule& capsule,
+ const std::string& expected_bytes) {
+ QuicBuffer serialized_capsule =
+ SerializeCapsule(capsule, SimpleBufferAllocator::Get());
+ quiche::test::CompareCharArraysWithHexError(
+ "Serialized capsule", serialized_capsule.data(),
+ serialized_capsule.size(), expected_bytes.data(),
+ expected_bytes.size());
+ }
+
+ ::testing::StrictMock<MockCapsuleParserVisitor> visitor_;
+ CapsuleParser capsule_parser_;
+};
+
+TEST_F(CapsuleTest, DatagramCapsule) {
+ std::string capsule_fragment = absl::HexStringToBytes(
+ "80ff37a0" // DATAGRAM capsule type
+ "08" // capsule length
+ "a1a2a3a4a5a6a7a8" // HTTP Datagram payload
+ );
+ std::string datagram_payload = absl::HexStringToBytes("a1a2a3a4a5a6a7a8");
+ Capsule expected_capsule =
+ Capsule::Datagram(/*context_id=*/absl::nullopt, datagram_payload);
+ {
+ EXPECT_CALL(visitor_, OnCapsule(expected_capsule));
+ ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment));
+ }
+ ValidateParserIsEmpty();
+ TestSerialization(expected_capsule, capsule_fragment);
+}
+
+TEST_F(CapsuleTest, DatagramCapsuleWithContext) {
+ std::string capsule_fragment = absl::HexStringToBytes(
+ "80ff37a0" // DATAGRAM capsule type
+ "09" // capsule length
+ "04" // context ID
+ "a1a2a3a4a5a6a7a8" // HTTP Datagram payload
+ );
+ capsule_parser_.set_datagram_context_id_present(true);
+ std::string datagram_payload = absl::HexStringToBytes("a1a2a3a4a5a6a7a8");
+ Capsule expected_capsule =
+ Capsule::Datagram(/*context_id=*/4, datagram_payload);
+ {
+ EXPECT_CALL(visitor_, OnCapsule(expected_capsule));
+ ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment));
+ }
+ ValidateParserIsEmpty();
+ TestSerialization(expected_capsule, capsule_fragment);
+}
+
+TEST_F(CapsuleTest, RegisterContextCapsule) {
+ std::string capsule_fragment = absl::HexStringToBytes(
+ "80ff37a1" // REGISTER_DATAGRAM_CONTEXT capsule type
+ "0d" // capsule length
+ "04" // context ID
+ "80123456" // 0x123456 datagram format type
+ "f1f2f3f4f5f6f7f8" // format additional data
+ );
+ std::string format_additional_data =
+ absl::HexStringToBytes("f1f2f3f4f5f6f7f8");
+ Capsule expected_capsule = Capsule::RegisterDatagramContext(
+ /*context_id=*/4, kFakeFormatType, format_additional_data);
+ {
+ EXPECT_CALL(visitor_, OnCapsule(expected_capsule));
+ ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment));
+ }
+ ValidateParserIsEmpty();
+ TestSerialization(expected_capsule, capsule_fragment);
+}
+
+TEST_F(CapsuleTest, RegisterNoContextCapsule) {
+ std::string capsule_fragment = absl::HexStringToBytes(
+ "80ff37a2" // REGISTER_DATAGRAM_NO_CONTEXT capsule type
+ "0c" // capsule length
+ "80123456" // 0x123456 datagram format type
+ "f1f2f3f4f5f6f7f8" // format additional data
+ );
+ std::string format_additional_data =
+ absl::HexStringToBytes("f1f2f3f4f5f6f7f8");
+ Capsule expected_capsule = Capsule::RegisterDatagramNoContext(
+ kFakeFormatType, format_additional_data);
+ {
+ EXPECT_CALL(visitor_, OnCapsule(expected_capsule));
+ ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment));
+ }
+ ValidateParserIsEmpty();
+ TestSerialization(expected_capsule, capsule_fragment);
+}
+
+TEST_F(CapsuleTest, CloseContextCapsule) {
+ std::string capsule_fragment = absl::HexStringToBytes(
+ "80ff37a3" // CLOSE_DATAGRAM_CONTEXT capsule type
+ "27" // capsule length
+ "04" // context ID
+ "80654321" // 0x654321 close code
+ );
+ std::string close_details = "All your contexts are belong to us";
+ capsule_fragment += close_details;
+ Capsule expected_capsule = Capsule::CloseDatagramContext(
+ /*context_id=*/4, kFakeCloseCode, close_details);
+ {
+ EXPECT_CALL(visitor_, OnCapsule(expected_capsule));
+ ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment));
+ }
+ ValidateParserIsEmpty();
+ TestSerialization(expected_capsule, capsule_fragment);
+}
+
+TEST_F(CapsuleTest, CloseWebTransportStreamCapsule) {
+ std::string capsule_fragment = absl::HexStringToBytes(
+ "6843" // CLOSE_WEBTRANSPORT_STREAM capsule type
+ "09" // capsule length
+ "00001234" // 0x1234 error code
+ "68656c6c6f" // "hello" error message
+ );
+ Capsule expected_capsule = Capsule::CloseWebTransportSession(
+ /*error_code=*/0x1234, /*error_message=*/"hello");
+ {
+ EXPECT_CALL(visitor_, OnCapsule(expected_capsule));
+ ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment));
+ }
+ ValidateParserIsEmpty();
+ TestSerialization(expected_capsule, capsule_fragment);
+}
+
+TEST_F(CapsuleTest, UnknownCapsule) {
+ std::string capsule_fragment = absl::HexStringToBytes(
+ "33" // unknown capsule type of 0x33
+ "08" // capsule length
+ "a1a2a3a4a5a6a7a8" // unknown capsule data
+ );
+ std::string unknown_capsule_data = absl::HexStringToBytes("a1a2a3a4a5a6a7a8");
+ Capsule expected_capsule = Capsule::Unknown(0x33, unknown_capsule_data);
+ {
+ EXPECT_CALL(visitor_, OnCapsule(expected_capsule));
+ ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment));
+ }
+ ValidateParserIsEmpty();
+ TestSerialization(expected_capsule, capsule_fragment);
+}
+
+TEST_F(CapsuleTest, TwoDatagramCapsules) {
+ std::string capsule_fragment = absl::HexStringToBytes(
+ "80ff37a0" // DATAGRAM capsule type
+ "08" // capsule length
+ "a1a2a3a4a5a6a7a8" // HTTP Datagram payload
+ "80ff37a0" // DATAGRAM capsule type
+ "08" // capsule length
+ "b1b2b3b4b5b6b7b8" // HTTP Datagram payload
+ );
+ std::string datagram_payload1 = absl::HexStringToBytes("a1a2a3a4a5a6a7a8");
+ std::string datagram_payload2 = absl::HexStringToBytes("b1b2b3b4b5b6b7b8");
+ Capsule expected_capsule1 =
+ Capsule::Datagram(/*context_id=*/absl::nullopt, datagram_payload1);
+ Capsule expected_capsule2 =
+ Capsule::Datagram(/*context_id=*/absl::nullopt, datagram_payload2);
+ {
+ InSequence s;
+ EXPECT_CALL(visitor_, OnCapsule(expected_capsule1));
+ EXPECT_CALL(visitor_, OnCapsule(expected_capsule2));
+ ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment));
+ }
+ ValidateParserIsEmpty();
+}
+
+TEST_F(CapsuleTest, TwoDatagramCapsulesPartialReads) {
+ std::string capsule_fragment1 = absl::HexStringToBytes(
+ "80ff37a0" // first capsule DATAGRAM capsule type
+ "08" // frist capsule length
+ "a1a2a3a4" // first half of HTTP Datagram payload of first capsule
+ );
+ std::string capsule_fragment2 = absl::HexStringToBytes(
+ "a5a6a7a8" // second half of HTTP Datagram payload 1
+ "80ff37a0" // second capsule DATAGRAM capsule type
+ );
+ std::string capsule_fragment3 = absl::HexStringToBytes(
+ "08" // second capsule length
+ "b1b2b3b4b5b6b7b8" // HTTP Datagram payload of second capsule
+ );
+ capsule_parser_.ErrorIfThereIsRemainingBufferedData();
+ std::string datagram_payload1 = absl::HexStringToBytes("a1a2a3a4a5a6a7a8");
+ std::string datagram_payload2 = absl::HexStringToBytes("b1b2b3b4b5b6b7b8");
+ Capsule expected_capsule1 =
+ Capsule::Datagram(/*context_id=*/absl::nullopt, datagram_payload1);
+ Capsule expected_capsule2 =
+ Capsule::Datagram(/*context_id=*/absl::nullopt, datagram_payload2);
+ {
+ InSequence s;
+ EXPECT_CALL(visitor_, OnCapsule(expected_capsule1));
+ EXPECT_CALL(visitor_, OnCapsule(expected_capsule2));
+ ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment1));
+ ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment2));
+ ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment3));
+ }
+ ValidateParserIsEmpty();
+}
+
+TEST_F(CapsuleTest, TwoDatagramCapsulesOneByteAtATime) {
+ std::string capsule_fragment = absl::HexStringToBytes(
+ "80ff37a0" // DATAGRAM capsule type
+ "08" // capsule length
+ "a1a2a3a4a5a6a7a8" // HTTP Datagram payload
+ "80ff37a0" // DATAGRAM capsule type
+ "08" // capsule length
+ "b1b2b3b4b5b6b7b8" // HTTP Datagram payload
+ );
+ std::string datagram_payload1 = absl::HexStringToBytes("a1a2a3a4a5a6a7a8");
+ std::string datagram_payload2 = absl::HexStringToBytes("b1b2b3b4b5b6b7b8");
+ Capsule expected_capsule1 =
+ Capsule::Datagram(/*context_id=*/absl::nullopt, datagram_payload1);
+ Capsule expected_capsule2 =
+ Capsule::Datagram(/*context_id=*/absl::nullopt, datagram_payload2);
+ for (size_t i = 0; i < capsule_fragment.size(); i++) {
+ if (i < capsule_fragment.size() / 2 - 1) {
+ EXPECT_CALL(visitor_, OnCapsule(_)).Times(0);
+ ASSERT_TRUE(
+ capsule_parser_.IngestCapsuleFragment(capsule_fragment.substr(i, 1)));
+ } else if (i == capsule_fragment.size() / 2 - 1) {
+ EXPECT_CALL(visitor_, OnCapsule(expected_capsule1));
+ ASSERT_TRUE(
+ capsule_parser_.IngestCapsuleFragment(capsule_fragment.substr(i, 1)));
+ EXPECT_TRUE(CapsuleParserPeer::buffered_data(&capsule_parser_)->empty());
+ } else if (i < capsule_fragment.size() - 1) {
+ EXPECT_CALL(visitor_, OnCapsule(_)).Times(0);
+ ASSERT_TRUE(
+ capsule_parser_.IngestCapsuleFragment(capsule_fragment.substr(i, 1)));
+ } else {
+ EXPECT_CALL(visitor_, OnCapsule(expected_capsule2));
+ ASSERT_TRUE(
+ capsule_parser_.IngestCapsuleFragment(capsule_fragment.substr(i, 1)));
+ EXPECT_TRUE(CapsuleParserPeer::buffered_data(&capsule_parser_)->empty());
+ }
+ }
+ capsule_parser_.ErrorIfThereIsRemainingBufferedData();
+ EXPECT_TRUE(CapsuleParserPeer::buffered_data(&capsule_parser_)->empty());
+}
+
+TEST_F(CapsuleTest, PartialCapsuleThenError) {
+ std::string capsule_fragment = absl::HexStringToBytes(
+ "80ff37a0" // DATAGRAM capsule type
+ "08" // capsule length
+ "a1a2a3a4" // first half of HTTP Datagram payload
+ );
+ EXPECT_CALL(visitor_, OnCapsule(_)).Times(0);
+ {
+ EXPECT_CALL(visitor_, OnCapsuleParseFailure(_)).Times(0);
+ ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment));
+ }
+ {
+ EXPECT_CALL(visitor_,
+ OnCapsuleParseFailure(
+ "Incomplete capsule left at the end of the stream"));
+ capsule_parser_.ErrorIfThereIsRemainingBufferedData();
+ }
+}
+
+TEST_F(CapsuleTest, RejectOverlyLongCapsule) {
+ std::string capsule_fragment = absl::HexStringToBytes(
+ "33" // unknown capsule type of 0x33
+ "80123456" // capsule length
+ ) +
+ std::string(1111111, '?');
+ EXPECT_CALL(visitor_, OnCapsuleParseFailure(
+ "Refusing to buffer too much capsule data"));
+ EXPECT_FALSE(capsule_parser_.IngestCapsuleFragment(capsule_fragment));
+}
+
+} // namespace
+} // namespace test
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/end_to_end_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/end_to_end_test.cc
index e64d8e62581..54f6fa9fbdf 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
@@ -80,7 +80,7 @@ using ::testing::_;
using ::testing::Assign;
using ::testing::Invoke;
using ::testing::NiceMock;
-using testing::NotNull;
+using ::testing::UnorderedElementsAreArray;
namespace quic {
namespace test {
@@ -378,7 +378,10 @@ class EndToEndTest : public QuicTestWithParam<TestParams> {
copt.push_back(kILD0);
}
copt.push_back(kPLE1);
- copt.push_back(kRVCM);
+ if (!GetQuicReloadableFlag(
+ quic_remove_connection_migration_connection_option)) {
+ copt.push_back(kRVCM);
+ }
client_config_.SetConnectionOptionsToSend(copt);
// Start the server first, because CreateQuicClient() attempts
@@ -724,21 +727,37 @@ class EndToEndTest : public QuicTestWithParam<TestParams> {
}
std::string ReadDataFromWebTransportStreamUntilFin(
- WebTransportStream* stream) {
+ WebTransportStream* stream, MockStreamVisitor* visitor = nullptr) {
+ QuicStreamId id = stream->GetStreamId();
std::string buffer;
+
+ // Try reading data if immediately available.
+ WebTransportStream::ReadResult result = stream->Read(&buffer);
+ if (result.fin) {
+ return buffer;
+ }
+
while (true) {
bool can_read = false;
- auto visitor = std::make_unique<MockStreamVisitor>();
+ if (visitor == nullptr) {
+ auto visitor_owned = std::make_unique<MockStreamVisitor>();
+ visitor = visitor_owned.get();
+ stream->SetVisitor(std::move(visitor_owned));
+ }
EXPECT_CALL(*visitor, OnCanRead()).WillOnce(Assign(&can_read, true));
- stream->SetVisitor(std::move(visitor));
client_->WaitUntil(5000 /*ms*/, [&can_read]() { return can_read; });
if (!can_read) {
- ADD_FAILURE() << "Waiting for readable data on stream "
- << stream->GetStreamId() << " timed out";
+ ADD_FAILURE() << "Waiting for readable data on stream " << id
+ << " timed out";
+ return buffer;
+ }
+ if (GetClientSession()->GetOrCreateSpdyDataStream(id) == nullptr) {
+ ADD_FAILURE() << "Stream " << id
+ << " was deleted while waiting for incoming data";
return buffer;
}
- WebTransportStream::ReadResult result = stream->Read(&buffer);
+ result = stream->Read(&buffer);
if (result.fin) {
return buffer;
}
@@ -750,6 +769,19 @@ class EndToEndTest : public QuicTestWithParam<TestParams> {
}
}
+ void ReadAllIncomingWebTransportUnidirectionalStreams(
+ WebTransportSession* session) {
+ while (true) {
+ WebTransportStream* received_stream =
+ session->AcceptIncomingUnidirectionalStream();
+ if (received_stream == nullptr) {
+ break;
+ }
+ received_webtransport_unidirectional_streams_.push_back(
+ ReadDataFromWebTransportStreamUntilFin(received_stream));
+ }
+ }
+
void WaitForNewConnectionIds() {
// Wait until a new server CID is available for another migration.
const auto* client_connection = GetClientConnection();
@@ -790,6 +822,7 @@ class EndToEndTest : public QuicTestWithParam<TestParams> {
int override_client_connection_id_length_ = -1;
uint8_t expected_server_connection_id_length_;
bool enable_web_transport_ = false;
+ std::vector<std::string> received_webtransport_unidirectional_streams_;
};
// Run all end to end tests with all supported versions.
@@ -799,6 +832,8 @@ INSTANTIATE_TEST_SUITE_P(EndToEndTests,
::testing::PrintToStringParamName());
TEST_P(EndToEndTest, HandshakeSuccessful) {
+ SetQuicReloadableFlag(quic_delay_sequencer_buffer_allocation_until_new_data,
+ true);
ASSERT_TRUE(Initialize());
EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
ASSERT_TRUE(server_thread_);
@@ -854,6 +889,51 @@ TEST_P(EndToEndTest, HandshakeSuccessful) {
server_thread_->Resume();
}
+TEST_P(EndToEndTest, ExportKeyingMaterial) {
+ ASSERT_TRUE(Initialize());
+ if (!version_.UsesTls()) {
+ return;
+ }
+ const char* kExportLabel = "label";
+ const int kExportLen = 30;
+ std::string client_keying_material_export, server_keying_material_export;
+
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
+ ASSERT_TRUE(server_thread_);
+ server_thread_->WaitForCryptoHandshakeConfirmed();
+
+ server_thread_->Pause();
+ QuicSpdySession* server_session = GetServerSession();
+ QuicCryptoStream* server_crypto_stream = nullptr;
+ if (server_session != nullptr) {
+ server_crypto_stream =
+ QuicSessionPeer::GetMutableCryptoStream(server_session);
+ } else {
+ ADD_FAILURE() << "Missing server session";
+ }
+ if (server_crypto_stream != nullptr) {
+ ASSERT_TRUE(server_crypto_stream->ExportKeyingMaterial(
+ kExportLabel, /*context=*/"", kExportLen,
+ &server_keying_material_export));
+
+ } else {
+ ADD_FAILURE() << "Missing server crypto stream";
+ }
+ server_thread_->Resume();
+
+ QuicSpdyClientSession* client_session = GetClientSession();
+ ASSERT_TRUE(client_session);
+ QuicCryptoStream* client_crypto_stream =
+ QuicSessionPeer::GetMutableCryptoStream(client_session);
+ ASSERT_TRUE(client_crypto_stream);
+ ASSERT_TRUE(client_crypto_stream->ExportKeyingMaterial(
+ kExportLabel, /*context=*/"", kExportLen,
+ &client_keying_material_export));
+ ASSERT_EQ(client_keying_material_export.size(),
+ static_cast<size_t>(kExportLen));
+ EXPECT_EQ(client_keying_material_export, server_keying_material_export);
+}
+
TEST_P(EndToEndTest, SimpleRequestResponse) {
ASSERT_TRUE(Initialize());
@@ -5644,7 +5724,7 @@ class CopyingPacketWriter : public PacketDroppingTestWriter {
std::vector<std::unique_ptr<QuicEncryptedPacket>> packets_;
};
-TEST_P(EndToEndTest, ChaosProtection) {
+TEST_P(EndToEndTest, ChaosProtectionDisabled) {
if (!version_.UsesCryptoFrames()) {
ASSERT_TRUE(Initialize());
return;
@@ -5653,8 +5733,8 @@ TEST_P(EndToEndTest, ChaosProtection) {
auto copying_writer = new CopyingPacketWriter(1);
delete client_writer_;
client_writer_ = copying_writer;
- // Enable chaos protection and perform an HTTP request.
- client_config_.SetClientConnectionOptions(QuicTagVector{kCHSP});
+ // Disable chaos protection and perform an HTTP request.
+ client_config_.SetClientConnectionOptions(QuicTagVector{kNCHP});
ASSERT_TRUE(Initialize());
SendSynchronousFooRequestAndCheckResponse();
// Parse the saved packet to make sure it's valid.
@@ -5667,31 +5747,15 @@ TEST_P(EndToEndTest, ChaosProtection) {
// can inspect the contents of this packet.
}
-TEST_P(EndToEndTest, ChaosProtectionWithMultiPacketChlo) {
- if (!version_.UsesCryptoFrames()) {
- ASSERT_TRUE(Initialize());
- return;
- }
- // Enable chaos protection.
- client_config_.SetClientConnectionOptions(QuicTagVector{kCHSP});
- // Add a transport parameter to make the client hello span multiple packets.
- constexpr auto kCustomParameter =
- static_cast<TransportParameters::TransportParameterId>(0xff34);
- client_config_.custom_transport_parameters_to_send()[kCustomParameter] =
- std::string(2000, '?');
- ASSERT_TRUE(Initialize());
- SendSynchronousFooRequestAndCheckResponse();
-}
-
-TEST_P(EndToEndTest, PermuteTlsExtensions) {
+TEST_P(EndToEndTest, DisablePermuteTlsExtensions) {
if (!version_.UsesTls()) {
ASSERT_TRUE(Initialize());
return;
}
- // Enable TLS extension permutation and perform an HTTP request.
- client_config_.SetClientConnectionOptions(QuicTagVector{kBPTE});
+ // Disable TLS extension permutation and perform an HTTP request.
+ client_config_.SetClientConnectionOptions(QuicTagVector{kNBPE});
ASSERT_TRUE(Initialize());
- EXPECT_TRUE(GetClientSession()->permutes_tls_extensions());
+ EXPECT_FALSE(GetClientSession()->permutes_tls_extensions());
SendSynchronousFooRequestAndCheckResponse();
}
@@ -5884,7 +5948,7 @@ TEST_P(EndToEndTest, KeyUpdateInitiatedByBoth) {
}
TEST_P(EndToEndTest, KeyUpdateInitiatedByConfidentialityLimit) {
- SetQuicFlag(FLAGS_quic_key_update_confidentiality_limit, 4U);
+ SetQuicFlag(FLAGS_quic_key_update_confidentiality_limit, 16U);
if (!version_.UsesTls()) {
// Key Update is only supported in TLS handshake.
@@ -5910,9 +5974,11 @@ TEST_P(EndToEndTest, KeyUpdateInitiatedByConfidentialityLimit) {
},
QuicTime::Delta::FromSeconds(5));
- SendSynchronousFooRequestAndCheckResponse();
- SendSynchronousFooRequestAndCheckResponse();
- SendSynchronousFooRequestAndCheckResponse();
+ for (uint64_t i = 0;
+ i < GetQuicFlag(FLAGS_quic_key_update_confidentiality_limit); ++i) {
+ SendSynchronousFooRequestAndCheckResponse();
+ }
+
// Don't know exactly how many packets will be sent in each request/response,
// so just test that at least one key update occurred.
EXPECT_LE(1u, client_connection->GetStats().key_update_count);
@@ -6049,6 +6115,30 @@ TEST_P(EndToEndTest, WebTransportSessionSetup) {
server_thread_->Resume();
}
+TEST_P(EndToEndTest, WebTransportSessionSetupWithEchoWithSuffix) {
+ enable_web_transport_ = true;
+ ASSERT_TRUE(Initialize());
+
+ if (!version_.UsesHttp3()) {
+ return;
+ }
+
+ // "/echoFoo" should be accepted as "echo" with "set-header" query.
+ WebTransportHttp3* web_transport = CreateWebTransportSession(
+ "/echoFoo?set-header=bar:baz", /*wait_for_server_response=*/true);
+ ASSERT_NE(web_transport, nullptr);
+
+ server_thread_->Pause();
+ QuicSpdySession* server_session = GetServerSession();
+ EXPECT_TRUE(server_session->GetWebTransportSession(web_transport->id()) !=
+ nullptr);
+ server_thread_->Resume();
+ const spdy::SpdyHeaderBlock* response_headers = client_->response_headers();
+ auto it = response_headers->find("bar");
+ EXPECT_NE(it, response_headers->end());
+ EXPECT_EQ(it->second, "baz");
+}
+
TEST_P(EndToEndTest, WebTransportSessionWithLoss) {
enable_web_transport_ = true;
// Enable loss to verify all permutations of receiving SETTINGS and
@@ -6087,6 +6177,13 @@ TEST_P(EndToEndTest, WebTransportSessionUnidirectionalStream) {
WebTransportStream* outgoing_stream =
session->OpenOutgoingUnidirectionalStream();
ASSERT_TRUE(outgoing_stream != nullptr);
+
+ auto stream_visitor = std::make_unique<NiceMock<MockStreamVisitor>>();
+ bool data_acknowledged = false;
+ EXPECT_CALL(*stream_visitor, OnWriteSideInDataRecvdState())
+ .WillOnce(Assign(&data_acknowledged, true));
+ outgoing_stream->SetVisitor(std::move(stream_visitor));
+
EXPECT_TRUE(outgoing_stream->Write("test"));
EXPECT_TRUE(outgoing_stream->SendFin());
@@ -6102,6 +6199,10 @@ TEST_P(EndToEndTest, WebTransportSessionUnidirectionalStream) {
WebTransportStream::ReadResult result = received_stream->Read(&received_data);
EXPECT_EQ(received_data, "test");
EXPECT_TRUE(result.fin);
+
+ client_->WaitUntil(2000,
+ [&data_acknowledged]() { return data_acknowledged; });
+ EXPECT_TRUE(data_acknowledged);
}
TEST_P(EndToEndTest, WebTransportSessionUnidirectionalStreamSentEarly) {
@@ -6152,11 +6253,24 @@ TEST_P(EndToEndTest, WebTransportSessionBidirectionalStream) {
WebTransportStream* stream = session->OpenOutgoingBidirectionalStream();
ASSERT_TRUE(stream != nullptr);
+
+ auto stream_visitor_owned = std::make_unique<NiceMock<MockStreamVisitor>>();
+ MockStreamVisitor* stream_visitor = stream_visitor_owned.get();
+ bool data_acknowledged = false;
+ EXPECT_CALL(*stream_visitor, OnWriteSideInDataRecvdState())
+ .WillOnce(Assign(&data_acknowledged, true));
+ stream->SetVisitor(std::move(stream_visitor_owned));
+
EXPECT_TRUE(stream->Write("test"));
EXPECT_TRUE(stream->SendFin());
- std::string received_data = ReadDataFromWebTransportStreamUntilFin(stream);
+ std::string received_data =
+ ReadDataFromWebTransportStreamUntilFin(stream, stream_visitor);
EXPECT_EQ(received_data, "test");
+
+ client_->WaitUntil(2000,
+ [&data_acknowledged]() { return data_acknowledged; });
+ EXPECT_TRUE(data_acknowledged);
}
TEST_P(EndToEndTest, WebTransportSessionBidirectionalStreamWithBuffering) {
@@ -6239,6 +6353,183 @@ TEST_P(EndToEndTest, WebTransportDatagrams) {
EXPECT_GT(received, 0);
}
+TEST_P(EndToEndTest, WebTransportSessionClose) {
+ enable_web_transport_ = true;
+ ASSERT_TRUE(Initialize());
+
+ if (!version_.UsesHttp3()) {
+ return;
+ }
+
+ WebTransportHttp3* session =
+ CreateWebTransportSession("/echo", /*wait_for_server_response=*/true);
+ ASSERT_TRUE(session != nullptr);
+ NiceMock<MockClientVisitor>& visitor = SetupWebTransportVisitor(session);
+
+ WebTransportStream* stream = session->OpenOutgoingBidirectionalStream();
+ ASSERT_TRUE(stream != nullptr);
+ QuicStreamId stream_id = stream->GetStreamId();
+ EXPECT_TRUE(stream->Write("test"));
+ // Keep stream open.
+
+ bool close_received = false;
+ EXPECT_CALL(visitor, OnSessionClosed(42, "test error"))
+ .WillOnce(Assign(&close_received, true));
+ session->CloseSession(42, "test error");
+ client_->WaitUntil(2000, [&]() { return close_received; });
+ EXPECT_TRUE(close_received);
+
+ QuicSpdyStream* spdy_stream =
+ GetClientSession()->GetOrCreateSpdyDataStream(stream_id);
+ EXPECT_TRUE(spdy_stream == nullptr);
+}
+
+TEST_P(EndToEndTest, WebTransportSessionCloseWithoutCapsule) {
+ enable_web_transport_ = true;
+ ASSERT_TRUE(Initialize());
+
+ if (!version_.UsesHttp3()) {
+ return;
+ }
+
+ WebTransportHttp3* session =
+ CreateWebTransportSession("/echo", /*wait_for_server_response=*/true);
+ ASSERT_TRUE(session != nullptr);
+ NiceMock<MockClientVisitor>& visitor = SetupWebTransportVisitor(session);
+
+ WebTransportStream* stream = session->OpenOutgoingBidirectionalStream();
+ ASSERT_TRUE(stream != nullptr);
+ QuicStreamId stream_id = stream->GetStreamId();
+ EXPECT_TRUE(stream->Write("test"));
+ // Keep stream open.
+
+ bool close_received = false;
+ EXPECT_CALL(visitor, OnSessionClosed(0, ""))
+ .WillOnce(Assign(&close_received, true));
+ session->CloseSessionWithFinOnlyForTests();
+ client_->WaitUntil(2000, [&]() { return close_received; });
+ EXPECT_TRUE(close_received);
+
+ QuicSpdyStream* spdy_stream =
+ GetClientSession()->GetOrCreateSpdyDataStream(stream_id);
+ EXPECT_TRUE(spdy_stream == nullptr);
+}
+
+TEST_P(EndToEndTest, WebTransportSessionReceiveClose) {
+ enable_web_transport_ = true;
+ ASSERT_TRUE(Initialize());
+
+ if (!version_.UsesHttp3()) {
+ return;
+ }
+
+ WebTransportHttp3* session = CreateWebTransportSession(
+ "/session-close", /*wait_for_server_response=*/true);
+ ASSERT_TRUE(session != nullptr);
+ NiceMock<MockClientVisitor>& visitor = SetupWebTransportVisitor(session);
+
+ WebTransportStream* stream = session->OpenOutgoingUnidirectionalStream();
+ ASSERT_TRUE(stream != nullptr);
+ QuicStreamId stream_id = stream->GetStreamId();
+ EXPECT_TRUE(stream->Write("42 test error"));
+ EXPECT_TRUE(stream->SendFin());
+
+ // Have some other streams open pending, to ensure they are closed properly.
+ stream = session->OpenOutgoingUnidirectionalStream();
+ stream = session->OpenOutgoingBidirectionalStream();
+
+ bool close_received = false;
+ EXPECT_CALL(visitor, OnSessionClosed(42, "test error"))
+ .WillOnce(Assign(&close_received, true));
+ client_->WaitUntil(2000, [&]() { return close_received; });
+ EXPECT_TRUE(close_received);
+
+ QuicSpdyStream* spdy_stream =
+ GetClientSession()->GetOrCreateSpdyDataStream(stream_id);
+ EXPECT_TRUE(spdy_stream == nullptr);
+}
+
+TEST_P(EndToEndTest, WebTransportSessionStreamTermination) {
+ enable_web_transport_ = true;
+ ASSERT_TRUE(Initialize());
+
+ if (!version_.UsesHttp3()) {
+ return;
+ }
+
+ WebTransportHttp3* session =
+ CreateWebTransportSession("/resets", /*wait_for_server_response=*/true);
+ ASSERT_TRUE(session != nullptr);
+
+ NiceMock<MockClientVisitor>& visitor = SetupWebTransportVisitor(session);
+ EXPECT_CALL(visitor, OnIncomingUnidirectionalStreamAvailable())
+ .WillRepeatedly([this, session]() {
+ ReadAllIncomingWebTransportUnidirectionalStreams(session);
+ });
+
+ WebTransportStream* stream = session->OpenOutgoingBidirectionalStream();
+ QuicStreamId id1 = stream->GetStreamId();
+ ASSERT_TRUE(stream != nullptr);
+ EXPECT_TRUE(stream->Write("test"));
+ stream->ResetWithUserCode(42);
+
+ // This read fails if the stream is closed in both directions, since that
+ // results in stream object being deleted.
+ std::string received_data = ReadDataFromWebTransportStreamUntilFin(stream);
+ EXPECT_LE(received_data.size(), 4u);
+
+ stream = session->OpenOutgoingBidirectionalStream();
+ QuicStreamId id2 = stream->GetStreamId();
+ ASSERT_TRUE(stream != nullptr);
+ EXPECT_TRUE(stream->Write("test"));
+ stream->SendStopSending(24);
+
+ std::array<std::string, 2> expected_log = {
+ absl::StrCat("Received reset for stream ", id1, " with error code 42"),
+ absl::StrCat("Received stop sending for stream ", id2,
+ " with error code 24"),
+ };
+ client_->WaitUntil(2000, [this, &expected_log]() {
+ return received_webtransport_unidirectional_streams_.size() >=
+ expected_log.size();
+ });
+ EXPECT_THAT(received_webtransport_unidirectional_streams_,
+ UnorderedElementsAreArray(expected_log));
+
+ // Since we closed the read side, cleanly closing the write side should result
+ // in the stream getting deleted.
+ ASSERT_TRUE(GetClientSession()->GetOrCreateSpdyDataStream(id2) != nullptr);
+ EXPECT_TRUE(stream->SendFin());
+ EXPECT_TRUE(client_->WaitUntil(2000, [this, id2]() {
+ return GetClientSession()->GetOrCreateSpdyDataStream(id2) == nullptr;
+ }));
+}
+
+TEST_P(EndToEndTest, WebTransportSession404) {
+ enable_web_transport_ = true;
+ ASSERT_TRUE(Initialize());
+
+ if (!version_.UsesHttp3()) {
+ return;
+ }
+
+ WebTransportHttp3* session = CreateWebTransportSession(
+ "/does-not-exist", /*wait_for_server_response=*/false);
+ ASSERT_TRUE(session != nullptr);
+ QuicSpdyStream* connect_stream = client_->latest_created_stream();
+ QuicStreamId connect_stream_id = connect_stream->id();
+
+ WebTransportStream* stream = session->OpenOutgoingBidirectionalStream();
+ ASSERT_TRUE(stream != nullptr);
+ EXPECT_TRUE(stream->Write("test"));
+ EXPECT_TRUE(stream->SendFin());
+
+ EXPECT_TRUE(client_->WaitUntil(-1, [this, connect_stream_id]() {
+ return GetClientSession()->GetOrCreateSpdyDataStream(connect_stream_id) ==
+ nullptr;
+ }));
+}
+
} // namespace
} // namespace test
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/http_constants.cc b/chromium/net/third_party/quiche/src/quic/core/http/http_constants.cc
index f3ed523647f..851fd9186a3 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/http_constants.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/http_constants.cc
@@ -17,7 +17,8 @@ std::string H3SettingsToString(Http3AndQpackSettingsIdentifiers identifier) {
RETURN_STRING_LITERAL(SETTINGS_QPACK_MAX_TABLE_CAPACITY);
RETURN_STRING_LITERAL(SETTINGS_MAX_FIELD_SECTION_SIZE);
RETURN_STRING_LITERAL(SETTINGS_QPACK_BLOCKED_STREAMS);
- RETURN_STRING_LITERAL(SETTINGS_H3_DATAGRAM);
+ RETURN_STRING_LITERAL(SETTINGS_H3_DATAGRAM_DRAFT00);
+ RETURN_STRING_LITERAL(SETTINGS_H3_DATAGRAM_DRAFT04);
RETURN_STRING_LITERAL(SETTINGS_WEBTRANS_DRAFT00);
}
return absl::StrCat("UNSUPPORTED_SETTINGS_TYPE(", identifier, ")");
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 c13a1a8c2b2..ce03a1eea78 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
@@ -38,8 +38,10 @@ enum Http3AndQpackSettingsIdentifiers : uint64_t {
// Same value as spdy::SETTINGS_MAX_HEADER_LIST_SIZE.
SETTINGS_MAX_FIELD_SECTION_SIZE = 0x06,
SETTINGS_QPACK_BLOCKED_STREAMS = 0x07,
- // draft-ietf-masque-h3-datagram.
- SETTINGS_H3_DATAGRAM = 0x276,
+ // draft-ietf-masque-h3-datagram-00.
+ SETTINGS_H3_DATAGRAM_DRAFT00 = 0x276,
+ // draft-ietf-masque-h3-datagram-04.
+ SETTINGS_H3_DATAGRAM_DRAFT04 = 0xffd277,
// draft-ietf-webtrans-http3-00
SETTINGS_WEBTRANS_DRAFT00 = 0x2b603742,
};
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 de86955739b..02aa123ed7a 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
@@ -5,7 +5,6 @@
#include "quic/core/http/http_decoder.h"
#include <cstdint>
-#include <limits>
#include "absl/base/attributes.h"
#include "absl/strings/string_view.h"
@@ -21,6 +20,17 @@
namespace quic {
+namespace {
+
+// Limit on the payload length for frames that are buffered by HttpDecoder.
+// If a frame header indicating a payload length exceeding this limit is
+// received, HttpDecoder closes the connection. Does not apply to frames that
+// are not buffered here but each payload fragment is immediately passed to
+// Visitor, like HEADERS, DATA, and unknown frames.
+constexpr QuicByteCount kPayloadLengthLimit = 1024 * 1024;
+
+} // anonymous namespace
+
HttpDecoder::HttpDecoder(Visitor* visitor) : HttpDecoder(visitor, Options()) {}
HttpDecoder::HttpDecoder(Visitor* visitor, Options options)
: visitor_(visitor),
@@ -90,8 +100,11 @@ QuicByteCount HttpDecoder::ProcessInput(const char* data, QuicByteCount len) {
QuicDataReader reader(data, len);
bool continue_processing = true;
- while (continue_processing &&
- (reader.BytesRemaining() != 0 || state_ == STATE_FINISH_PARSING)) {
+ // BufferOrParsePayload() and FinishParsing() may need to be called even if
+ // there is no more data so that they can finish processing the current frame.
+ while (continue_processing && (reader.BytesRemaining() != 0 ||
+ state_ == STATE_BUFFER_OR_PARSE_PAYLOAD ||
+ state_ == STATE_FINISH_PARSING)) {
// |continue_processing| must have been set to false upon error.
QUICHE_DCHECK_EQ(QUIC_NO_ERROR, error_);
QUICHE_DCHECK_NE(STATE_ERROR, state_);
@@ -103,11 +116,14 @@ QuicByteCount HttpDecoder::ProcessInput(const char* data, QuicByteCount len) {
case STATE_READING_FRAME_LENGTH:
continue_processing = ReadFrameLength(&reader);
break;
+ case STATE_BUFFER_OR_PARSE_PAYLOAD:
+ continue_processing = BufferOrParsePayload(&reader);
+ break;
case STATE_READING_FRAME_PAYLOAD:
continue_processing = ReadFramePayload(&reader);
break;
case STATE_FINISH_PARSING:
- continue_processing = FinishParsing(&reader);
+ continue_processing = FinishParsing();
break;
case STATE_PARSING_NO_LONGER_POSSIBLE:
continue_processing = false;
@@ -227,11 +243,8 @@ bool HttpDecoder::ReadFrameLength(QuicDataReader* reader) {
return false;
}
- if (current_frame_length_ > MaxFrameLength(current_frame_type_)) {
- // MaxFrameLength() returns numeric_limits::max()
- // if IsFrameBuffered() is false.
- QUICHE_DCHECK(IsFrameBuffered());
-
+ if (IsFrameBuffered() &&
+ current_frame_length_ > MaxFrameLength(current_frame_type_)) {
RaiseError(QUIC_HTTP_FRAME_TOO_LARGE, "Frame is too large.");
return false;
}
@@ -277,6 +290,12 @@ bool HttpDecoder::ReadFrameLength(QuicDataReader* reader) {
}
remaining_frame_length_ = current_frame_length_;
+
+ if (IsFrameBuffered()) {
+ state_ = STATE_BUFFER_OR_PARSE_PAYLOAD;
+ return continue_processing;
+ }
+
state_ = (remaining_frame_length_ == 0) ? STATE_FINISH_PARSING
: STATE_READING_FRAME_PAYLOAD;
return continue_processing;
@@ -301,6 +320,7 @@ bool HttpDecoder::IsFrameBuffered() {
}
bool HttpDecoder::ReadFramePayload(QuicDataReader* reader) {
+ QUICHE_DCHECK(!IsFrameBuffered());
QUICHE_DCHECK_NE(0u, reader->BytesRemaining());
QUICHE_DCHECK_NE(0u, remaining_frame_length_);
@@ -334,7 +354,7 @@ bool HttpDecoder::ReadFramePayload(QuicDataReader* reader) {
break;
}
case static_cast<uint64_t>(HttpFrameType::SETTINGS): {
- continue_processing = BufferOrParsePayload(reader);
+ QUICHE_NOTREACHED();
break;
}
case static_cast<uint64_t>(HttpFrameType::PUSH_PROMISE): {
@@ -342,19 +362,19 @@ bool HttpDecoder::ReadFramePayload(QuicDataReader* reader) {
break;
}
case static_cast<uint64_t>(HttpFrameType::GOAWAY): {
- continue_processing = BufferOrParsePayload(reader);
+ QUICHE_NOTREACHED();
break;
}
case static_cast<uint64_t>(HttpFrameType::MAX_PUSH_ID): {
- continue_processing = BufferOrParsePayload(reader);
+ QUICHE_NOTREACHED();
break;
}
case static_cast<uint64_t>(HttpFrameType::PRIORITY_UPDATE_REQUEST_STREAM): {
- continue_processing = BufferOrParsePayload(reader);
+ QUICHE_NOTREACHED();
break;
}
case static_cast<uint64_t>(HttpFrameType::ACCEPT_CH): {
- continue_processing = BufferOrParsePayload(reader);
+ QUICHE_NOTREACHED();
break;
}
default: {
@@ -363,26 +383,15 @@ bool HttpDecoder::ReadFramePayload(QuicDataReader* reader) {
}
}
- if (IsFrameBuffered()) {
- if (state_ != STATE_READING_FRAME_PAYLOAD) {
- // BufferOrParsePayload() has advanced |state_|.
- // TODO(bnc): Simplify state transitions.
- QUICHE_DCHECK_EQ(STATE_READING_FRAME_TYPE, state_);
- QUICHE_DCHECK_EQ(0u, remaining_frame_length_);
- }
- } else {
- QUICHE_DCHECK(state_ == STATE_READING_FRAME_PAYLOAD);
- }
-
- // BufferOrParsePayload() may have advanced |state_|.
- if (state_ == STATE_READING_FRAME_PAYLOAD && remaining_frame_length_ == 0) {
+ if (remaining_frame_length_ == 0) {
state_ = STATE_FINISH_PARSING;
}
return continue_processing;
}
-bool HttpDecoder::FinishParsing(QuicDataReader* reader) {
+bool HttpDecoder::FinishParsing() {
+ QUICHE_DCHECK(!IsFrameBuffered());
QUICHE_DCHECK_EQ(0u, remaining_frame_length_);
bool continue_processing = true;
@@ -401,9 +410,7 @@ bool HttpDecoder::FinishParsing(QuicDataReader* reader) {
break;
}
case static_cast<uint64_t>(HttpFrameType::SETTINGS): {
- // If frame payload is not empty, FinishParsing() is skipped.
- QUICHE_DCHECK_EQ(0u, current_frame_length_);
- continue_processing = BufferOrParsePayload(reader);
+ QUICHE_NOTREACHED();
break;
}
case static_cast<uint64_t>(HttpFrameType::PUSH_PROMISE): {
@@ -411,37 +418,33 @@ bool HttpDecoder::FinishParsing(QuicDataReader* reader) {
break;
}
case static_cast<uint64_t>(HttpFrameType::GOAWAY): {
- // If frame payload is not empty, FinishParsing() is skipped.
- QUICHE_DCHECK_EQ(0u, current_frame_length_);
- continue_processing = BufferOrParsePayload(reader);
+ QUICHE_NOTREACHED();
break;
}
case static_cast<uint64_t>(HttpFrameType::MAX_PUSH_ID): {
- // If frame payload is not empty, FinishParsing() is skipped.
- QUICHE_DCHECK_EQ(0u, current_frame_length_);
- continue_processing = BufferOrParsePayload(reader);
+ QUICHE_NOTREACHED();
break;
}
case static_cast<uint64_t>(HttpFrameType::PRIORITY_UPDATE_REQUEST_STREAM): {
- // If frame payload is not empty, FinishParsing() is skipped.
- QUICHE_DCHECK_EQ(0u, current_frame_length_);
- continue_processing = BufferOrParsePayload(reader);
+ QUICHE_NOTREACHED();
break;
}
case static_cast<uint64_t>(HttpFrameType::ACCEPT_CH): {
- // If frame payload is not empty, FinishParsing() is skipped.
- QUICHE_DCHECK_EQ(0u, current_frame_length_);
- continue_processing = BufferOrParsePayload(reader);
+ QUICHE_NOTREACHED();
break;
}
default:
continue_processing = visitor_->OnUnknownFrameEnd();
}
+ ResetForNextFrame();
+ return continue_processing;
+}
+
+void HttpDecoder::ResetForNextFrame() {
current_length_field_length_ = 0;
current_type_field_length_ = 0;
state_ = STATE_READING_FRAME_TYPE;
- return continue_processing;
}
bool HttpDecoder::HandleUnknownFramePayload(QuicDataReader* reader) {
@@ -460,44 +463,39 @@ bool HttpDecoder::BufferOrParsePayload(QuicDataReader* reader) {
QUICHE_DCHECK_EQ(current_frame_length_,
buffer_.size() + remaining_frame_length_);
- bool continue_processing = true;
-
if (buffer_.empty() && reader->BytesRemaining() >= current_frame_length_) {
// |*reader| contains entire payload, which might be empty.
remaining_frame_length_ = 0;
QuicDataReader current_payload_reader(reader->PeekRemainingPayload().data(),
current_frame_length_);
- continue_processing = ParseEntirePayload(&current_payload_reader);
- reader->Seek(current_frame_length_);
- } else {
- if (buffer_.empty()) {
- buffer_.reserve(current_frame_length_);
- }
+ bool continue_processing = ParseEntirePayload(&current_payload_reader);
- // Buffer as much of the payload as |*reader| contains.
- QuicByteCount bytes_to_read = std::min<QuicByteCount>(
- remaining_frame_length_, reader->BytesRemaining());
- absl::StrAppend(&buffer_, reader->PeekRemainingPayload().substr(
- /* pos = */ 0, bytes_to_read));
- reader->Seek(bytes_to_read);
- remaining_frame_length_ -= bytes_to_read;
+ reader->Seek(current_frame_length_);
+ ResetForNextFrame();
+ return continue_processing;
+ }
- QUICHE_DCHECK_EQ(current_frame_length_,
- buffer_.size() + remaining_frame_length_);
+ // Buffer as much of the payload as |*reader| contains.
+ QuicByteCount bytes_to_read = std::min<QuicByteCount>(
+ remaining_frame_length_, reader->BytesRemaining());
+ absl::StrAppend(&buffer_, reader->PeekRemainingPayload().substr(
+ /* pos = */ 0, bytes_to_read));
+ reader->Seek(bytes_to_read);
+ remaining_frame_length_ -= bytes_to_read;
- if (remaining_frame_length_ > 0) {
- QUICHE_DCHECK(reader->IsDoneReading());
- return true;
- }
+ QUICHE_DCHECK_EQ(current_frame_length_,
+ buffer_.size() + remaining_frame_length_);
- QuicDataReader buffer_reader(buffer_);
- continue_processing = ParseEntirePayload(&buffer_reader);
- buffer_.clear();
+ if (remaining_frame_length_ > 0) {
+ QUICHE_DCHECK(reader->IsDoneReading());
+ return false;
}
- current_length_field_length_ = 0;
- current_type_field_length_ = 0;
- state_ = STATE_READING_FRAME_TYPE;
+ QuicDataReader buffer_reader(buffer_);
+ bool continue_processing = ParseEntirePayload(&buffer_reader);
+ buffer_.clear();
+
+ ResetForNextFrame();
return continue_processing;
}
@@ -654,23 +652,22 @@ bool HttpDecoder::ParseAcceptChFrame(QuicDataReader* reader,
}
QuicByteCount HttpDecoder::MaxFrameLength(uint64_t frame_type) {
+ QUICHE_DCHECK(IsFrameBuffered());
+
switch (frame_type) {
case static_cast<uint64_t>(HttpFrameType::SETTINGS):
- // This limit is arbitrary.
- return 1024 * 1024;
+ return kPayloadLengthLimit;
case static_cast<uint64_t>(HttpFrameType::GOAWAY):
return VARIABLE_LENGTH_INTEGER_LENGTH_8;
case static_cast<uint64_t>(HttpFrameType::MAX_PUSH_ID):
return VARIABLE_LENGTH_INTEGER_LENGTH_8;
case static_cast<uint64_t>(HttpFrameType::PRIORITY_UPDATE_REQUEST_STREAM):
- // This limit is arbitrary.
- return 1024 * 1024;
+ return kPayloadLengthLimit;
case static_cast<uint64_t>(HttpFrameType::ACCEPT_CH):
- // This limit is arbitrary.
- return 1024 * 1024;
+ return kPayloadLengthLimit;
default:
- // Other frames require no data buffering, so it's safe to have no limit.
- return std::numeric_limits<QuicByteCount>::max();
+ QUICHE_NOTREACHED();
+ return 0;
}
}
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 002ff68f008..118fbcf59f5 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
@@ -155,8 +155,14 @@ class QUIC_EXPORT_PRIVATE HttpDecoder {
enum HttpDecoderState {
STATE_READING_FRAME_LENGTH,
STATE_READING_FRAME_TYPE,
+
+ // States used for buffered frame types
+ STATE_BUFFER_OR_PARSE_PAYLOAD,
+
+ // States used for non-buffered frame types
STATE_READING_FRAME_PAYLOAD,
STATE_FINISH_PARSING,
+
STATE_PARSING_NO_LONGER_POSSIBLE,
STATE_ERROR
};
@@ -188,7 +194,10 @@ class QUIC_EXPORT_PRIVATE HttpDecoder {
// empty, and it calls BufferOrParsePayload(). For other frame types, this
// method directly calls visitor methods to signal that frame had been
// received completely. Returns whether processing should continue.
- bool FinishParsing(QuicDataReader* reader);
+ bool FinishParsing();
+
+ // Reset internal fields to prepare for reading next frame.
+ void ResetForNextFrame();
// Read payload of unknown frame from |reader| and call
// Visitor::OnUnknownFramePayload(). Returns true decoding should continue,
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 0266632aae7..95d5913896b 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
@@ -27,7 +27,6 @@ using ::testing::InSequence;
using ::testing::Return;
namespace quic {
-
namespace test {
class HttpDecoderPeer {
@@ -37,9 +36,11 @@ class HttpDecoderPeer {
}
};
-class MockVisitor : public HttpDecoder::Visitor {
+namespace {
+
+class MockHttpDecoderVisitor : public HttpDecoder::Visitor {
public:
- ~MockVisitor() override = default;
+ ~MockHttpDecoderVisitor() override = default;
// Called if an error is detected.
MOCK_METHOD(void, OnError, (HttpDecoder*), (override));
@@ -164,7 +165,7 @@ class HttpDecoderTest : public QuicTest {
return processed_bytes;
}
- testing::StrictMock<MockVisitor> visitor_;
+ testing::StrictMock<MockHttpDecoderVisitor> visitor_;
HttpDecoder decoder_;
};
@@ -626,6 +627,25 @@ TEST_F(HttpDecoderTest, MaxPushIdWithOverlyLargePayload) {
EXPECT_EQ("Frame is too large.", decoder_.error_detail());
}
+TEST_F(HttpDecoderTest, FrameWithOverlyLargePayload) {
+ // Regression test for b/193919867: Ensure that reading frames with incredibly
+ // large payload lengths does not lead to allocating unbounded memory.
+ constexpr size_t max_input_length =
+ /*max frame type varint length*/ sizeof(uint64_t) +
+ /*max frame length varint length*/ sizeof(uint64_t) +
+ /*one byte of payload*/ sizeof(uint8_t);
+ char input[max_input_length];
+ for (uint64_t frame_type = 0; frame_type < 1025; frame_type++) {
+ ::testing::NiceMock<MockHttpDecoderVisitor> visitor;
+ HttpDecoder decoder(&visitor);
+ QuicDataWriter writer(max_input_length, input);
+ ASSERT_TRUE(writer.WriteVarInt62(frame_type)); // frame type.
+ ASSERT_TRUE(writer.WriteVarInt62(kVarInt62MaxValue)); // frame length.
+ ASSERT_TRUE(writer.WriteUInt8(0x00)); // one byte of payload.
+ EXPECT_NE(decoder.ProcessInput(input, writer.length()), 0u) << frame_type;
+ }
+}
+
TEST_F(HttpDecoderTest, MalformedSettingsFrame) {
char input[30];
QuicDataWriter writer(30, input);
@@ -1049,7 +1069,7 @@ TEST_F(HttpDecoderTest, WebTransportStreamDisabled) {
TEST(HttpDecoderTestNoFixture, WebTransportStream) {
HttpDecoder::Options options;
options.allow_web_transport_stream = true;
- testing::StrictMock<MockVisitor> visitor;
+ testing::StrictMock<MockHttpDecoderVisitor> visitor;
HttpDecoder decoder(&visitor, options);
// WebTransport stream for session ID 0x104, with four bytes of extra data.
@@ -1062,7 +1082,7 @@ TEST(HttpDecoderTestNoFixture, WebTransportStream) {
TEST(HttpDecoderTestNoFixture, WebTransportStreamError) {
HttpDecoder::Options options;
options.allow_web_transport_stream = true;
- testing::StrictMock<MockVisitor> visitor;
+ testing::StrictMock<MockHttpDecoderVisitor> visitor;
HttpDecoder decoder(&visitor, options);
std::string input = absl::HexStringToBytes("404100");
@@ -1111,6 +1131,6 @@ TEST_F(HttpDecoderTest, DecodeSettings) {
EXPECT_FALSE(HttpDecoder::DecodeSettings(input.data(), input.size(), &out));
}
+} // namespace
} // namespace test
-
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_client_promised_info.h b/chromium/net/third_party/quiche/src/quic/core/http/quic_client_promised_info.h
index 0666c3ac02e..ec071f09c3f 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_client_promised_info.h
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_client_promised_info.h
@@ -84,7 +84,8 @@ class QUIC_EXPORT_PRIVATE QuicClientPromisedInfo
private:
friend class test::QuicClientPromisedInfoPeer;
- class QUIC_EXPORT_PRIVATE CleanupAlarm : public QuicAlarm::Delegate {
+ class QUIC_EXPORT_PRIVATE CleanupAlarm
+ : public QuicAlarm::DelegateWithoutContext {
public:
explicit CleanupAlarm(QuicClientPromisedInfo* promised)
: promised_(promised) {}
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 9c164d0e448..3c6546fb8f3 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
@@ -24,7 +24,6 @@ QuicReceiveControlStream::QuicReceiveControlStream(
QuicSpdySession* spdy_session)
: QuicStream(pending,
spdy_session,
- READ_UNIDIRECTIONAL,
/*is_static=*/true),
settings_frame_received_(false),
decoder_(this),
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.cc
index 79555e05967..92831f2d14d 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.cc
@@ -31,7 +31,7 @@ void QuicSendControlStream::OnStreamReset(const QuicRstStreamFrame& /*frame*/) {
<< "OnStreamReset() called for write unidirectional stream.";
}
-bool QuicSendControlStream::OnStopSending(QuicRstStreamErrorCode /* code */) {
+bool QuicSendControlStream::OnStopSending(QuicResetStreamError /* code */) {
stream_delegate()->OnStreamError(
QUIC_HTTP_CLOSED_CRITICAL_STREAM,
"STOP_SENDING received for send control stream");
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.h b/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.h
index face80632af..d376a63c48b 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.h
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.h
@@ -31,7 +31,7 @@ class QUIC_EXPORT_PRIVATE QuicSendControlStream : public QuicStream {
// Overriding QuicStream::OnStopSending() to make sure control stream is never
// closed before connection.
void OnStreamReset(const QuicRstStreamFrame& frame) override;
- bool OnStopSending(QuicRstStreamErrorCode code) override;
+ bool OnStopSending(QuicResetStreamError code) override;
// Send SETTINGS frame if it hasn't been sent yet. Settings frame must be the
// first frame sent on this stream.
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream_test.cc
index 3066cb38871..59435852623 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream_test.cc
@@ -71,9 +71,7 @@ class QuicSendControlStreamTest : public QuicTestWithParam<TestParams> {
public:
QuicSendControlStreamTest()
: connection_(new StrictMock<MockQuicConnection>(
- &helper_,
- &alarm_factory_,
- perspective(),
+ &helper_, &alarm_factory_, perspective(),
SupportedVersions(GetParam().version))),
session_(connection_) {
ON_CALL(session_, WritevData(_, _, _, _, _, _))
@@ -104,8 +102,7 @@ class QuicSendControlStreamTest : public QuicTestWithParam<TestParams> {
QuicSendControlStream* send_control_stream_;
};
-INSTANTIATE_TEST_SUITE_P(Tests,
- QuicSendControlStreamTest,
+INSTANTIATE_TEST_SUITE_P(Tests, QuicSendControlStreamTest,
::testing::ValuesIn(GetTestParams()),
::testing::PrintToStringParamName());
@@ -133,24 +130,27 @@ TEST_P(QuicSendControlStreamTest, WriteSettings) {
"4040" // 0x40 as the reserved frame type
"01" // 1 byte frame length
"61"); // payload "a"
- if (QuicSpdySessionPeer::ShouldNegotiateHttp3Datagram(&session_)) {
+ if (QuicSpdySessionPeer::LocalHttpDatagramSupport(&session_) ==
+ HttpDatagramSupport::kDraft00And04) {
expected_write_data = absl::HexStringToBytes(
- "00" // stream type: control stream
- "04" // frame type: SETTINGS frame
- "0e" // frame length
- "01" // SETTINGS_QPACK_MAX_TABLE_CAPACITY
- "40ff" // 255
- "06" // SETTINGS_MAX_HEADER_LIST_SIZE
- "4400" // 1024
- "07" // SETTINGS_QPACK_BLOCKED_STREAMS
- "10" // 16
- "4040" // 0x40 as the reserved settings id
- "14" // 20
- "4276" // SETTINGS_H3_DATAGRAM
- "01" // 1
- "4040" // 0x40 as the reserved frame type
- "01" // 1 byte frame length
- "61"); // payload "a"
+ "00" // stream type: control stream
+ "04" // frame type: SETTINGS frame
+ "0e" // frame length
+ "01" // SETTINGS_QPACK_MAX_TABLE_CAPACITY
+ "40ff" // 255
+ "06" // SETTINGS_MAX_HEADER_LIST_SIZE
+ "4400" // 1024
+ "07" // SETTINGS_QPACK_BLOCKED_STREAMS
+ "10" // 16
+ "4040" // 0x40 as the reserved settings id
+ "14" // 20
+ "4276" // SETTINGS_H3_DATAGRAM_DRAFT00
+ "01" // 1
+ "800ffd277" // SETTINGS_H3_DATAGRAM_DRAFT04
+ "01" // 1
+ "4040" // 0x40 as the reserved frame type
+ "01" // 1 byte frame length
+ "61"); // payload "a"
}
auto buffer = std::make_unique<char[]>(expected_write_data.size());
@@ -216,7 +216,8 @@ TEST_P(QuicSendControlStreamTest, CloseControlStream) {
Initialize();
EXPECT_CALL(*connection_,
CloseConnection(QUIC_HTTP_CLOSED_CRITICAL_STREAM, _, _));
- send_control_stream_->OnStopSending(QUIC_STREAM_CANCELLED);
+ send_control_stream_->OnStopSending(
+ QuicResetStreamError::FromInternal(QUIC_STREAM_CANCELLED));
}
TEST_P(QuicSendControlStreamTest, ReceiveDataOnSendControlStream) {
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 69d6cb47a9d..1f6ec744f53 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
@@ -286,15 +286,19 @@ QuicSSLConfig QuicServerSessionBase::GetSSLConfig() const {
QUICHE_DCHECK(crypto_config_ && crypto_config_->proof_source());
QuicSSLConfig ssl_config = QuicSpdySession::GetSSLConfig();
- if (!GetQuicReloadableFlag(quic_tls_set_signature_algorithm_prefs) ||
- !crypto_config_ || !crypto_config_->proof_source()) {
+
+ if (quic_tls_disable_resumption_refactor()) {
+ ssl_config.disable_ticket_support =
+ GetQuicFlag(FLAGS_quic_disable_server_tls_resumption);
+ }
+
+ if (!crypto_config_ || !crypto_config_->proof_source()) {
return ssl_config;
}
absl::InlinedVector<uint16_t, 8> signature_algorithms =
crypto_config_->proof_source()->SupportedTlsSignatureAlgorithms();
if (!signature_algorithms.empty()) {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_tls_set_signature_algorithm_prefs, 1, 2);
ssl_config.signing_algorithm_prefs = std::move(signature_algorithms);
}
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 ac7fc1e59c8..279ff60798b 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
@@ -17,6 +17,7 @@
#include "quic/core/quic_connection.h"
#include "quic/core/quic_crypto_server_stream.h"
#include "quic/core/quic_crypto_server_stream_base.h"
+#include "quic/core/quic_types.h"
#include "quic/core/quic_utils.h"
#include "quic/core/tls_server_handshaker.h"
#include "quic/platform/api/quic_expect_bug.h"
@@ -93,8 +94,8 @@ class TestServerSession : public QuicServerSessionBase {
}
QuicSpdyStream* CreateIncomingStream(PendingStream* pending) override {
- QuicSpdyStream* stream = new QuicSimpleServerStream(
- pending, this, BIDIRECTIONAL, quic_simple_server_backend_);
+ QuicSpdyStream* stream =
+ new QuicSimpleServerStream(pending, this, quic_simple_server_backend_);
ActivateStream(absl::WrapUnique(stream));
return 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 45bdd1d31b1..898398f59e3 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
@@ -185,8 +185,7 @@ bool QuicSpdyClientSession::ShouldCreateIncomingStream(QuicStreamId id) {
QuicSpdyStream* QuicSpdyClientSession::CreateIncomingStream(
PendingStream* pending) {
- QuicSpdyStream* stream =
- new QuicSpdyClientStream(pending, this, READ_UNIDIRECTIONAL);
+ QuicSpdyStream* stream = new QuicSpdyClientStream(pending, this);
ActivateStream(absl::WrapUnique(stream));
return stream;
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream.cc
index d264ba64879..7391fdc79ae 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream.cc
@@ -31,9 +31,8 @@ QuicSpdyClientStream::QuicSpdyClientStream(QuicStreamId id,
has_preliminary_headers_(false) {}
QuicSpdyClientStream::QuicSpdyClientStream(PendingStream* pending,
- QuicSpdyClientSession* session,
- StreamType type)
- : QuicSpdyStream(pending, session, type),
+ QuicSpdyClientSession* session)
+ : QuicSpdyStream(pending, session),
content_length_(-1),
response_code_(0),
header_bytes_read_(0),
@@ -62,8 +61,13 @@ void QuicSpdyClientStream::OnInitialHeadersComplete(
if (web_transport() != nullptr) {
web_transport()->HeadersReceived(response_headers_);
if (!web_transport()->ready()) {
- // Rejected due to status not being 200, or other reason.
- WriteOrBufferData("", /*fin=*/true, nullptr);
+ // The request was rejected by WebTransport, typically due to not having a
+ // 2xx status. The reason we're using Reset() here rather than closing
+ // cleanly is that even if the server attempts to send us any form of body
+ // with a 4xx request, we've already set up the capsule parser, and we
+ // don't have any way to process anything from the response body in
+ // question.
+ Reset(QUIC_STREAM_CANCELLED);
return;
}
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream.h b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream.h
index 231846508e4..8637d11bb43 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream.h
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream.h
@@ -25,8 +25,7 @@ class QUIC_EXPORT_PRIVATE QuicSpdyClientStream : public QuicSpdyStream {
QuicSpdyClientSession* session,
StreamType type);
QuicSpdyClientStream(PendingStream* pending,
- QuicSpdyClientSession* spdy_session,
- StreamType type);
+ QuicSpdyClientSession* spdy_session);
QuicSpdyClientStream(const QuicSpdyClientStream&) = delete;
QuicSpdyClientStream& operator=(const QuicSpdyClientStream&) = delete;
~QuicSpdyClientStream() override;
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_server_stream_base.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_server_stream_base.cc
index c2e7845edb7..93f1c2bfe7b 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_server_stream_base.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_server_stream_base.cc
@@ -16,9 +16,8 @@ QuicSpdyServerStreamBase::QuicSpdyServerStreamBase(QuicStreamId id,
: QuicSpdyStream(id, session, type) {}
QuicSpdyServerStreamBase::QuicSpdyServerStreamBase(PendingStream* pending,
- QuicSpdySession* session,
- StreamType type)
- : QuicSpdyStream(pending, session, type) {}
+ QuicSpdySession* session)
+ : QuicSpdyStream(pending, session) {}
void QuicSpdyServerStreamBase::CloseWriteSide() {
if (!fin_received() && !rst_received() && sequencer()->ignore_read_data() &&
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_server_stream_base.h b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_server_stream_base.h
index 252addfaab6..21ecc0baa65 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_server_stream_base.h
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_server_stream_base.h
@@ -14,9 +14,7 @@ class QUIC_NO_EXPORT QuicSpdyServerStreamBase : public QuicSpdyStream {
QuicSpdyServerStreamBase(QuicStreamId id,
QuicSpdySession* session,
StreamType type);
- QuicSpdyServerStreamBase(PendingStream* pending,
- QuicSpdySession* session,
- StreamType type);
+ QuicSpdyServerStreamBase(PendingStream* pending, QuicSpdySession* session);
QuicSpdyServerStreamBase(const QuicSpdyServerStreamBase&) = delete;
QuicSpdyServerStreamBase& operator=(const QuicSpdyServerStreamBase&) = delete;
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 fe630de5108..aa41b3c37cd 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
@@ -19,8 +19,7 @@ namespace {
class TestQuicSpdyServerStream : public QuicSpdyServerStreamBase {
public:
- TestQuicSpdyServerStream(QuicStreamId id,
- QuicSpdySession* session,
+ TestQuicSpdyServerStream(QuicStreamId id, QuicSpdySession* session,
StreamType type)
: QuicSpdyServerStreamBase(id, session, type) {}
@@ -30,8 +29,7 @@ class TestQuicSpdyServerStream : public QuicSpdyServerStreamBase {
class QuicSpdyServerStreamBaseTest : public QuicTest {
protected:
QuicSpdyServerStreamBaseTest()
- : session_(new MockQuicConnection(&helper_,
- &alarm_factory_,
+ : session_(new MockQuicConnection(&helper_, &alarm_factory_,
Perspective::IS_SERVER)) {
session_.Initialize();
session_.connection()->SetEncrypter(
@@ -56,10 +54,15 @@ TEST_F(QuicSpdyServerStreamBaseTest,
stream_->StopReading();
if (session_.version().UsesHttp3()) {
- EXPECT_CALL(session_, MaybeSendStopSendingFrame(_, QUIC_STREAM_NO_ERROR))
+ EXPECT_CALL(session_,
+ MaybeSendStopSendingFrame(_, QuicResetStreamError::FromInternal(
+ QUIC_STREAM_NO_ERROR)))
.Times(1);
} else {
- EXPECT_CALL(session_, MaybeSendRstStreamFrame(_, QUIC_STREAM_NO_ERROR, _))
+ EXPECT_CALL(
+ session_,
+ MaybeSendRstStreamFrame(
+ _, QuicResetStreamError::FromInternal(QUIC_STREAM_NO_ERROR), _))
.Times(1);
}
QuicStreamPeer::SetFinSent(stream_);
@@ -73,9 +76,10 @@ TEST_F(QuicSpdyServerStreamBaseTest,
EXPECT_CALL(session_,
MaybeSendRstStreamFrame(
_,
- VersionHasIetfQuicFrames(session_.transport_version())
- ? QUIC_STREAM_CANCELLED
- : QUIC_RST_ACKNOWLEDGEMENT,
+ QuicResetStreamError::FromInternal(
+ VersionHasIetfQuicFrames(session_.transport_version())
+ ? QUIC_STREAM_CANCELLED
+ : QUIC_RST_ACKNOWLEDGEMENT),
_))
.Times(1);
QuicRstStreamFrame rst_frame(kInvalidControlFrameId, stream_->id(),
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 56b0db3ff48..0cd2644abcb 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
@@ -33,8 +33,6 @@
#include "spdy/core/http2_frame_decoder_adapter.h"
using http2::Http2DecoderAdapter;
-using spdy::HpackEntry;
-using spdy::HpackHeaderTable;
using spdy::Http2WeightToSpdy3Priority;
using spdy::Spdy3PriorityToHttp2Weight;
using spdy::SpdyErrorCode;
@@ -195,8 +193,7 @@ class QuicSpdySession::SpdyFramerVisitor
header_list_.Clear();
}
- void OnStreamFrameData(SpdyStreamId /*stream_id*/,
- const char* /*data*/,
+ void OnStreamFrameData(SpdyStreamId /*stream_id*/, const char* /*data*/,
size_t /*len*/) override {
QUICHE_DCHECK(!VersionUsesHttp3(session_->transport_version()));
CloseConnection("SPDY DATA frame received.",
@@ -284,8 +281,7 @@ class QuicSpdySession::SpdyFramerVisitor
code);
}
- void OnDataFrameHeader(SpdyStreamId /*stream_id*/,
- size_t /*length*/,
+ void OnDataFrameHeader(SpdyStreamId /*stream_id*/, size_t /*length*/,
bool /*fin*/) override {
QUICHE_DCHECK(!VersionUsesHttp3(session_->transport_version()));
CloseConnection("SPDY DATA frame received.",
@@ -318,13 +314,9 @@ class QuicSpdySession::SpdyFramerVisitor
QUIC_INVALID_HEADERS_STREAM_DATA);
}
- void OnHeaders(SpdyStreamId stream_id,
- bool has_priority,
- int weight,
- SpdyStreamId /* parent_stream_id */,
- bool /* exclusive */,
- bool fin,
- bool /*end*/) override {
+ void OnHeaders(SpdyStreamId stream_id, bool has_priority, int weight,
+ SpdyStreamId /* parent_stream_id */, bool /* exclusive */,
+ bool fin, bool /*end*/) override {
if (!session_->IsConnected()) {
return;
}
@@ -352,8 +344,7 @@ class QuicSpdySession::SpdyFramerVisitor
QUIC_INVALID_HEADERS_STREAM_DATA);
}
- void OnPushPromise(SpdyStreamId stream_id,
- SpdyStreamId promised_stream_id,
+ void OnPushPromise(SpdyStreamId stream_id, SpdyStreamId promised_stream_id,
bool /*end*/) override {
QUICHE_DCHECK(!VersionUsesHttp3(session_->transport_version()));
if (session_->perspective() != Perspective::IS_CLIENT) {
@@ -369,10 +360,8 @@ class QuicSpdySession::SpdyFramerVisitor
void OnContinuation(SpdyStreamId /*stream_id*/, bool /*end*/) override {}
- void OnPriority(SpdyStreamId stream_id,
- SpdyStreamId /* parent_id */,
- int weight,
- bool /* exclusive */) override {
+ void OnPriority(SpdyStreamId stream_id, SpdyStreamId /* parent_id */,
+ int weight, bool /* exclusive */) override {
QUICHE_DCHECK(!VersionUsesHttp3(session_->transport_version()));
if (!session_->IsConnected()) {
return;
@@ -395,10 +384,8 @@ class QuicSpdySession::SpdyFramerVisitor
}
// SpdyFramerDebugVisitorInterface implementation
- void OnSendCompressedFrame(SpdyStreamId /*stream_id*/,
- SpdyFrameType /*type*/,
- size_t payload_len,
- size_t frame_len) override {
+ void OnSendCompressedFrame(SpdyStreamId /*stream_id*/, SpdyFrameType /*type*/,
+ size_t payload_len, size_t frame_len) override {
if (payload_len == 0) {
QUIC_BUG(quic_bug_10360_1) << "Zero payload length.";
return;
@@ -470,9 +457,6 @@ QuicSpdySession::QuicSpdySession(
h2_deframer_.set_visitor(spdy_framer_visitor_.get());
h2_deframer_.set_debug_visitor(spdy_framer_visitor_.get());
spdy_framer_.set_debug_visitor(spdy_framer_visitor_.get());
- if (decline_server_push_stream_) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_decline_server_push_stream);
- }
}
QuicSpdySession::~QuicSpdySession() {
@@ -523,8 +507,17 @@ void QuicSpdySession::FillSettingsFrame() {
qpack_maximum_blocked_streams_;
settings_.values[SETTINGS_MAX_FIELD_SECTION_SIZE] =
max_inbound_header_list_size_;
- if (ShouldNegotiateHttp3Datagram() && version().UsesHttp3()) {
- settings_.values[SETTINGS_H3_DATAGRAM] = 1;
+ if (version().UsesHttp3()) {
+ HttpDatagramSupport local_http_datagram_support =
+ LocalHttpDatagramSupport();
+ if (local_http_datagram_support == HttpDatagramSupport::kDraft00 ||
+ local_http_datagram_support == HttpDatagramSupport::kDraft00And04) {
+ settings_.values[SETTINGS_H3_DATAGRAM_DRAFT00] = 1;
+ }
+ if (local_http_datagram_support == HttpDatagramSupport::kDraft04 ||
+ local_http_datagram_support == HttpDatagramSupport::kDraft00And04) {
+ settings_.values[SETTINGS_H3_DATAGRAM_DRAFT04] = 1;
+ }
}
if (WillNegotiateWebTransport()) {
settings_.values[SETTINGS_WEBTRANS_DRAFT00] = 1;
@@ -548,8 +541,7 @@ void QuicSpdySession::OnEncoderStreamError(QuicErrorCode error_code,
}
void QuicSpdySession::OnStreamHeadersPriority(
- QuicStreamId stream_id,
- const spdy::SpdyStreamPrecedence& precedence) {
+ QuicStreamId stream_id, const spdy::SpdyStreamPrecedence& precedence) {
QuicSpdyStream* stream = GetOrCreateSpdyDataStream(stream_id);
if (!stream) {
// It's quite possible to receive headers after a stream has been reset.
@@ -558,8 +550,7 @@ void QuicSpdySession::OnStreamHeadersPriority(
stream->OnStreamHeadersPriority(precedence);
}
-void QuicSpdySession::OnStreamHeaderList(QuicStreamId stream_id,
- bool fin,
+void QuicSpdySession::OnStreamHeaderList(QuicStreamId stream_id, bool fin,
size_t frame_len,
const QuicHeaderList& header_list) {
if (IsStaticStream(stream_id)) {
@@ -598,8 +589,7 @@ void QuicSpdySession::OnStreamHeaderList(QuicStreamId stream_id,
}
void QuicSpdySession::OnPriorityFrame(
- QuicStreamId stream_id,
- const spdy::SpdyStreamPrecedence& precedence) {
+ QuicStreamId stream_id, const spdy::SpdyStreamPrecedence& precedence) {
QuicSpdyStream* stream = GetOrCreateSpdyDataStream(stream_id);
if (!stream) {
// It's quite possible to receive a PRIORITY frame after a stream has been
@@ -676,9 +666,7 @@ size_t QuicSpdySession::ProcessHeaderData(const struct iovec& iov) {
}
size_t QuicSpdySession::WriteHeadersOnHeadersStream(
- QuicStreamId id,
- SpdyHeaderBlock headers,
- bool fin,
+ QuicStreamId id, SpdyHeaderBlock headers, bool fin,
const spdy::SpdyStreamPrecedence& precedence,
QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) {
QUICHE_DCHECK(!VersionUsesHttp3(transport_version()));
@@ -691,8 +679,7 @@ size_t QuicSpdySession::WriteHeadersOnHeadersStream(
}
size_t QuicSpdySession::WritePriority(QuicStreamId id,
- QuicStreamId parent_stream_id,
- int weight,
+ QuicStreamId parent_stream_id, int weight,
bool exclusive) {
QUICHE_DCHECK(!VersionUsesHttp3(transport_version()));
SpdyPriorityIR priority_frame(id, parent_stream_id, weight, exclusive);
@@ -764,7 +751,6 @@ bool QuicSpdySession::OnStreamsBlockedFrame(
void QuicSpdySession::SendHttp3GoAway(QuicErrorCode error_code,
const std::string& reason) {
- QUICHE_DCHECK_EQ(perspective(), Perspective::IS_SERVER);
QUICHE_DCHECK(VersionUsesHttp3(transport_version()));
if (!IsEncryptionEstablished()) {
QUIC_CODE_COUNT(quic_h3_goaway_before_encryption_established);
@@ -871,8 +857,7 @@ QuicSpdyStream* QuicSpdySession::GetOrCreateSpdyDataStream(
}
void QuicSpdySession::OnNewEncryptionKeyAvailable(
- EncryptionLevel level,
- std::unique_ptr<QuicEncrypter> encrypter) {
+ EncryptionLevel level, std::unique_ptr<QuicEncrypter> encrypter) {
QuicSession::OnNewEncryptionKeyAvailable(level, std::move(encrypter));
if (IsEncryptionEstablished()) {
// Send H3 SETTINGs once encryption is established.
@@ -880,13 +865,11 @@ void QuicSpdySession::OnNewEncryptionKeyAvailable(
}
}
-bool QuicSpdySession::ShouldNegotiateWebTransport() {
- return false;
-}
+bool QuicSpdySession::ShouldNegotiateWebTransport() { return false; }
bool QuicSpdySession::WillNegotiateWebTransport() {
- return ShouldNegotiateHttp3Datagram() && version().UsesHttp3() &&
- ShouldNegotiateWebTransport();
+ return LocalHttpDatagramSupport() != HttpDatagramSupport::kNone &&
+ version().UsesHttp3() && ShouldNegotiateWebTransport();
}
// True if there are open HTTP requests.
@@ -896,20 +879,20 @@ bool QuicSpdySession::ShouldKeepConnectionAlive() const {
return GetNumActiveStreams() + pending_streams_size() > 0;
}
-bool QuicSpdySession::UsesPendingStreams() const {
- // QuicSpdySession supports PendingStreams, therefore this method should
- // eventually just return true. However, pending streams can only be used if
- // unidirectional stream type is supported.
- return VersionUsesHttp3(transport_version());
+bool QuicSpdySession::UsesPendingStreamForFrame(QuicFrameType type,
+ QuicStreamId stream_id) const {
+ // Pending streams can only be used to handle unidirectional stream with
+ // STREAM & RESET_STREAM frames in IETF QUIC.
+ return VersionUsesHttp3(transport_version()) &&
+ (type == STREAM_FRAME || type == RST_STREAM_FRAME) &&
+ QuicUtils::GetStreamType(stream_id, perspective(),
+ IsIncomingStream(stream_id),
+ version()) == READ_UNIDIRECTIONAL;
}
size_t QuicSpdySession::WriteHeadersOnHeadersStreamImpl(
- QuicStreamId id,
- spdy::SpdyHeaderBlock headers,
- bool fin,
- QuicStreamId parent_stream_id,
- int weight,
- bool exclusive,
+ QuicStreamId id, spdy::SpdyHeaderBlock headers, bool fin,
+ QuicStreamId parent_stream_id, int weight, bool exclusive,
QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) {
QUICHE_DCHECK(!VersionUsesHttp3(transport_version()));
@@ -943,10 +926,8 @@ size_t QuicSpdySession::WriteHeadersOnHeadersStreamImpl(
}
void QuicSpdySession::OnPromiseHeaderList(
- QuicStreamId /*stream_id*/,
- QuicStreamId /*promised_stream_id*/,
- size_t /*frame_len*/,
- const QuicHeaderList& /*header_list*/) {
+ QuicStreamId /*stream_id*/, QuicStreamId /*promised_stream_id*/,
+ size_t /*frame_len*/, const QuicHeaderList& /*header_list*/) {
std::string error =
"OnPromiseHeaderList should be overridden in client code.";
QUIC_BUG(quic_bug_10360_6) << error;
@@ -976,8 +957,7 @@ bool QuicSpdySession::ResumeApplicationState(ApplicationState* cached_state) {
}
absl::optional<std::string> QuicSpdySession::OnAlpsData(
- const uint8_t* alps_data,
- size_t alps_length) {
+ const uint8_t* alps_data, size_t alps_length) {
AlpsFrameDecoder alps_frame_decoder(this);
HttpDecoder decoder(&alps_frame_decoder);
decoder.ProcessInput(reinterpret_cast<const char*>(alps_data), alps_length);
@@ -1045,6 +1025,21 @@ absl::optional<std::string> QuicSpdySession::OnSettingsFrameViaAlps(
return absl::nullopt;
}
+bool QuicSpdySession::VerifySettingIsZeroOrOne(uint64_t id, uint64_t value) {
+ if (value == 0 || value == 1) {
+ return true;
+ }
+ std::string error_details = absl::StrCat(
+ "Received ",
+ H3SettingsToString(static_cast<Http3AndQpackSettingsIdentifiers>(id)),
+ " with invalid value ", value);
+ QUIC_PEER_BUG(bad received setting) << ENDPOINT << error_details;
+ // TODO(dschinazi) use QUIC_HTTP_INVALID_SETTING_VALUE instead of
+ // QUIC_HTTP_RECEIVE_SPDY_SETTING once cl/396439351 lands.
+ CloseConnectionWithDetails(QUIC_HTTP_RECEIVE_SPDY_SETTING, error_details);
+ return false;
+}
+
bool QuicSpdySession::OnSetting(uint64_t id, uint64_t value) {
any_settings_received_ = true;
@@ -1129,24 +1124,47 @@ bool QuicSpdySession::OnSetting(uint64_t id, uint64_t value) {
absl::StrCat("received HTTP/2 specific setting in HTTP/3 session: ",
id));
return false;
- case SETTINGS_H3_DATAGRAM: {
- if (!ShouldNegotiateHttp3Datagram()) {
+ case SETTINGS_H3_DATAGRAM_DRAFT00: {
+ HttpDatagramSupport local_http_datagram_support =
+ LocalHttpDatagramSupport();
+ if (local_http_datagram_support != HttpDatagramSupport::kDraft00 &&
+ local_http_datagram_support != HttpDatagramSupport::kDraft00And04) {
+ break;
+ }
+ QUIC_DVLOG(1) << ENDPOINT
+ << "SETTINGS_H3_DATAGRAM_DRAFT00 received with value "
+ << value;
+ if (!version().UsesHttp3()) {
+ break;
+ }
+ if (!VerifySettingIsZeroOrOne(id, value)) {
+ return false;
+ }
+ if (value && http_datagram_support_ != HttpDatagramSupport::kDraft04) {
+ // If both draft-00 and draft-04 are supported, use draft-04.
+ http_datagram_support_ = HttpDatagramSupport::kDraft00;
+ }
+ break;
+ }
+ case SETTINGS_H3_DATAGRAM_DRAFT04: {
+ HttpDatagramSupport local_http_datagram_support =
+ LocalHttpDatagramSupport();
+ if (local_http_datagram_support != HttpDatagramSupport::kDraft04 &&
+ local_http_datagram_support != HttpDatagramSupport::kDraft00And04) {
break;
}
- QUIC_DVLOG(1) << ENDPOINT << "SETTINGS_H3_DATAGRAM received with value "
+ QUIC_DVLOG(1) << ENDPOINT
+ << "SETTINGS_H3_DATAGRAM_DRAFT04 received with value "
<< value;
if (!version().UsesHttp3()) {
break;
}
- if (value != 0 && value != 1) {
- std::string error_details = absl::StrCat(
- "received SETTINGS_H3_DATAGRAM with invalid value ", value);
- QUIC_PEER_BUG(quic_peer_bug_10360_7) << ENDPOINT << error_details;
- CloseConnectionWithDetails(QUIC_HTTP_RECEIVE_SPDY_SETTING,
- error_details);
+ if (!VerifySettingIsZeroOrOne(id, value)) {
return false;
}
- h3_datagram_supported_ = !!value;
+ if (value) {
+ http_datagram_support_ = HttpDatagramSupport::kDraft04;
+ }
break;
}
case SETTINGS_WEBTRANS_DRAFT00:
@@ -1156,14 +1174,7 @@ bool QuicSpdySession::OnSetting(uint64_t id, uint64_t value) {
QUIC_DVLOG(1) << ENDPOINT
<< "SETTINGS_ENABLE_WEBTRANSPORT received with value "
<< value;
- if (value != 0 && value != 1) {
- std::string error_details = absl::StrCat(
- "received SETTINGS_ENABLE_WEBTRANSPORT with invalid value ",
- value);
- QUIC_PEER_BUG(invalid SETTINGS_ENABLE_WEBTRANSPORT value)
- << ENDPOINT << error_details;
- CloseConnectionWithDetails(QUIC_HTTP_RECEIVE_SPDY_SETTING,
- error_details);
+ if (!VerifySettingIsZeroOrOne(id, value)) {
return false;
}
peer_supports_webtransport_ = (value == 1);
@@ -1236,8 +1247,7 @@ bool QuicSpdySession::ShouldReleaseHeadersStreamSequencerBuffer() {
return false;
}
-void QuicSpdySession::OnHeaders(SpdyStreamId stream_id,
- bool has_priority,
+void QuicSpdySession::OnHeaders(SpdyStreamId stream_id, bool has_priority,
const spdy::SpdyStreamPrecedence& precedence,
bool fin) {
if (has_priority) {
@@ -1361,13 +1371,9 @@ QuicStream* QuicSpdySession::ProcessPendingStream(PendingStream* pending) {
return receive_control_stream_;
}
case kServerPushStream: { // Push Stream.
- if (decline_server_push_stream_) {
- CloseConnectionWithDetails(QUIC_HTTP_RECEIVE_SERVER_PUSH,
- "Received server push stream");
- return nullptr;
- }
- QuicSpdyStream* stream = CreateIncomingStream(pending);
- return stream;
+ CloseConnectionWithDetails(QUIC_HTTP_RECEIVE_SERVER_PUSH,
+ "Received server push stream");
+ return nullptr;
}
case kQpackEncoderStream: { // QPACK encoder stream.
if (qpack_encoder_receive_stream_) {
@@ -1423,7 +1429,9 @@ QuicStream* QuicSpdySession::ProcessPendingStream(PendingStream* pending) {
default:
break;
}
- MaybeSendStopSendingFrame(pending->id(), QUIC_STREAM_STREAM_CREATION_ERROR);
+ MaybeSendStopSendingFrame(
+ pending->id(),
+ QuicResetStreamError::FromInternal(QUIC_STREAM_STREAM_CREATION_ERROR));
pending->StopReading();
return nullptr;
}
@@ -1576,9 +1584,7 @@ void QuicSpdySession::CloseConnectionOnDuplicateHttp3UnidirectionalStreams(
// static
void QuicSpdySession::LogHeaderCompressionRatioHistogram(
- bool using_qpack,
- bool is_sent,
- QuicByteCount compressed,
+ bool using_qpack, bool is_sent, QuicByteCount compressed,
QuicByteCount uncompressed) {
if (compressed <= 0 || uncompressed <= 0) {
return;
@@ -1624,15 +1630,25 @@ MessageStatus QuicSpdySession::SendHttp3Datagram(
QuicDatagramStreamId stream_id,
absl::optional<QuicDatagramContextId> context_id,
absl::string_view payload) {
+ if (!SupportsH3Datagram()) {
+ QUIC_BUG(send http datagram too early)
+ << "Refusing to send HTTP Datagram before SETTINGS received";
+ return MESSAGE_STATUS_INTERNAL_ERROR;
+ }
+ uint64_t stream_id_to_write = stream_id;
+ if (http_datagram_support_ != HttpDatagramSupport::kDraft00) {
+ // Stream ID is sent divided by four as per the specification.
+ stream_id_to_write /= kHttpDatagramStreamIdDivisor;
+ }
size_t slice_length =
- QuicDataWriter::GetVarInt62Len(stream_id) + payload.length();
+ QuicDataWriter::GetVarInt62Len(stream_id_to_write) + payload.length();
if (context_id.has_value()) {
slice_length += QuicDataWriter::GetVarInt62Len(context_id.value());
}
QuicBuffer buffer(connection()->helper()->GetStreamSendBufferAllocator(),
slice_length);
QuicDataWriter writer(slice_length, buffer.data());
- if (!writer.WriteVarInt62(stream_id)) {
+ if (!writer.WriteVarInt62(stream_id_to_write)) {
QUIC_BUG(h3 datagram stream ID write fail)
<< "Failed to write HTTP/3 datagram stream ID";
return MESSAGE_STATUS_INTERNAL_ERROR;
@@ -1673,8 +1689,8 @@ void QuicSpdySession::UnregisterHttp3DatagramFlowId(
void QuicSpdySession::OnMessageReceived(absl::string_view message) {
QuicSession::OnMessageReceived(message);
- if (!h3_datagram_supported_) {
- QUIC_DLOG(ERROR) << "Ignoring unexpected received HTTP/3 datagram";
+ if (!SupportsH3Datagram()) {
+ QUIC_DLOG(INFO) << "Ignoring unexpected received HTTP/3 datagram";
return;
}
QuicDataReader reader(message);
@@ -1683,7 +1699,12 @@ void QuicSpdySession::OnMessageReceived(absl::string_view message) {
QUIC_DLOG(ERROR) << "Failed to parse stream ID in received HTTP/3 datagram";
return;
}
- if (perspective() == Perspective::IS_SERVER) {
+ if (http_datagram_support_ != HttpDatagramSupport::kDraft00) {
+ // Stream ID is sent divided by four as per the specification.
+ stream_id64 *= kHttpDatagramStreamIdDivisor;
+ }
+ if (perspective() == Perspective::IS_SERVER &&
+ http_datagram_support_ == HttpDatagramSupport::kDraft00) {
auto it = h3_datagram_flow_id_to_stream_id_map_.find(stream_id64);
if (it == h3_datagram_flow_id_to_stream_id_map_.end()) {
QUIC_DLOG(INFO) << "Received unknown HTTP/3 datagram flow ID "
@@ -1713,10 +1734,14 @@ void QuicSpdySession::OnMessageReceived(absl::string_view message) {
}
bool QuicSpdySession::SupportsWebTransport() {
- return WillNegotiateWebTransport() && h3_datagram_supported_ &&
+ return WillNegotiateWebTransport() && SupportsH3Datagram() &&
peer_supports_webtransport_;
}
+bool QuicSpdySession::SupportsH3Datagram() const {
+ return http_datagram_support_ != HttpDatagramSupport::kNone;
+}
+
WebTransportHttp3* QuicSpdySession::GetWebTransportSession(
WebTransportSessionId id) {
if (!SupportsWebTransport()) {
@@ -1747,8 +1772,7 @@ void QuicSpdySession::OnStreamWaitingForClientSettings(QuicStreamId id) {
}
void QuicSpdySession::AssociateIncomingWebTransportStreamWithSession(
- WebTransportSessionId session_id,
- QuicStreamId stream_id) {
+ WebTransportSessionId session_id, QuicStreamId stream_id) {
if (QuicUtils::IsOutgoingStreamId(version(), stream_id, perspective())) {
QUIC_BUG(AssociateIncomingWebTransportStreamWithSession got outgoing stream)
<< ENDPOINT
@@ -1844,8 +1868,29 @@ void QuicSpdySession::DatagramObserver::OnDatagramProcessed(
session_->OnDatagramProcessed(status);
}
-bool QuicSpdySession::ShouldNegotiateHttp3Datagram() {
- return false;
+HttpDatagramSupport QuicSpdySession::LocalHttpDatagramSupport() {
+ return HttpDatagramSupport::kNone;
+}
+
+std::string HttpDatagramSupportToString(
+ HttpDatagramSupport http_datagram_support) {
+ switch (http_datagram_support) {
+ case HttpDatagramSupport::kNone:
+ return "None";
+ case HttpDatagramSupport::kDraft00:
+ return "Draft00";
+ case HttpDatagramSupport::kDraft04:
+ return "Draft04";
+ case HttpDatagramSupport::kDraft00And04:
+ return "Draft00And04";
+ }
+ return absl::StrCat("Unknown(", static_cast<int>(http_datagram_support), ")");
+}
+
+std::ostream& operator<<(std::ostream& os,
+ const HttpDatagramSupport& http_datagram_support) {
+ os << HttpDatagramSupportToString(http_datagram_support);
+ return os;
}
#undef ENDPOINT // undef for jumbo builds
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 78c132a6ad6..d8503cc05aa 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
@@ -6,6 +6,7 @@
#define QUICHE_QUIC_CORE_HTTP_QUIC_SPDY_SESSION_H_
#include <cstddef>
+#include <cstdint>
#include <list>
#include <memory>
#include <string>
@@ -90,8 +91,8 @@ class QUIC_EXPORT_PRIVATE Http3DebugVisitor {
virtual void OnDataFrameReceived(QuicStreamId /*stream_id*/,
QuicByteCount /*payload_length*/) {}
virtual void OnHeadersFrameReceived(
- QuicStreamId /*stream_id*/,
- QuicByteCount /*compressed_headers_length*/) {}
+ QuicStreamId /*stream_id*/, QuicByteCount /*compressed_headers_length*/) {
+ }
virtual void OnHeadersDecoded(QuicStreamId /*stream_id*/,
QuicHeaderList /*headers*/) {}
@@ -119,6 +120,20 @@ class QUIC_EXPORT_PRIVATE Http3DebugVisitor {
virtual void OnSettingsFrameResumed(const SettingsFrame& /*frame*/) {}
};
+// Whether draft-ietf-masque-h3-datagram is supported on this session and if so
+// which draft is currently in use.
+enum class HttpDatagramSupport : uint8_t {
+ kNone = 0, // HTTP Datagrams are not supported for this session.
+ kDraft00 = 1,
+ kDraft04 = 2,
+ kDraft00And04 = 3, // only used locally, we only negotiate one draft.
+};
+
+QUIC_EXPORT_PRIVATE std::string HttpDatagramSupportToString(
+ HttpDatagramSupport http_datagram_support);
+QUIC_EXPORT_PRIVATE std::ostream& operator<<(
+ std::ostream& os, const HttpDatagramSupport& http_datagram_support);
+
// A QUIC session for HTTP.
class QUIC_EXPORT_PRIVATE QuicSpdySession
: public QuicSession,
@@ -126,8 +141,7 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession
public QpackDecoder::EncoderStreamErrorDelegate {
public:
// Does not take ownership of |connection| or |visitor|.
- QuicSpdySession(QuicConnection* connection,
- QuicSession::Visitor* visitor,
+ QuicSpdySession(QuicConnection* connection, QuicSession::Visitor* visitor,
const QuicConfig& config,
const ParsedQuicVersionVector& supported_versions);
QuicSpdySession(const QuicSpdySession&) = delete;
@@ -148,14 +162,12 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession
// Called by |headers_stream_| when headers with a priority have been
// received for a stream. This method will only be called for server streams.
virtual void OnStreamHeadersPriority(
- QuicStreamId stream_id,
- const spdy::SpdyStreamPrecedence& precedence);
+ QuicStreamId stream_id, const spdy::SpdyStreamPrecedence& precedence);
// Called by |headers_stream_| when headers have been completely received
// for a stream. |fin| will be true if the fin flag was set in the headers
// frame.
- virtual void OnStreamHeaderList(QuicStreamId stream_id,
- bool fin,
+ virtual void OnStreamHeaderList(QuicStreamId stream_id, bool fin,
size_t frame_len,
const QuicHeaderList& header_list);
@@ -192,18 +204,14 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession
// If provided, |ack_notifier_delegate| will be registered to be notified when
// we have seen ACKs for all packets resulting from this call.
virtual size_t WriteHeadersOnHeadersStream(
- QuicStreamId id,
- spdy::SpdyHeaderBlock headers,
- bool fin,
+ QuicStreamId id, spdy::SpdyHeaderBlock headers, bool fin,
const spdy::SpdyStreamPrecedence& precedence,
QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener);
// Writes an HTTP/2 PRIORITY frame the to peer. Returns the size in bytes of
// the resulting PRIORITY frame.
- size_t WritePriority(QuicStreamId id,
- QuicStreamId parent_stream_id,
- int weight,
- bool exclusive);
+ size_t WritePriority(QuicStreamId id, QuicStreamId parent_stream_id,
+ int weight, bool exclusive);
// Writes an HTTP/3 PRIORITY_UPDATE frame to the peer.
void WriteHttp3PriorityUpdate(const PriorityUpdateFrame& priority_update);
@@ -349,8 +357,7 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession
// In order for measurements for different protocol to be comparable, the
// caller must ensure that uncompressed size is the total length of header
// names and values without any overhead.
- static void LogHeaderCompressionRatioHistogram(bool using_qpack,
- bool is_sent,
+ static void LogHeaderCompressionRatioHistogram(bool using_qpack, bool is_sent,
QuicByteCount compressed,
QuicByteCount uncompressed);
@@ -374,9 +381,11 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession
// extension.
virtual void OnAcceptChFrameReceivedViaAlps(const AcceptChFrame& /*frame*/);
- // Whether HTTP/3 datagrams are supported on this session, based on received
- // SETTINGS.
- bool h3_datagram_supported() const { return h3_datagram_supported_; }
+ // Whether HTTP datagrams are supported on this session and which draft is in
+ // use, based on received SETTINGS.
+ HttpDatagramSupport http_datagram_support() const {
+ return http_datagram_support_;
+ }
// This must not be used except by QuicSpdyStream::SendHttp3Datagram.
MessageStatus SendHttp3Datagram(
@@ -400,7 +409,7 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession
bool SupportsWebTransport();
// Indicates whether both the peer and us support HTTP/3 Datagrams.
- bool SupportsH3Datagram() { return h3_datagram_supported_; }
+ bool SupportsH3Datagram() const;
// Indicates whether the HTTP/3 session will indicate WebTransport support to
// the peer.
@@ -414,7 +423,7 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession
// until the SETTINGS are received. Only works for HTTP/3.
bool ShouldBufferRequestsUntilSettings() {
return version().UsesHttp3() && perspective() == Perspective::IS_SERVER &&
- ShouldNegotiateHttp3Datagram();
+ LocalHttpDatagramSupport() != HttpDatagramSupport::kNone;
}
// Returns if the incoming bidirectional streams should process data. This is
@@ -427,8 +436,7 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession
// Links the specified stream with a WebTransport session. If the session is
// not present, it is buffered until a corresponding stream is found.
void AssociateIncomingWebTransportStreamWithSession(
- WebTransportSessionId session_id,
- QuicStreamId stream_id);
+ WebTransportSessionId session_id, QuicStreamId stream_id);
void ProcessBufferedWebTransportStreamsForSession(WebTransportHttp3* session);
@@ -478,7 +486,8 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession
bool ShouldKeepConnectionAlive() const override;
// Overridden to buffer incoming unidirectional streams for version 99.
- bool UsesPendingStreams() const override;
+ bool UsesPendingStreamForFrame(QuicFrameType type,
+ QuicStreamId stream_id) const override;
// Processes incoming unidirectional streams; parses the stream type, and
// creates a new stream of the corresponding type. Returns the pointer to the
@@ -486,17 +495,12 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession
QuicStream* ProcessPendingStream(PendingStream* pending) override;
size_t WriteHeadersOnHeadersStreamImpl(
- QuicStreamId id,
- spdy::SpdyHeaderBlock headers,
- bool fin,
- QuicStreamId parent_stream_id,
- int weight,
- bool exclusive,
+ QuicStreamId id, spdy::SpdyHeaderBlock headers, bool fin,
+ QuicStreamId parent_stream_id, int weight, bool exclusive,
QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener);
void OnNewEncryptionKeyAvailable(
- EncryptionLevel level,
- std::unique_ptr<QuicEncrypter> encrypter) override;
+ EncryptionLevel level, std::unique_ptr<QuicEncrypter> encrypter) override;
// Sets the maximum size of the header compression table spdy_framer_ is
// willing to use to encode header blocks.
@@ -519,8 +523,9 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession
// Called whenever a datagram is dequeued or dropped from datagram_queue().
virtual void OnDatagramProcessed(absl::optional<MessageStatus> status);
- // Returns true if HTTP/3 datagram extension should be supported.
- virtual bool ShouldNegotiateHttp3Datagram();
+ // Returns which version of the HTTP/3 datagram extension we should advertise
+ // in settings and accept remote settings for.
+ virtual HttpDatagramSupport LocalHttpDatagramSupport();
private:
friend class test::QuicSpdySessionPeer;
@@ -546,10 +551,8 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession
// The following methods are called by the SimpleVisitor.
// Called when a HEADERS frame has been received.
- void OnHeaders(spdy::SpdyStreamId stream_id,
- bool has_priority,
- const spdy::SpdyStreamPrecedence& precedence,
- bool fin);
+ void OnHeaders(spdy::SpdyStreamId stream_id, bool has_priority,
+ const spdy::SpdyStreamPrecedence& precedence, bool fin);
// Called when a PRIORITY frame has been received.
void OnPriority(spdy::SpdyStreamId stream_id,
@@ -567,6 +570,8 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession
void FillSettingsFrame();
+ bool VerifySettingIsZeroOrOne(uint64_t id, uint64_t value);
+
std::unique_ptr<QpackEncoder> qpack_encoder_;
std::unique_ptr<QpackDecoder> qpack_decoder_;
@@ -654,8 +659,9 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession
// frame has been sent yet.
absl::optional<uint64_t> last_sent_http3_goaway_id_;
- // Whether both this endpoint and our peer support HTTP/3 datagrams.
- bool h3_datagram_supported_ = false;
+ // Whether both this endpoint and our peer support HTTP datagrams and which
+ // draft is in use for this session.
+ HttpDatagramSupport http_datagram_support_ = HttpDatagramSupport::kNone;
// Whether the peer has indicated WebTransport support.
bool peer_supports_webtransport_ = false;
@@ -678,10 +684,6 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession
// Limited to kMaxUnassociatedWebTransportStreams; when the list is full,
// oldest streams are evicated first.
std::list<BufferedWebTransportStream> buffered_streams_;
-
- // Latched value of flag_quic_decline_server_push_stream.
- const bool decline_server_push_stream_ =
- GetQuicReloadableFlag(quic_decline_server_push_stream);
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session_test.cc
index 5a984323de4..5c3e5255cce 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
@@ -186,6 +186,14 @@ class TestCryptoStream : public QuicCryptoStream, public QuicCryptoHandshaker {
void OnConnectionClosed(QuicErrorCode /*error*/,
ConnectionCloseSource /*source*/) override {}
+ SSL* GetSsl() const override { return nullptr; }
+
+ bool ExportKeyingMaterial(absl::string_view /*label*/,
+ absl::string_view /*context*/,
+ size_t /*result_len*/,
+ std::string* /*result*/) override {
+ return false;
+ }
private:
using QuicCryptoStream::session;
@@ -208,16 +216,15 @@ class TestStream : public QuicSpdyStream {
TestStream(QuicStreamId id, QuicSpdySession* session, StreamType type)
: QuicSpdyStream(id, session, type) {}
- TestStream(PendingStream* pending, QuicSpdySession* session, StreamType type)
- : QuicSpdyStream(pending, session, type) {}
+ TestStream(PendingStream* pending, QuicSpdySession* session)
+ : QuicSpdyStream(pending, session) {}
using QuicStream::CloseWriteSide;
void OnBodyAvailable() override {}
MOCK_METHOD(void, OnCanWrite, (), (override));
- MOCK_METHOD(bool,
- RetransmitStreamData,
+ MOCK_METHOD(bool, RetransmitStreamData,
(QuicStreamOffset, QuicByteCount, bool, TransmissionType),
(override));
@@ -227,9 +234,7 @@ class TestStream : public QuicSpdyStream {
class TestSession : public QuicSpdySession {
public:
explicit TestSession(QuicConnection* connection)
- : QuicSpdySession(connection,
- nullptr,
- DefaultQuicConfig(),
+ : QuicSpdySession(connection, nullptr, DefaultQuicConfig(),
CurrentSupportedVersions()),
crypto_stream_(this),
writev_consumes_all_data_(false) {
@@ -286,11 +291,7 @@ class TestSession : public QuicSpdySession {
}
TestStream* CreateIncomingStream(PendingStream* pending) override {
- QuicStreamId id = pending->id();
- TestStream* stream = new TestStream(
- pending, this,
- DetermineStreamType(id, connection()->version(), perspective(),
- /*is_incoming=*/true, BIDIRECTIONAL));
+ TestStream* stream = new TestStream(pending, this);
ActivateStream(absl::WrapUnique(stream));
return stream;
}
@@ -353,11 +354,11 @@ class TestSession : public QuicSpdySession {
bool ShouldNegotiateWebTransport() override { return supports_webtransport_; }
void set_supports_webtransport(bool value) { supports_webtransport_ = value; }
- bool ShouldNegotiateHttp3Datagram() override {
- return should_negotiate_h3_datagram_;
+ HttpDatagramSupport LocalHttpDatagramSupport() override {
+ return local_http_datagram_support_;
}
- void set_should_negotiate_h3_datagram(bool value) {
- should_negotiate_h3_datagram_ = value;
+ void set_local_http_datagram_support(HttpDatagramSupport value) {
+ local_http_datagram_support_ = value;
}
MOCK_METHOD(void, OnAcceptChFrame, (const AcceptChFrame&), (override));
@@ -365,14 +366,14 @@ class TestSession : public QuicSpdySession {
using QuicSession::closed_streams;
using QuicSession::ShouldKeepConnectionAlive;
using QuicSpdySession::ProcessPendingStream;
- using QuicSpdySession::UsesPendingStreams;
+ using QuicSpdySession::UsesPendingStreamForFrame;
private:
StrictMock<TestCryptoStream> crypto_stream_;
bool writev_consumes_all_data_;
bool supports_webtransport_ = false;
- bool should_negotiate_h3_datagram_ = false;
+ HttpDatagramSupport local_http_datagram_support_ = HttpDatagramSupport::kNone;
};
class QuicSpdySessionTestBase : public QuicTestWithParam<ParsedQuicVersion> {
@@ -387,11 +388,9 @@ class QuicSpdySessionTestBase : public QuicTestWithParam<ParsedQuicVersion> {
protected:
explicit QuicSpdySessionTestBase(Perspective perspective)
- : connection_(
- new StrictMock<MockQuicConnection>(&helper_,
- &alarm_factory_,
- perspective,
- SupportedVersions(GetParam()))),
+ : connection_(new StrictMock<MockQuicConnection>(
+ &helper_, &alarm_factory_, perspective,
+ SupportedVersions(GetParam()))),
session_(connection_) {
session_.config()->SetInitialStreamFlowControlWindowToSend(
kInitialStreamFlowControlWindowForTest);
@@ -510,8 +509,7 @@ class QuicSpdySessionTestBase : public QuicTestWithParam<ParsedQuicVersion> {
}
QuicStreamId StreamCountToId(QuicStreamCount stream_count,
- Perspective perspective,
- bool bidirectional) {
+ Perspective perspective, bool bidirectional) {
// Calculate and build up stream ID rather than use
// GetFirst... because the test that relies on this method
// needs to do the stream count where #1 is 0/1/2/3, and not
@@ -547,7 +545,7 @@ class QuicSpdySessionTestBase : public QuicTestWithParam<ParsedQuicVersion> {
void ReceiveWebTransportSettings() {
SettingsFrame settings;
- settings.values[SETTINGS_H3_DATAGRAM] = 1;
+ settings.values[SETTINGS_H3_DATAGRAM_DRAFT04] = 1;
settings.values[SETTINGS_WEBTRANS_DRAFT00] = 1;
std::string data =
std::string(1, kControlStream) + EncodeSettings(settings);
@@ -571,8 +569,14 @@ class QuicSpdySessionTestBase : public QuicTestWithParam<ParsedQuicVersion> {
headers.OnHeaderBlockStart();
headers.OnHeader(":method", "CONNECT");
headers.OnHeader(":protocol", "webtransport");
- headers.OnHeader("datagram-flow-id", absl::StrCat(session_id));
+ if (session_.http_datagram_support() == HttpDatagramSupport::kDraft00) {
+ headers.OnHeader("datagram-flow-id", absl::StrCat(session_id));
+ }
stream->OnStreamHeaderList(/*fin=*/true, 0, headers);
+ if (session_.http_datagram_support() != HttpDatagramSupport::kDraft00) {
+ stream->OnCapsule(
+ Capsule::RegisterDatagramNoContext(DatagramFormatType::WEBTRANSPORT));
+ }
WebTransportHttp3* web_transport =
session_.GetWebTransportSession(session_id);
ASSERT_TRUE(web_transport != nullptr);
@@ -592,6 +596,11 @@ class QuicSpdySessionTestBase : public QuicTestWithParam<ParsedQuicVersion> {
session_.OnStreamFrame(frame);
}
+ void TestHttpDatagramSetting(HttpDatagramSupport local_support,
+ HttpDatagramSupport remote_support,
+ HttpDatagramSupport expected_support,
+ bool expected_datagram_supported);
+
MockQuicConnectionHelper helper_;
MockAlarmFactory alarm_factory_;
StrictMock<MockQuicConnection>* connection_;
@@ -606,16 +615,29 @@ class QuicSpdySessionTestServer : public QuicSpdySessionTestBase {
: QuicSpdySessionTestBase(Perspective::IS_SERVER) {}
};
-INSTANTIATE_TEST_SUITE_P(Tests,
- QuicSpdySessionTestServer,
+INSTANTIATE_TEST_SUITE_P(Tests, QuicSpdySessionTestServer,
::testing::ValuesIn(AllSupportedVersions()),
::testing::PrintToStringParamName());
-TEST_P(QuicSpdySessionTestServer, UsesPendingStreams) {
+TEST_P(QuicSpdySessionTestServer, UsesPendingStreamsForFrame) {
if (!VersionUsesHttp3(transport_version())) {
return;
}
- EXPECT_TRUE(session_.UsesPendingStreams());
+ EXPECT_TRUE(session_.UsesPendingStreamForFrame(
+ STREAM_FRAME, QuicUtils::GetFirstUnidirectionalStreamId(
+ transport_version(), Perspective::IS_CLIENT)));
+ EXPECT_TRUE(session_.UsesPendingStreamForFrame(
+ RST_STREAM_FRAME, QuicUtils::GetFirstUnidirectionalStreamId(
+ transport_version(), Perspective::IS_CLIENT)));
+ EXPECT_FALSE(session_.UsesPendingStreamForFrame(
+ RST_STREAM_FRAME, QuicUtils::GetFirstUnidirectionalStreamId(
+ transport_version(), Perspective::IS_SERVER)));
+ EXPECT_FALSE(session_.UsesPendingStreamForFrame(
+ STOP_SENDING_FRAME, QuicUtils::GetFirstUnidirectionalStreamId(
+ transport_version(), Perspective::IS_CLIENT)));
+ EXPECT_FALSE(session_.UsesPendingStreamForFrame(
+ RST_STREAM_FRAME, QuicUtils::GetFirstBidirectionalStreamId(
+ transport_version(), Perspective::IS_CLIENT)));
}
TEST_P(QuicSpdySessionTestServer, PeerAddress) {
@@ -1839,16 +1861,29 @@ class QuicSpdySessionTestClient : public QuicSpdySessionTestBase {
: QuicSpdySessionTestBase(Perspective::IS_CLIENT) {}
};
-INSTANTIATE_TEST_SUITE_P(Tests,
- QuicSpdySessionTestClient,
+INSTANTIATE_TEST_SUITE_P(Tests, QuicSpdySessionTestClient,
::testing::ValuesIn(AllSupportedVersions()),
::testing::PrintToStringParamName());
-TEST_P(QuicSpdySessionTestClient, UsesPendingStreams) {
+TEST_P(QuicSpdySessionTestClient, UsesPendingStreamsForFrame) {
if (!VersionUsesHttp3(transport_version())) {
return;
}
- EXPECT_TRUE(session_.UsesPendingStreams());
+ EXPECT_TRUE(session_.UsesPendingStreamForFrame(
+ STREAM_FRAME, QuicUtils::GetFirstUnidirectionalStreamId(
+ transport_version(), Perspective::IS_SERVER)));
+ EXPECT_TRUE(session_.UsesPendingStreamForFrame(
+ RST_STREAM_FRAME, QuicUtils::GetFirstUnidirectionalStreamId(
+ transport_version(), Perspective::IS_SERVER)));
+ EXPECT_FALSE(session_.UsesPendingStreamForFrame(
+ RST_STREAM_FRAME, QuicUtils::GetFirstUnidirectionalStreamId(
+ transport_version(), Perspective::IS_CLIENT)));
+ EXPECT_FALSE(session_.UsesPendingStreamForFrame(
+ STOP_SENDING_FRAME, QuicUtils::GetFirstUnidirectionalStreamId(
+ transport_version(), Perspective::IS_SERVER)));
+ EXPECT_FALSE(session_.UsesPendingStreamForFrame(
+ RST_STREAM_FRAME, QuicUtils::GetFirstBidirectionalStreamId(
+ transport_version(), Perspective::IS_SERVER)));
}
// Regression test for crbug.com/977581.
@@ -2007,33 +2042,11 @@ TEST_P(QuicSpdySessionTestClient, Http3ServerPush) {
std::string frame_type1 = absl::HexStringToBytes("01");
QuicStreamId stream_id1 =
GetNthServerInitiatedUnidirectionalStreamId(transport_version(), 0);
- if (!GetQuicReloadableFlag(quic_decline_server_push_stream)) {
- session_.OnStreamFrame(QuicStreamFrame(stream_id1, /* fin = */ false,
- /* offset = */ 0, frame_type1));
-
- EXPECT_EQ(1u, QuicSessionPeer::GetNumOpenDynamicStreams(&session_));
- QuicStream* stream = session_.GetOrCreateStream(stream_id1);
- EXPECT_EQ(1u, QuicStreamPeer::bytes_consumed(stream));
- EXPECT_EQ(1u, session_.flow_controller()->bytes_consumed());
-
- // The same stream type can be encoded differently.
- std::string frame_type2 = absl::HexStringToBytes("80000001");
- QuicStreamId stream_id2 =
- GetNthServerInitiatedUnidirectionalStreamId(transport_version(), 1);
- session_.OnStreamFrame(QuicStreamFrame(stream_id2, /* fin = */ false,
- /* offset = */ 0, frame_type2));
-
- EXPECT_EQ(2u, QuicSessionPeer::GetNumOpenDynamicStreams(&session_));
- stream = session_.GetOrCreateStream(stream_id2);
- EXPECT_EQ(4u, QuicStreamPeer::bytes_consumed(stream));
- EXPECT_EQ(5u, session_.flow_controller()->bytes_consumed());
- } else {
- EXPECT_CALL(*connection_,
- CloseConnection(QUIC_HTTP_RECEIVE_SERVER_PUSH, _, _))
- .Times(1);
- session_.OnStreamFrame(QuicStreamFrame(stream_id1, /* fin = */ false,
- /* offset = */ 0, frame_type1));
- }
+ EXPECT_CALL(*connection_,
+ CloseConnection(QUIC_HTTP_RECEIVE_SERVER_PUSH, _, _))
+ .Times(1);
+ session_.OnStreamFrame(QuicStreamFrame(stream_id1, /* fin = */ false,
+ /* offset = */ 0, frame_type1));
}
TEST_P(QuicSpdySessionTestClient, Http3ServerPushOutofOrderFrame) {
@@ -2060,18 +2073,10 @@ TEST_P(QuicSpdySessionTestClient, Http3ServerPushOutofOrderFrame) {
// Receiving some stream data without stream type does not open the stream.
session_.OnStreamFrame(data2);
EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(&session_));
-
- if (!GetQuicReloadableFlag(quic_decline_server_push_stream)) {
- session_.OnStreamFrame(data1);
- EXPECT_EQ(1u, QuicSessionPeer::GetNumOpenDynamicStreams(&session_));
- QuicStream* stream = session_.GetOrCreateStream(stream_id);
- EXPECT_EQ(3u, stream->highest_received_byte_offset());
- } else {
- EXPECT_CALL(*connection_,
- CloseConnection(QUIC_HTTP_RECEIVE_SERVER_PUSH, _, _))
- .Times(1);
- session_.OnStreamFrame(data1);
- }
+ EXPECT_CALL(*connection_,
+ CloseConnection(QUIC_HTTP_RECEIVE_SERVER_PUSH, _, _))
+ .Times(1);
+ session_.OnStreamFrame(data1);
}
TEST_P(QuicSpdySessionTestServer, OnStreamFrameLost) {
@@ -2580,10 +2585,10 @@ TEST_P(QuicSpdySessionTestClient, ResetAfterInvalidIncomingStreamType) {
return;
}
CompleteHandshake();
- ASSERT_TRUE(session_.UsesPendingStreams());
const QuicStreamId stream_id =
GetNthServerInitiatedUnidirectionalStreamId(transport_version(), 0);
+ ASSERT_TRUE(session_.UsesPendingStreamForFrame(STREAM_FRAME, stream_id));
// Payload consists of two bytes. The first byte is an unknown unidirectional
// stream type. The second one would be the type of a push stream, but it
@@ -2627,10 +2632,10 @@ TEST_P(QuicSpdySessionTestClient, FinAfterInvalidIncomingStreamType) {
return;
}
CompleteHandshake();
- ASSERT_TRUE(session_.UsesPendingStreams());
const QuicStreamId stream_id =
GetNthServerInitiatedUnidirectionalStreamId(transport_version(), 0);
+ ASSERT_TRUE(session_.UsesPendingStreamForFrame(STREAM_FRAME, stream_id));
// Payload consists of two bytes. The first byte is an unknown unidirectional
// stream type. The second one would be the type of a push stream, but it
@@ -2666,10 +2671,10 @@ TEST_P(QuicSpdySessionTestClient, ResetInMiddleOfStreamType) {
if (!VersionUsesHttp3(transport_version())) {
return;
}
- ASSERT_TRUE(session_.UsesPendingStreams());
const QuicStreamId stream_id =
GetNthServerInitiatedUnidirectionalStreamId(transport_version(), 0);
+ ASSERT_TRUE(session_.UsesPendingStreamForFrame(STREAM_FRAME, stream_id));
// Payload is the first byte of a two byte varint encoding.
std::string payload = absl::HexStringToBytes("40");
@@ -2694,10 +2699,10 @@ TEST_P(QuicSpdySessionTestClient, FinInMiddleOfStreamType) {
if (!VersionUsesHttp3(transport_version())) {
return;
}
- ASSERT_TRUE(session_.UsesPendingStreams());
const QuicStreamId stream_id =
GetNthServerInitiatedUnidirectionalStreamId(transport_version(), 0);
+ ASSERT_TRUE(session_.UsesPendingStreamForFrame(STREAM_FRAME, stream_id));
// Payload is the first byte of a two byte varint encoding with a FIN.
std::string payload = absl::HexStringToBytes("40");
@@ -3417,16 +3422,32 @@ TEST_P(QuicSpdySessionTestClient, AlpsTwoSettingsFrame) {
EXPECT_EQ("multiple SETTINGS frames", error.value());
}
-TEST_P(QuicSpdySessionTestClient, H3DatagramSetting) {
+void QuicSpdySessionTestBase::TestHttpDatagramSetting(
+ HttpDatagramSupport local_support, HttpDatagramSupport remote_support,
+ HttpDatagramSupport expected_support, bool expected_datagram_supported) {
if (!version().UsesHttp3()) {
return;
}
- session_.set_should_negotiate_h3_datagram(true);
+ session_.set_local_http_datagram_support(local_support);
// HTTP/3 datagrams aren't supported before SETTINGS are received.
- EXPECT_FALSE(session_.h3_datagram_supported());
+ EXPECT_FALSE(session_.SupportsH3Datagram());
+ EXPECT_EQ(session_.http_datagram_support(), HttpDatagramSupport::kNone);
// Receive SETTINGS.
SettingsFrame settings;
- settings.values[SETTINGS_H3_DATAGRAM] = 1;
+ switch (remote_support) {
+ case HttpDatagramSupport::kNone:
+ break;
+ case HttpDatagramSupport::kDraft00:
+ settings.values[SETTINGS_H3_DATAGRAM_DRAFT00] = 1;
+ break;
+ case HttpDatagramSupport::kDraft04:
+ settings.values[SETTINGS_H3_DATAGRAM_DRAFT04] = 1;
+ break;
+ case HttpDatagramSupport::kDraft00And04:
+ settings.values[SETTINGS_H3_DATAGRAM_DRAFT00] = 1;
+ settings.values[SETTINGS_H3_DATAGRAM_DRAFT04] = 1;
+ break;
+ }
std::string data = std::string(1, kControlStream) + EncodeSettings(settings);
QuicStreamId stream_id =
GetNthServerInitiatedUnidirectionalStreamId(transport_version(), 3);
@@ -3436,15 +3457,88 @@ TEST_P(QuicSpdySessionTestClient, H3DatagramSetting) {
EXPECT_CALL(debug_visitor, OnPeerControlStreamCreated(stream_id));
EXPECT_CALL(debug_visitor, OnSettingsFrameReceived(settings));
session_.OnStreamFrame(frame);
- // HTTP/3 datagrams are now supported.
- EXPECT_TRUE(session_.h3_datagram_supported());
+ EXPECT_EQ(session_.http_datagram_support(), expected_support);
+ EXPECT_EQ(session_.SupportsH3Datagram(), expected_datagram_supported);
+}
+
+TEST_P(QuicSpdySessionTestClient, HttpDatagramSettingLocal00Remote00) {
+ TestHttpDatagramSetting(
+ /*local_support=*/HttpDatagramSupport::kDraft00,
+ /*remote_support=*/HttpDatagramSupport::kDraft00,
+ /*expected_support=*/HttpDatagramSupport::kDraft00,
+ /*expected_datagram_supported=*/true);
+}
+
+TEST_P(QuicSpdySessionTestClient, HttpDatagramSettingLocal00Remote04) {
+ TestHttpDatagramSetting(
+ /*local_support=*/HttpDatagramSupport::kDraft00,
+ /*remote_support=*/HttpDatagramSupport::kDraft04,
+ /*expected_support=*/HttpDatagramSupport::kNone,
+ /*expected_datagram_supported=*/false);
+}
+
+TEST_P(QuicSpdySessionTestClient, HttpDatagramSettingLocal00Remote00And04) {
+ TestHttpDatagramSetting(
+ /*local_support=*/HttpDatagramSupport::kDraft00,
+ /*remote_support=*/HttpDatagramSupport::kDraft00And04,
+ /*expected_support=*/HttpDatagramSupport::kDraft00,
+ /*expected_datagram_supported=*/true);
+}
+
+TEST_P(QuicSpdySessionTestClient, HttpDatagramSettingLocal04Remote00) {
+ TestHttpDatagramSetting(
+ /*local_support=*/HttpDatagramSupport::kDraft04,
+ /*remote_support=*/HttpDatagramSupport::kDraft00,
+ /*expected_support=*/HttpDatagramSupport::kNone,
+ /*expected_datagram_supported=*/false);
+}
+
+TEST_P(QuicSpdySessionTestClient, HttpDatagramSettingLocal04Remote04) {
+ TestHttpDatagramSetting(
+ /*local_support=*/HttpDatagramSupport::kDraft04,
+ /*remote_support=*/HttpDatagramSupport::kDraft04,
+ /*expected_support=*/HttpDatagramSupport::kDraft04,
+ /*expected_datagram_supported=*/true);
+}
+
+TEST_P(QuicSpdySessionTestClient, HttpDatagramSettingLocal04Remote00And04) {
+ TestHttpDatagramSetting(
+ /*local_support=*/HttpDatagramSupport::kDraft04,
+ /*remote_support=*/HttpDatagramSupport::kDraft00And04,
+ /*expected_support=*/HttpDatagramSupport::kDraft04,
+ /*expected_datagram_supported=*/true);
+}
+
+TEST_P(QuicSpdySessionTestClient, HttpDatagramSettingLocal00And04Remote00) {
+ TestHttpDatagramSetting(
+ /*local_support=*/HttpDatagramSupport::kDraft00And04,
+ /*remote_support=*/HttpDatagramSupport::kDraft00,
+ /*expected_support=*/HttpDatagramSupport::kDraft00,
+ /*expected_datagram_supported=*/true);
+}
+
+TEST_P(QuicSpdySessionTestClient, HttpDatagramSettingLocal00And04Remote04) {
+ TestHttpDatagramSetting(
+ /*local_support=*/HttpDatagramSupport::kDraft00And04,
+ /*remote_support=*/HttpDatagramSupport::kDraft04,
+ /*expected_support=*/HttpDatagramSupport::kDraft04,
+ /*expected_datagram_supported=*/true);
+}
+
+TEST_P(QuicSpdySessionTestClient,
+ HttpDatagramSettingLocal00And04Remote00And04) {
+ TestHttpDatagramSetting(
+ /*local_support=*/HttpDatagramSupport::kDraft00And04,
+ /*remote_support=*/HttpDatagramSupport::kDraft00And04,
+ /*expected_support=*/HttpDatagramSupport::kDraft04,
+ /*expected_datagram_supported=*/true);
}
TEST_P(QuicSpdySessionTestClient, WebTransportSetting) {
if (!version().UsesHttp3()) {
return;
}
- session_.set_should_negotiate_h3_datagram(true);
+ session_.set_local_http_datagram_support(HttpDatagramSupport::kDraft00And04);
session_.set_supports_webtransport(true);
EXPECT_FALSE(session_.SupportsWebTransport());
@@ -3457,7 +3551,7 @@ TEST_P(QuicSpdySessionTestClient, WebTransportSetting) {
CompleteHandshake();
SettingsFrame server_settings;
- server_settings.values[SETTINGS_H3_DATAGRAM] = 1;
+ server_settings.values[SETTINGS_H3_DATAGRAM_DRAFT04] = 1;
server_settings.values[SETTINGS_WEBTRANS_DRAFT00] = 1;
std::string data =
std::string(1, kControlStream) + EncodeSettings(server_settings);
@@ -3474,7 +3568,7 @@ TEST_P(QuicSpdySessionTestClient, WebTransportSettingSetToZero) {
if (!version().UsesHttp3()) {
return;
}
- session_.set_should_negotiate_h3_datagram(true);
+ session_.set_local_http_datagram_support(HttpDatagramSupport::kDraft00And04);
session_.set_supports_webtransport(true);
EXPECT_FALSE(session_.SupportsWebTransport());
@@ -3487,7 +3581,7 @@ TEST_P(QuicSpdySessionTestClient, WebTransportSettingSetToZero) {
CompleteHandshake();
SettingsFrame server_settings;
- server_settings.values[SETTINGS_H3_DATAGRAM] = 1;
+ server_settings.values[SETTINGS_H3_DATAGRAM_DRAFT04] = 1;
server_settings.values[SETTINGS_WEBTRANS_DRAFT00] = 0;
std::string data =
std::string(1, kControlStream) + EncodeSettings(server_settings);
@@ -3504,7 +3598,7 @@ TEST_P(QuicSpdySessionTestServer, WebTransportSetting) {
if (!version().UsesHttp3()) {
return;
}
- session_.set_should_negotiate_h3_datagram(true);
+ session_.set_local_http_datagram_support(HttpDatagramSupport::kDraft00And04);
session_.set_supports_webtransport(true);
EXPECT_FALSE(session_.SupportsWebTransport());
@@ -3521,7 +3615,7 @@ TEST_P(QuicSpdySessionTestServer, BufferingIncomingStreams) {
if (!version().UsesHttp3()) {
return;
}
- session_.set_should_negotiate_h3_datagram(true);
+ session_.set_local_http_datagram_support(HttpDatagramSupport::kDraft00And04);
session_.set_supports_webtransport(true);
CompleteHandshake();
@@ -3554,7 +3648,7 @@ TEST_P(QuicSpdySessionTestServer, BufferingIncomingStreamsLimit) {
if (!version().UsesHttp3()) {
return;
}
- session_.set_should_negotiate_h3_datagram(true);
+ session_.set_local_http_datagram_support(HttpDatagramSupport::kDraft00And04);
session_.set_supports_webtransport(true);
CompleteHandshake();
@@ -3595,7 +3689,7 @@ TEST_P(QuicSpdySessionTestServer, ResetOutgoingWebTransportStreams) {
if (!version().UsesHttp3()) {
return;
}
- session_.set_should_negotiate_h3_datagram(true);
+ session_.set_local_http_datagram_support(HttpDatagramSupport::kDraft00And04);
session_.set_supports_webtransport(true);
CompleteHandshake();
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 bc23474e72a..c25d33a2891 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
@@ -13,18 +13,20 @@
#include "absl/strings/numbers.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
+#include "quic/core/http/capsule.h"
#include "quic/core/http/http_constants.h"
#include "quic/core/http/http_decoder.h"
+#include "quic/core/http/http_frames.h"
#include "quic/core/http/quic_spdy_session.h"
#include "quic/core/http/spdy_utils.h"
#include "quic/core/http/web_transport_http3.h"
#include "quic/core/qpack/qpack_decoder.h"
#include "quic/core/qpack/qpack_encoder.h"
-#include "quic/core/quic_error_codes.h"
#include "quic/core/quic_types.h"
#include "quic/core/quic_utils.h"
#include "quic/core/quic_versions.h"
#include "quic/core/quic_write_blocked_list.h"
+#include "quic/core/web_transport_interface.h"
#include "quic/platform/api/quic_bug_tracker.h"
#include "quic/platform/api/quic_flag_utils.h"
#include "quic/platform/api/quic_flags.h"
@@ -129,13 +131,11 @@ class QuicSpdyStream::HttpDecoderVisitor : public HttpDecoder::Visitor {
}
void OnWebTransportStreamFrameType(
- QuicByteCount header_length,
- WebTransportSessionId session_id) override {
+ QuicByteCount header_length, WebTransportSessionId session_id) override {
stream_->OnWebTransportStreamFrameType(header_length, session_id);
}
- bool OnUnknownFrameStart(uint64_t frame_type,
- QuicByteCount header_length,
+ bool OnUnknownFrameStart(uint64_t frame_type, QuicByteCount header_length,
QuicByteCount payload_length) override {
return stream_->OnUnknownFrameStart(frame_type, header_length,
payload_length);
@@ -213,9 +213,8 @@ QuicSpdyStream::QuicSpdyStream(QuicStreamId id, QuicSpdySession* spdy_session,
}
QuicSpdyStream::QuicSpdyStream(PendingStream* pending,
- QuicSpdySession* spdy_session,
- StreamType type)
- : QuicStream(pending, spdy_session, type, /*is_static=*/false),
+ QuicSpdySession* spdy_session)
+ : QuicStream(pending, spdy_session, /*is_static=*/false),
spdy_session_(spdy_session),
on_body_available_called_because_sequencer_is_closed_(false),
visitor_(nullptr),
@@ -250,8 +249,7 @@ QuicSpdyStream::QuicSpdyStream(PendingStream* pending,
QuicSpdyStream::~QuicSpdyStream() {}
size_t QuicSpdyStream::WriteHeaders(
- SpdyHeaderBlock header_block,
- bool fin,
+ SpdyHeaderBlock header_block, bool fin,
QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) {
if (!AssertNotWebTransportDataStream("writing headers")) {
return 0;
@@ -287,6 +285,16 @@ size_t QuicSpdyStream::WriteHeaders(
SetFinSent();
CloseWriteSide();
}
+
+ if (web_transport_ != nullptr &&
+ session()->perspective() == Perspective::IS_CLIENT) {
+ // This will send a capsule and therefore needs to happen after headers have
+ // been sent.
+ RegisterHttp3DatagramContextId(
+ web_transport_->context_id(), DatagramFormatType::WEBTRANSPORT,
+ /*format_additional_data=*/absl::string_view(), web_transport_.get());
+ }
+
return bytes_written;
}
@@ -356,8 +364,7 @@ size_t QuicSpdyStream::WriteTrailers(
return bytes_written;
}
-QuicConsumedData QuicSpdyStream::WritevBody(const struct iovec* iov,
- int count,
+QuicConsumedData QuicSpdyStream::WritevBody(const struct iovec* iov, int count,
bool fin) {
QuicMemSliceStorage storage(
iov, count,
@@ -391,7 +398,7 @@ bool QuicSpdyStream::WriteDataFrameHeader(QuicByteCount data_length,
if (can_write) {
// Save one copy and allocation if send buffer can accomodate the header.
QuicMemSlice header_slice(std::move(header));
- WriteMemSlices(QuicMemSliceSpan(&header_slice), false);
+ WriteMemSlices(absl::MakeSpan(&header_slice, 1), false);
} else {
QUICHE_DCHECK(force_write);
WriteOrBufferData(header.AsStringView(), false, nullptr);
@@ -399,26 +406,8 @@ bool QuicSpdyStream::WriteDataFrameHeader(QuicByteCount data_length,
return true;
}
-QuicConsumedData QuicSpdyStream::WriteBodySlices(QuicMemSliceSpan slices,
- bool fin) {
- if (!VersionUsesHttp3(transport_version()) || slices.empty()) {
- return WriteMemSlices(slices, fin);
- }
-
- QuicConnection::ScopedPacketFlusher flusher(spdy_session_->connection());
- if (!WriteDataFrameHeader(slices.total_length(), /*force_write=*/false)) {
- return {0, false};
- }
-
- QUIC_DLOG(INFO) << ENDPOINT << "Stream " << id()
- << " is writing DATA frame payload of length "
- << slices.total_length();
- return WriteMemSlices(slices, fin);
-}
-
QuicConsumedData QuicSpdyStream::WriteBodySlices(
- absl::Span<QuicMemSlice> slices,
- bool fin) {
+ absl::Span<QuicMemSlice> slices, bool fin) {
if (!VersionUsesHttp3(transport_version()) || slices.empty()) {
return WriteMemSlices(slices, fin);
}
@@ -477,9 +466,7 @@ bool QuicSpdyStream::HasBytesToRead() const {
return body_manager_.HasBytesToRead();
}
-void QuicSpdyStream::MarkTrailersConsumed() {
- trailers_consumed_ = true;
-}
+void QuicSpdyStream::MarkTrailersConsumed() { trailers_consumed_ = true; }
uint64_t QuicSpdyStream::total_body_bytes_read() const {
if (VersionUsesHttp3(transport_version())) {
@@ -501,14 +488,14 @@ void QuicSpdyStream::ConsumeHeaderList() {
}
if (body_manager_.HasBytesToRead()) {
- OnBodyAvailable();
+ HandleBodyAvailable();
return;
}
if (sequencer()->IsClosed() &&
!on_body_available_called_because_sequencer_is_closed_) {
on_body_available_called_because_sequencer_is_closed_ = true;
- OnBodyAvailable();
+ HandleBodyAvailable();
}
}
@@ -519,8 +506,7 @@ void QuicSpdyStream::OnStreamHeadersPriority(
SetPriority(precedence);
}
-void QuicSpdyStream::OnStreamHeaderList(bool fin,
- size_t frame_len,
+void QuicSpdyStream::OnStreamHeaderList(bool fin, size_t frame_len,
const QuicHeaderList& header_list) {
if (!spdy_session()->user_agent_id().has_value()) {
std::string uaid;
@@ -583,14 +569,14 @@ void QuicSpdyStream::OnHeadersDecoded(QuicHeaderList headers,
}
}
-void QuicSpdyStream::OnHeaderDecodingError(absl::string_view error_message) {
+void QuicSpdyStream::OnHeaderDecodingError(QuicErrorCode error_code,
+ absl::string_view error_message) {
qpack_decoded_headers_accumulator_.reset();
std::string connection_close_error_message = absl::StrCat(
"Error decoding ", headers_decompressed_ ? "trailers" : "headers",
" on stream ", id(), ": ", error_message);
- OnUnrecoverableError(QUIC_QPACK_DECOMPRESSION_FAILED,
- connection_close_error_message);
+ OnUnrecoverableError(error_code, connection_close_error_message);
}
void QuicSpdyStream::MaybeSendPriorityUpdateFrame() {
@@ -613,14 +599,10 @@ void QuicSpdyStream::MaybeSendPriorityUpdateFrame() {
spdy_session_->WriteHttp3PriorityUpdate(priority_update);
}
-void QuicSpdyStream::OnHeadersTooLarge() {
- Reset(QUIC_HEADERS_TOO_LARGE);
-}
+void QuicSpdyStream::OnHeadersTooLarge() { Reset(QUIC_HEADERS_TOO_LARGE); }
void QuicSpdyStream::OnInitialHeadersComplete(
- bool fin,
- size_t /*frame_len*/,
- const QuicHeaderList& header_list) {
+ bool fin, size_t /*frame_len*/, const QuicHeaderList& header_list) {
// TODO(b/134706391): remove |fin| argument.
headers_decompressed_ = true;
header_list_ = header_list;
@@ -646,8 +628,7 @@ void QuicSpdyStream::OnInitialHeadersComplete(
}
void QuicSpdyStream::OnPromiseHeaderList(
- QuicStreamId /* promised_id */,
- size_t /* frame_len */,
+ QuicStreamId /* promised_id */, size_t /* frame_len */,
const QuicHeaderList& /*header_list */) {
// To be overridden in QuicSpdyClientStream. Not supported on
// server side.
@@ -656,9 +637,7 @@ void QuicSpdyStream::OnPromiseHeaderList(
}
void QuicSpdyStream::OnTrailingHeadersComplete(
- bool fin,
- size_t /*frame_len*/,
- const QuicHeaderList& header_list) {
+ bool fin, size_t /*frame_len*/, const QuicHeaderList& header_list) {
// TODO(b/134706391): remove |fin| argument.
QUICHE_DCHECK(!trailers_decompressed_);
if (!VersionUsesHttp3(transport_version()) && fin_received()) {
@@ -706,6 +685,12 @@ void QuicSpdyStream::OnPriorityFrame(
void QuicSpdyStream::OnStreamReset(const QuicRstStreamFrame& frame) {
if (web_transport_data_ != nullptr) {
+ WebTransportStreamVisitor* webtransport_visitor =
+ web_transport_data_->adapter.visitor();
+ if (webtransport_visitor != nullptr) {
+ webtransport_visitor->OnResetStreamReceived(
+ Http3ErrorToWebTransportOrDefault(frame.ietf_error_code));
+ }
QuicStream::OnStreamReset(frame);
return;
}
@@ -744,11 +729,11 @@ void QuicSpdyStream::OnStreamReset(const QuicRstStreamFrame& frame) {
<< "Received QUIC_STREAM_NO_ERROR, not discarding response";
set_rst_received(true);
MaybeIncreaseHighestReceivedOffset(frame.byte_offset);
- set_stream_error(frame.error_code);
+ set_stream_error(frame.error());
CloseWriteSide();
}
-void QuicSpdyStream::Reset(QuicRstStreamErrorCode error) {
+void QuicSpdyStream::ResetWithError(QuicResetStreamError error) {
if (VersionUsesHttp3(transport_version()) && !fin_received() &&
spdy_session_->qpack_decoder() && web_transport_data_ == nullptr) {
QUIC_CODE_COUNT_N(quic_abort_qpack_on_stream_reset, 2, 2);
@@ -759,7 +744,30 @@ void QuicSpdyStream::Reset(QuicRstStreamErrorCode error) {
}
}
- QuicStream::Reset(error);
+ QuicStream::ResetWithError(error);
+}
+
+bool QuicSpdyStream::OnStopSending(QuicResetStreamError error) {
+ if (web_transport_data_ != nullptr) {
+ WebTransportStreamVisitor* visitor = web_transport_data_->adapter.visitor();
+ if (visitor != nullptr) {
+ visitor->OnStopSendingReceived(
+ Http3ErrorToWebTransportOrDefault(error.ietf_application_code()));
+ }
+ }
+
+ return QuicStream::OnStopSending(error);
+}
+
+void QuicSpdyStream::OnWriteSideInDataRecvdState() {
+ if (web_transport_data_ != nullptr) {
+ WebTransportStreamVisitor* visitor = web_transport_data_->adapter.visitor();
+ if (visitor != nullptr) {
+ visitor->OnWriteSideInDataRecvdState();
+ }
+ }
+
+ QuicStream::OnWriteSideInDataRecvdState();
}
void QuicSpdyStream::OnDataAvailable() {
@@ -769,7 +777,7 @@ void QuicSpdyStream::OnDataAvailable() {
}
if (!VersionUsesHttp3(transport_version())) {
- OnBodyAvailable();
+ HandleBodyAvailable();
return;
}
@@ -814,20 +822,20 @@ void QuicSpdyStream::OnDataAvailable() {
}
}
- // Do not call OnBodyAvailable() until headers are consumed.
+ // Do not call HandleBodyAvailable() until headers are consumed.
if (!FinishedReadingHeaders()) {
return;
}
if (body_manager_.HasBytesToRead()) {
- OnBodyAvailable();
+ HandleBodyAvailable();
return;
}
if (sequencer()->IsClosed() &&
!on_body_available_called_because_sequencer_is_closed_) {
on_body_available_called_because_sequencer_is_closed_ = true;
- OnBodyAvailable();
+ HandleBodyAvailable();
}
}
@@ -849,7 +857,7 @@ void QuicSpdyStream::OnClose() {
}
if (web_transport_ != nullptr) {
- web_transport_->CloseAllAssociatedStreams();
+ web_transport_->OnConnectStreamClosing();
}
if (web_transport_data_ != nullptr) {
WebTransportHttp3* web_transport =
@@ -989,8 +997,7 @@ void QuicSpdyStream::OnStreamFrameRetransmitted(QuicStreamOffset offset,
}
QuicByteCount QuicSpdyStream::GetNumFrameHeadersInInterval(
- QuicStreamOffset offset,
- QuicByteCount data_length) const {
+ QuicStreamOffset offset, QuicByteCount data_length) const {
QuicByteCount header_acked_length = 0;
QuicIntervalSet<QuicStreamOffset> newly_acked(offset, offset + data_length);
newly_acked.Intersection(unacked_frame_headers_offsets_);
@@ -1061,8 +1068,7 @@ bool QuicSpdyStream::OnHeadersFrameEnd() {
}
void QuicSpdyStream::OnWebTransportStreamFrameType(
- QuicByteCount header_length,
- WebTransportSessionId session_id) {
+ QuicByteCount header_length, WebTransportSessionId session_id) {
QUIC_DVLOG(1) << ENDPOINT << " Received WEBTRANSPORT_STREAM on stream "
<< id() << " for session " << session_id;
sequencer()->MarkConsumed(header_length);
@@ -1114,13 +1120,10 @@ bool QuicSpdyStream::OnUnknownFramePayload(absl::string_view payload) {
return true;
}
-bool QuicSpdyStream::OnUnknownFrameEnd() {
- return true;
-}
+bool QuicSpdyStream::OnUnknownFrameEnd() { return true; }
size_t QuicSpdyStream::WriteHeadersImpl(
- spdy::SpdyHeaderBlock header_block,
- bool fin,
+ spdy::SpdyHeaderBlock header_block, bool fin,
QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) {
if (!VersionUsesHttp3(transport_version())) {
return spdy_session_->WriteHeadersOnHeadersStream(
@@ -1206,6 +1209,13 @@ void QuicSpdyStream::MaybeProcessReceivedWebTransportHeaders() {
protocol = header_value;
}
if (header_name == "datagram-flow-id") {
+ if (spdy_session_->http_datagram_support() !=
+ HttpDatagramSupport::kDraft00) {
+ QUIC_DLOG(ERROR) << ENDPOINT
+ << "Rejecting WebTransport due to unexpected "
+ "Datagram-Flow-Id header";
+ return;
+ }
if (flow_id.has_value() || header_value.empty()) {
return;
}
@@ -1217,23 +1227,33 @@ void QuicSpdyStream::MaybeProcessReceivedWebTransportHeaders() {
}
}
- if (method != "CONNECT" || protocol != "webtransport" ||
- !flow_id.has_value()) {
+ if (method != "CONNECT" || protocol != "webtransport") {
return;
}
- RegisterHttp3DatagramFlowId(*flow_id);
+ if (spdy_session_->http_datagram_support() == HttpDatagramSupport::kDraft00) {
+ if (!flow_id.has_value()) {
+ QUIC_DLOG(ERROR)
+ << ENDPOINT
+ << "Rejecting WebTransport due to missing Datagram-Flow-Id header";
+ return;
+ }
+ RegisterHttp3DatagramFlowId(*flow_id);
+ }
web_transport_ =
std::make_unique<WebTransportHttp3>(spdy_session_, this, id());
+ if (spdy_session_->http_datagram_support() != HttpDatagramSupport::kDraft00) {
+ return;
+ }
// If we're in draft-ietf-masque-h3-datagram-00 mode, pretend we also received
- // a REGISTER_DATAGRAM_NO_CONTEXT capsule with no extensions.
+ // a REGISTER_DATAGRAM_NO_CONTEXT capsule.
// TODO(b/181256914) remove this when we remove support for
// draft-ietf-masque-h3-datagram-00 in favor of later drafts.
- RegisterHttp3DatagramContextId(/*context_id=*/absl::nullopt,
- Http3DatagramContextExtensions(),
- web_transport_.get());
+ RegisterHttp3DatagramContextId(
+ /*context_id=*/absl::nullopt, DatagramFormatType::WEBTRANSPORT,
+ /*format_additional_data=*/absl::string_view(), web_transport_.get());
}
void QuicSpdyStream::MaybeProcessSentWebTransportHeaders(
@@ -1255,14 +1275,12 @@ void QuicSpdyStream::MaybeProcessSentWebTransportHeaders(
return;
}
- QuicDatagramStreamId stream_id = id();
- headers["datagram-flow-id"] = absl::StrCat(stream_id);
+ if (spdy_session_->http_datagram_support() == HttpDatagramSupport::kDraft00) {
+ headers["datagram-flow-id"] = absl::StrCat(id());
+ }
web_transport_ =
std::make_unique<WebTransportHttp3>(spdy_session_, this, id());
- RegisterHttp3DatagramContextId(web_transport_->context_id(),
- Http3DatagramContextExtensions(),
- web_transport_.get());
}
void QuicSpdyStream::OnCanWriteNewData() {
@@ -1318,11 +1336,132 @@ void QuicSpdyStream::ConvertToWebTransportDataStream(
}
QuicSpdyStream::WebTransportDataStream::WebTransportDataStream(
- QuicSpdyStream* stream,
- WebTransportSessionId session_id)
+ QuicSpdyStream* stream, WebTransportSessionId session_id)
: session_id(session_id),
adapter(stream->spdy_session_, stream, stream->sequencer()) {}
+void QuicSpdyStream::HandleReceivedDatagram(
+ absl::optional<QuicDatagramContextId> context_id,
+ absl::string_view payload) {
+ Http3DatagramVisitor* visitor;
+ if (context_id.has_value()) {
+ auto it = datagram_context_visitors_.find(context_id.value());
+ if (it == datagram_context_visitors_.end()) {
+ QUIC_DLOG(ERROR) << ENDPOINT
+ << "Received datagram without any visitor for context "
+ << context_id.value();
+ return;
+ }
+ visitor = it->second;
+ } else {
+ if (datagram_no_context_visitor_ == nullptr) {
+ QUIC_DLOG(ERROR)
+ << ENDPOINT << "Received datagram without any visitor for no context";
+ return;
+ }
+ visitor = datagram_no_context_visitor_;
+ }
+ visitor->OnHttp3Datagram(id(), context_id, payload);
+}
+
+bool QuicSpdyStream::OnCapsule(const Capsule& capsule) {
+ QUIC_DLOG(INFO) << ENDPOINT << "Stream " << id() << " received capsule "
+ << capsule;
+ if (!headers_decompressed_) {
+ QUIC_PEER_BUG(capsule before headers)
+ << ENDPOINT << "Stream " << id() << " received capsule " << capsule
+ << " before headers";
+ return false;
+ }
+ if (web_transport_ != nullptr && web_transport_->close_received()) {
+ QUIC_PEER_BUG(capsule after close)
+ << ENDPOINT << "Stream " << id() << " received capsule " << capsule
+ << " after CLOSE_WEBTRANSPORT_SESSION.";
+ return false;
+ }
+ switch (capsule.capsule_type()) {
+ case CapsuleType::DATAGRAM: {
+ HandleReceivedDatagram(capsule.datagram_capsule().context_id,
+ capsule.datagram_capsule().http_datagram_payload);
+ } break;
+ case CapsuleType::REGISTER_DATAGRAM_CONTEXT:
+ if (datagram_registration_visitor_ == nullptr) {
+ QUIC_DLOG(ERROR) << ENDPOINT << "Received capsule " << capsule
+ << " without any registration visitor";
+ return false;
+ }
+ datagram_registration_visitor_->OnContextReceived(
+ id(), capsule.register_datagram_context_capsule().context_id,
+ capsule.register_datagram_context_capsule().format_type,
+ capsule.register_datagram_context_capsule().format_additional_data);
+ break;
+ case CapsuleType::REGISTER_DATAGRAM_NO_CONTEXT:
+ if (datagram_registration_visitor_ == nullptr) {
+ QUIC_DLOG(ERROR) << ENDPOINT << "Received capsule " << capsule
+ << " without any registration visitor";
+ return false;
+ }
+ datagram_registration_visitor_->OnContextReceived(
+ id(), /*context_id=*/absl::nullopt,
+ capsule.register_datagram_no_context_capsule().format_type,
+ capsule.register_datagram_no_context_capsule()
+ .format_additional_data);
+ break;
+ case CapsuleType::CLOSE_DATAGRAM_CONTEXT:
+ if (datagram_registration_visitor_ == nullptr) {
+ QUIC_DLOG(ERROR) << ENDPOINT << "Received capsule " << capsule
+ << " without any registration visitor";
+ return false;
+ }
+ datagram_registration_visitor_->OnContextClosed(
+ id(), capsule.close_datagram_context_capsule().context_id,
+ capsule.close_datagram_context_capsule().close_code,
+ capsule.close_datagram_context_capsule().close_details);
+ break;
+ case CapsuleType::CLOSE_WEBTRANSPORT_SESSION:
+ if (web_transport_ == nullptr) {
+ QUIC_DLOG(ERROR) << ENDPOINT << "Received capsule " << capsule
+ << " for a non-WebTransport stream.";
+ return false;
+ }
+ web_transport_->OnCloseReceived(
+ capsule.close_web_transport_session_capsule().error_code,
+ capsule.close_web_transport_session_capsule().error_message);
+ break;
+ }
+ return true;
+}
+
+void QuicSpdyStream::OnCapsuleParseFailure(const std::string& error_message) {
+ QUIC_DLOG(ERROR) << ENDPOINT << "Capsule parse failure: " << error_message;
+ Reset(QUIC_BAD_APPLICATION_PAYLOAD);
+}
+
+void QuicSpdyStream::WriteCapsule(const Capsule& capsule, bool fin) {
+ QUIC_DLOG(INFO) << ENDPOINT << "Stream " << id() << " sending capsule "
+ << capsule;
+ QuicBuffer serialized_capsule = SerializeCapsule(
+ capsule,
+ spdy_session_->connection()->helper()->GetStreamSendBufferAllocator());
+ QUICHE_DCHECK_GT(serialized_capsule.size(), 0u);
+ WriteOrBufferBody(serialized_capsule.AsStringView(), /*fin=*/fin);
+}
+
+void QuicSpdyStream::WriteGreaseCapsule() {
+ // GREASE capsulde IDs have a form of 41 * N + 23.
+ QuicRandom* random = spdy_session_->connection()->random_generator();
+ uint64_t type = random->InsecureRandUint64() >> 4;
+ type = (type / 41) * 41 + 23;
+ QUICHE_DCHECK_EQ((type - 23) % 41, 0u);
+
+ constexpr size_t kMaxLength = 64;
+ size_t length = random->InsecureRandUint64() % kMaxLength;
+ std::string bytes(length, '\0');
+ random->InsecureRandBytes(&bytes[0], bytes.size());
+ Capsule capsule = Capsule::Unknown(type, bytes);
+ WriteCapsule(capsule, /*fin=*/false);
+}
+
MessageStatus QuicSpdyStream::SendHttp3Datagram(
absl::optional<QuicDatagramContextId> context_id,
absl::string_view payload) {
@@ -1338,8 +1477,15 @@ void QuicSpdyStream::RegisterHttp3DatagramRegistrationVisitor(
<< ENDPOINT << "Null datagram registration visitor for" << id();
return;
}
+ if (datagram_registration_visitor_ != nullptr) {
+ QUIC_BUG(double datagram registration visitor)
+ << ENDPOINT << "Double datagram registration visitor for" << id();
+ return;
+ }
QUIC_DLOG(INFO) << ENDPOINT << "Registering datagram stream ID " << id();
datagram_registration_visitor_ = visitor;
+ QUICHE_DCHECK(!capsule_parser_);
+ capsule_parser_.reset(new CapsuleParser(this));
}
void QuicSpdyStream::UnregisterHttp3DatagramRegistrationVisitor() {
@@ -1363,24 +1509,27 @@ void QuicSpdyStream::MoveHttp3DatagramRegistration(
void QuicSpdyStream::RegisterHttp3DatagramContextId(
absl::optional<QuicDatagramContextId> context_id,
- const Http3DatagramContextExtensions& /*extensions*/,
+ DatagramFormatType format_type, absl::string_view format_additional_data,
Http3DatagramVisitor* visitor) {
if (visitor == nullptr) {
QUIC_BUG(null datagram visitor)
<< ENDPOINT << "Null datagram visitor for stream ID " << id()
- << " context ID " << (context_id.has_value() ? context_id.value() : 0);
+ << " context ID "
+ << (context_id.has_value() ? absl::StrCat(context_id.value()) : "none");
return;
}
if (datagram_registration_visitor_ == nullptr) {
QUIC_BUG(context registration without registration visitor)
<< ENDPOINT << "Cannot register context ID "
- << (context_id.has_value() ? context_id.value() : 0)
+ << (context_id.has_value() ? absl::StrCat(context_id.value()) : "none")
<< " without registration visitor for stream ID " << id();
return;
}
QUIC_DLOG(INFO) << ENDPOINT << "Registering datagram context ID "
- << (context_id.has_value() ? context_id.value() : 0)
+ << (context_id.has_value() ? absl::StrCat(context_id.value())
+ : "none")
<< " with stream ID " << id();
+
if (context_id.has_value()) {
if (datagram_no_context_visitor_ != nullptr) {
QUIC_BUG(h3 datagram context ID mix1)
@@ -1392,28 +1541,52 @@ void QuicSpdyStream::RegisterHttp3DatagramContextId(
}
auto insertion_result =
datagram_context_visitors_.insert({context_id.value(), visitor});
- QUIC_BUG_IF(h3 datagram double context registration,
- !insertion_result.second)
- << ENDPOINT << "Attempted to doubly register HTTP/3 stream ID " << id()
- << " context ID " << context_id.value();
- return;
- }
- // Registration without a context ID.
- if (!datagram_context_visitors_.empty()) {
- QUIC_BUG(h3 datagram context ID mix2)
- << ENDPOINT
- << "Attempted to mix registrations with and without context IDs "
- "for stream ID "
- << id();
- return;
- }
- if (datagram_no_context_visitor_ != nullptr) {
- QUIC_BUG(h3 datagram double no context registration)
- << ENDPOINT << "Attempted to doubly register HTTP/3 stream ID " << id()
- << " with no context ID";
- return;
+ if (!insertion_result.second) {
+ QUIC_BUG(h3 datagram double context registration)
+ << ENDPOINT << "Attempted to doubly register HTTP/3 stream ID "
+ << id() << " context ID " << context_id.value();
+ return;
+ }
+ capsule_parser_->set_datagram_context_id_present(true);
+ } else {
+ // Registration without a context ID.
+ if (!datagram_context_visitors_.empty()) {
+ QUIC_BUG(h3 datagram context ID mix2)
+ << ENDPOINT
+ << "Attempted to mix registrations with and without context IDs "
+ "for stream ID "
+ << id();
+ return;
+ }
+ if (datagram_no_context_visitor_ != nullptr) {
+ QUIC_BUG(h3 datagram double no context registration)
+ << ENDPOINT << "Attempted to doubly register HTTP/3 stream ID "
+ << id() << " with no context ID";
+ return;
+ }
+ datagram_no_context_visitor_ = visitor;
+ capsule_parser_->set_datagram_context_id_present(false);
+ }
+ if (spdy_session_->http_datagram_support() == HttpDatagramSupport::kDraft04) {
+ const bool is_client = session()->perspective() == Perspective::IS_CLIENT;
+ if (context_id.has_value()) {
+ const bool is_client_context = context_id.value() % 2 == 0;
+ if (is_client == is_client_context) {
+ QuicConnection::ScopedPacketFlusher flusher(
+ spdy_session_->connection());
+ WriteGreaseCapsule();
+ WriteCapsule(Capsule::RegisterDatagramContext(
+ context_id.value(), format_type, format_additional_data));
+ WriteGreaseCapsule();
+ }
+ } else if (is_client) {
+ QuicConnection::ScopedPacketFlusher flusher(spdy_session_->connection());
+ WriteGreaseCapsule();
+ WriteCapsule(Capsule::RegisterDatagramNoContext(format_type,
+ format_additional_data));
+ WriteGreaseCapsule();
+ }
}
- datagram_no_context_visitor_ = visitor;
}
void QuicSpdyStream::UnregisterHttp3DatagramContextId(
@@ -1421,26 +1594,31 @@ void QuicSpdyStream::UnregisterHttp3DatagramContextId(
if (datagram_registration_visitor_ == nullptr) {
QUIC_BUG(context unregistration without registration visitor)
<< ENDPOINT << "Cannot unregister context ID "
- << (context_id.has_value() ? context_id.value() : 0)
+ << (context_id.has_value() ? absl::StrCat(context_id.value()) : "none")
<< " without registration visitor for stream ID " << id();
return;
}
QUIC_DLOG(INFO) << ENDPOINT << "Unregistering datagram context ID "
- << (context_id.has_value() ? context_id.value() : 0)
+ << (context_id.has_value() ? absl::StrCat(context_id.value())
+ : "none")
<< " with stream ID " << id();
if (context_id.has_value()) {
size_t num_erased = datagram_context_visitors_.erase(context_id.value());
QUIC_BUG_IF(h3 datagram unregister unknown context, num_erased != 1)
<< "Attempted to unregister unknown HTTP/3 context ID "
<< context_id.value() << " on stream ID " << id();
- return;
+ } else {
+ // Unregistration without a context ID.
+ QUIC_BUG_IF(h3 datagram unknown context unregistration,
+ datagram_no_context_visitor_ == nullptr)
+ << "Attempted to unregister unknown no context on HTTP/3 stream ID "
+ << id();
+ datagram_no_context_visitor_ = nullptr;
+ }
+ if (spdy_session_->http_datagram_support() == HttpDatagramSupport::kDraft04 &&
+ context_id.has_value()) {
+ WriteCapsule(Capsule::CloseDatagramContext(context_id.value()));
}
- // Unregistration without a context ID.
- QUIC_BUG_IF(h3 datagram unknown context unregistration,
- datagram_no_context_visitor_ == nullptr)
- << "Attempted to unregister unknown no context on HTTP/3 stream ID "
- << id();
- datagram_no_context_visitor_ = nullptr;
}
void QuicSpdyStream::MoveHttp3DatagramContextIdRegistration(
@@ -1449,12 +1627,13 @@ void QuicSpdyStream::MoveHttp3DatagramContextIdRegistration(
if (datagram_registration_visitor_ == nullptr) {
QUIC_BUG(context move without registration visitor)
<< ENDPOINT << "Cannot move context ID "
- << (context_id.has_value() ? context_id.value() : 0)
+ << (context_id.has_value() ? absl::StrCat(context_id.value()) : "none")
<< " without registration visitor for stream ID " << id();
return;
}
QUIC_DLOG(INFO) << ENDPOINT << "Moving datagram context ID "
- << (context_id.has_value() ? context_id.value() : 0)
+ << (context_id.has_value() ? absl::StrCat(context_id.value())
+ : "none")
<< " with stream ID " << id();
if (context_id.has_value()) {
QUIC_BUG_IF(h3 datagram move unknown context,
@@ -1485,7 +1664,6 @@ QuicDatagramContextId QuicSpdyStream::GetNextDatagramContextId() {
void QuicSpdyStream::OnDatagramReceived(QuicDataReader* reader) {
absl::optional<QuicDatagramContextId> context_id;
const bool context_id_present = !datagram_context_visitors_.empty();
- Http3DatagramVisitor* visitor;
if (context_id_present) {
QuicDatagramContextId parsed_context_id;
if (!reader->ReadVarInt62(&parsed_context_id)) {
@@ -1495,28 +1673,58 @@ void QuicSpdyStream::OnDatagramReceived(QuicDataReader* reader) {
return;
}
context_id = parsed_context_id;
- auto it = datagram_context_visitors_.find(parsed_context_id);
- if (it == datagram_context_visitors_.end()) {
- // TODO(b/181256914) buffer unknown HTTP/3 datagrams for a short
- // period of time in case they were reordered.
- QUIC_DLOG(ERROR) << "Received unknown HTTP/3 datagram context ID "
- << parsed_context_id << " on stream ID " << id();
- return;
- }
- visitor = it->second;
- } else {
- if (datagram_no_context_visitor_ == nullptr) {
- // TODO(b/181256914) buffer unknown HTTP/3 datagrams for a short
- // period of time in case they were reordered.
- QUIC_DLOG(ERROR)
- << "Received HTTP/3 datagram without any registrations on stream ID "
- << id();
- return;
- }
- visitor = datagram_no_context_visitor_;
}
absl::string_view payload = reader->ReadRemainingPayload();
- visitor->OnHttp3Datagram(id(), context_id, payload);
+ HandleReceivedDatagram(context_id, payload);
+}
+
+QuicByteCount QuicSpdyStream::GetMaxDatagramSize(
+ absl::optional<QuicDatagramContextId> context_id) const {
+ QuicByteCount prefix_size = 0;
+ switch (spdy_session_->http_datagram_support()) {
+ case HttpDatagramSupport::kDraft00:
+ if (!datagram_flow_id_.has_value()) {
+ QUIC_BUG(GetMaxDatagramSize with no flow ID)
+ << "GetMaxDatagramSize() called when no flow ID available";
+ break;
+ }
+ prefix_size = QuicDataWriter::GetVarInt62Len(*datagram_flow_id_);
+ break;
+ case HttpDatagramSupport::kDraft04:
+ prefix_size =
+ QuicDataWriter::GetVarInt62Len(id() / kHttpDatagramStreamIdDivisor);
+ break;
+ case HttpDatagramSupport::kNone:
+ case HttpDatagramSupport::kDraft00And04:
+ QUIC_BUG(GetMaxDatagramSize called with no datagram support)
+ << "GetMaxDatagramSize() called when no HTTP/3 datagram support has "
+ "been negotiated. Support value: "
+ << spdy_session_->http_datagram_support();
+ break;
+ }
+ // If the logic above fails, use the largest possible value as the safe one.
+ if (prefix_size == 0) {
+ prefix_size = 8;
+ }
+
+ if (context_id.has_value()) {
+ QUIC_BUG_IF(
+ context_id with draft00 in GetMaxDatagramSize,
+ spdy_session_->http_datagram_support() == HttpDatagramSupport::kDraft00)
+ << "GetMaxDatagramSize() called with a context ID specified, but "
+ "draft00 does not support contexts.";
+ prefix_size += QuicDataWriter::GetVarInt62Len(*context_id);
+ }
+
+ QuicByteCount max_datagram_size =
+ session()->GetGuaranteedLargestMessagePayload();
+ if (max_datagram_size < prefix_size) {
+ QUIC_BUG(max_datagram_size smaller than prefix_size)
+ << "GetGuaranteedLargestMessagePayload() returned a datagram size that "
+ "is not sufficient to fit stream and/or context ID into it.";
+ return 0;
+ }
+ return max_datagram_size - prefix_size;
}
void QuicSpdyStream::RegisterHttp3DatagramFlowId(QuicDatagramStreamId flow_id) {
@@ -1524,5 +1732,33 @@ void QuicSpdyStream::RegisterHttp3DatagramFlowId(QuicDatagramStreamId flow_id) {
spdy_session_->RegisterHttp3DatagramFlowId(datagram_flow_id_.value(), id());
}
+void QuicSpdyStream::HandleBodyAvailable() {
+ if (!capsule_parser_) {
+ OnBodyAvailable();
+ return;
+ }
+ while (body_manager_.HasBytesToRead()) {
+ iovec iov;
+ int num_iov = GetReadableRegions(&iov, /*iov_len=*/1);
+ if (num_iov == 0) {
+ break;
+ }
+ if (!capsule_parser_->IngestCapsuleFragment(absl::string_view(
+ reinterpret_cast<const char*>(iov.iov_base), iov.iov_len))) {
+ break;
+ }
+ MarkConsumed(iov.iov_len);
+ }
+ // If we received a FIN, make sure that there isn't a partial capsule buffered
+ // in the capsule parser.
+ if (sequencer()->IsClosed()) {
+ capsule_parser_->ErrorIfThereIsRemainingBufferedData();
+ if (web_transport_ != nullptr) {
+ web_transport_->OnConnectStreamFinReceived();
+ }
+ OnFinRead();
+ }
+}
+
#undef ENDPOINT // undef for jumbo builds
} // namespace quic
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 4df1196abeb..7ea2d1ddd7a 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
@@ -19,17 +19,19 @@
#include "absl/base/attributes.h"
#include "absl/strings/string_view.h"
#include "absl/types/span.h"
+#include "quic/core/http/capsule.h"
#include "quic/core/http/http_decoder.h"
#include "quic/core/http/http_encoder.h"
#include "quic/core/http/quic_header_list.h"
#include "quic/core/http/quic_spdy_stream_body_manager.h"
+#include "quic/core/http/web_transport_stream_adapter.h"
#include "quic/core/qpack/qpack_decoded_headers_accumulator.h"
+#include "quic/core/quic_error_codes.h"
#include "quic/core/quic_packets.h"
#include "quic/core/quic_stream.h"
#include "quic/core/quic_stream_sequencer.h"
#include "quic/core/quic_types.h"
#include "quic/core/web_transport_interface.h"
-#include "quic/core/web_transport_stream_adapter.h"
#include "quic/platform/api/quic_export.h"
#include "quic/platform/api/quic_flags.h"
#include "quic/platform/api/quic_socket_address.h"
@@ -46,11 +48,10 @@ class QuicStreamPeer;
class QuicSpdySession;
class WebTransportHttp3;
-class QUIC_EXPORT_PRIVATE Http3DatagramContextExtensions {};
-
// A QUIC stream that can send and receive HTTP2 (SPDY) headers.
class QUIC_EXPORT_PRIVATE QuicSpdyStream
: public QuicStream,
+ public CapsuleParser::Visitor,
public QpackDecodedHeadersAccumulator::Visitor {
public:
// Visitor receives callbacks from the stream.
@@ -71,12 +72,9 @@ class QUIC_EXPORT_PRIVATE QuicSpdyStream
virtual ~Visitor() {}
};
- QuicSpdyStream(QuicStreamId id,
- QuicSpdySession* spdy_session,
- StreamType type);
- QuicSpdyStream(PendingStream* pending,
- QuicSpdySession* spdy_session,
+ QuicSpdyStream(QuicStreamId id, QuicSpdySession* spdy_session,
StreamType type);
+ QuicSpdyStream(PendingStream* pending, QuicSpdySession* spdy_session);
QuicSpdyStream(const QuicSpdyStream&) = delete;
QuicSpdyStream& operator=(const QuicSpdyStream&) = delete;
~QuicSpdyStream() override;
@@ -95,14 +93,12 @@ class QUIC_EXPORT_PRIVATE QuicSpdyStream
// Called by the session when decompressed headers have been completely
// delivered to this stream. If |fin| is true, then this stream
// should be closed; no more data will be sent by the peer.
- virtual void OnStreamHeaderList(bool fin,
- size_t frame_len,
+ virtual void OnStreamHeaderList(bool fin, size_t frame_len,
const QuicHeaderList& header_list);
// Called by the session when decompressed push promise headers have
// been completely delivered to this stream.
- virtual void OnPromiseHeaderList(QuicStreamId promised_id,
- size_t frame_len,
+ virtual void OnPromiseHeaderList(QuicStreamId promised_id, size_t frame_len,
const QuicHeaderList& header_list);
// Called by the session when a PRIORITY frame has been been received for this
@@ -112,8 +108,8 @@ class QUIC_EXPORT_PRIVATE QuicSpdyStream
// Override the base class to not discard response when receiving
// QUIC_STREAM_NO_ERROR.
void OnStreamReset(const QuicRstStreamFrame& frame) override;
-
- void Reset(QuicRstStreamErrorCode error) override;
+ void ResetWithError(QuicResetStreamError error) override;
+ bool OnStopSending(QuicResetStreamError error) override;
// Called by the sequencer when new data is available. Decodes the data and
// calls OnBodyAvailable() to pass to the upper layer.
@@ -127,8 +123,7 @@ class QUIC_EXPORT_PRIVATE QuicSpdyStream
// number of bytes sent, including data sent on the encoder stream when using
// QPACK.
virtual size_t WriteHeaders(
- spdy::SpdyHeaderBlock header_block,
- bool fin,
+ spdy::SpdyHeaderBlock header_block, bool fin,
QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener);
// Sends |data| to the peer, or buffers if it can't be sent immediately.
@@ -143,10 +138,8 @@ class QUIC_EXPORT_PRIVATE QuicSpdyStream
QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener);
// Override to report newly acked bytes via ack_listener_.
- bool OnStreamFrameAcked(QuicStreamOffset offset,
- QuicByteCount data_length,
- bool fin_acked,
- QuicTime::Delta ack_delay_time,
+ bool OnStreamFrameAcked(QuicStreamOffset offset, QuicByteCount data_length,
+ bool fin_acked, QuicTime::Delta ack_delay_time,
QuicTime receive_timestamp,
QuicByteCount* newly_acked_length) override;
@@ -161,7 +154,6 @@ class QUIC_EXPORT_PRIVATE QuicSpdyStream
// Does the same thing as WriteOrBufferBody except this method takes
// memslicespan as the data input. Right now it only calls WriteMemSlices.
- QuicConsumedData WriteBodySlices(QuicMemSliceSpan slices, bool fin);
QuicConsumedData WriteBodySlices(absl::Span<QuicMemSlice> slices, bool fin);
// Marks the trailers as consumed. This applies to the case where this object
@@ -220,7 +212,8 @@ class QUIC_EXPORT_PRIVATE QuicSpdyStream
// QpackDecodedHeadersAccumulator::Visitor implementation.
void OnHeadersDecoded(QuicHeaderList headers,
bool header_list_size_limit_exceeded) override;
- void OnHeaderDecodingError(absl::string_view error_message) override;
+ void OnHeaderDecodingError(QuicErrorCode error_code,
+ absl::string_view error_message) override;
QuicSpdySession* spdy_session() const { return spdy_session_; }
@@ -253,6 +246,10 @@ class QUIC_EXPORT_PRIVATE QuicSpdyStream
// rejected due to buffer being full. |write_size| must be non-zero.
bool CanWriteNewBodyData(QuicByteCount write_size) const;
+ // From CapsuleParser::Visitor.
+ bool OnCapsule(const Capsule& capsule) override;
+ void OnCapsuleParseFailure(const std::string& error_message) override;
+
// Sends an HTTP/3 datagram. The stream and context IDs are not part of
// |payload|.
MessageStatus SendHttp3Datagram(
@@ -282,7 +279,8 @@ class QUIC_EXPORT_PRIVATE QuicSpdyStream
virtual void OnContextReceived(
QuicStreamId stream_id,
absl::optional<QuicDatagramContextId> context_id,
- const Http3DatagramContextExtensions& extensions) = 0;
+ DatagramFormatType format_type,
+ absl::string_view format_additional_data) = 0;
// Called when a CLOSE_DATAGRAM_CONTEXT capsule is received. Note that this
// contains the stream ID even if flow IDs from
@@ -290,7 +288,7 @@ class QUIC_EXPORT_PRIVATE QuicSpdyStream
virtual void OnContextClosed(
QuicStreamId stream_id,
absl::optional<QuicDatagramContextId> context_id,
- const Http3DatagramContextExtensions& extensions) = 0;
+ ContextCloseCode close_code, absl::string_view close_details) = 0;
};
// Registers |visitor| to receive HTTP/3 datagram context registrations. This
@@ -316,7 +314,7 @@ class QUIC_EXPORT_PRIVATE QuicSpdyStream
// present, or always absent.
void RegisterHttp3DatagramContextId(
absl::optional<QuicDatagramContextId> context_id,
- const Http3DatagramContextExtensions& extensions,
+ DatagramFormatType format_type, absl::string_view format_additional_data,
Http3DatagramVisitor* visitor);
// Unregisters an HTTP/3 datagram context ID. Must be called on a previously
@@ -341,20 +339,25 @@ class QUIC_EXPORT_PRIVATE QuicSpdyStream
void RegisterHttp3DatagramFlowId(QuicDatagramStreamId flow_id);
+ QuicByteCount GetMaxDatagramSize(
+ absl::optional<QuicDatagramContextId> context_id) const;
+
+ // Writes |capsule| onto the DATA stream.
+ void WriteCapsule(const Capsule& capsule, bool fin = false);
+
+ void WriteGreaseCapsule();
+
protected:
// Called when the received headers are too large. By default this will
// reset the stream.
virtual void OnHeadersTooLarge();
- virtual void OnInitialHeadersComplete(bool fin,
- size_t frame_len,
+ virtual void OnInitialHeadersComplete(bool fin, size_t frame_len,
const QuicHeaderList& header_list);
- virtual void OnTrailingHeadersComplete(bool fin,
- size_t frame_len,
+ virtual void OnTrailingHeadersComplete(bool fin, size_t frame_len,
const QuicHeaderList& header_list);
virtual size_t WriteHeadersImpl(
- spdy::SpdyHeaderBlock header_block,
- bool fin,
+ spdy::SpdyHeaderBlock header_block, bool fin,
QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener);
Visitor* visitor() { return visitor_; }
@@ -366,6 +369,8 @@ class QUIC_EXPORT_PRIVATE QuicSpdyStream
ack_listener_ = std::move(ack_listener);
}
+ void OnWriteSideInDataRecvdState() override;
+
private:
friend class test::QuicSpdyStreamPeer;
friend class test::QuicStreamPeer;
@@ -391,8 +396,7 @@ class QUIC_EXPORT_PRIVATE QuicSpdyStream
bool OnHeadersFrameEnd();
void OnWebTransportStreamFrameType(QuicByteCount header_length,
WebTransportSessionId session_id);
- bool OnUnknownFrameStart(uint64_t frame_type,
- QuicByteCount header_length,
+ bool OnUnknownFrameStart(uint64_t frame_type, QuicByteCount header_length,
QuicByteCount payload_length);
bool OnUnknownFramePayload(absl::string_view payload);
bool OnUnknownFrameEnd();
@@ -410,6 +414,14 @@ class QUIC_EXPORT_PRIVATE QuicSpdyStream
ABSL_MUST_USE_RESULT bool WriteDataFrameHeader(QuicByteCount data_length,
bool force_write);
+ // Simply calls OnBodyAvailable() unless capsules are in use, in which case
+ // pass the capsule fragments to the capsule manager.
+ void HandleBodyAvailable();
+
+ // Called when a datagram frame or capsule is received.
+ void HandleReceivedDatagram(absl::optional<QuicDatagramContextId> context_id,
+ absl::string_view payload);
+
QuicSpdySession* spdy_session_;
bool on_body_available_called_because_sequencer_is_closed_;
@@ -450,6 +462,8 @@ class QUIC_EXPORT_PRIVATE QuicSpdyStream
// the sequencer each time new stream data is processed.
QuicSpdyStreamBodyManager body_manager_;
+ std::unique_ptr<CapsuleParser> capsule_parser_;
+
// Sequencer offset keeping track of how much data HttpDecoder has processed.
// Initial value is zero for fresh streams, or sequencer()->NumBytesConsumed()
// at time of construction if a PendingStream is converted to account for the
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 c19dc3c8431..48b654b9876 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
@@ -16,6 +16,7 @@
#include "absl/strings/string_view.h"
#include "quic/core/crypto/null_encrypter.h"
#include "quic/core/http/http_encoder.h"
+#include "quic/core/http/quic_spdy_session.h"
#include "quic/core/http/spdy_utils.h"
#include "quic/core/http/web_transport_http3.h"
#include "quic/core/quic_connection.h"
@@ -167,6 +168,15 @@ class TestCryptoStream : public QuicCryptoStream, public QuicCryptoHandshaker {
MOCK_METHOD(bool, HasPendingRetransmission, (), (const, override));
+ bool ExportKeyingMaterial(absl::string_view /*label*/,
+ absl::string_view /*context*/,
+ size_t /*result_len*/,
+ std::string* /*result*/) override {
+ return false;
+ }
+
+ SSL* GetSsl() const override { return nullptr; }
+
private:
using QuicCryptoStream::session;
@@ -177,8 +187,7 @@ class TestCryptoStream : public QuicCryptoStream, public QuicCryptoHandshaker {
class TestStream : public QuicSpdyStream {
public:
- TestStream(QuicStreamId id,
- QuicSpdySession* session,
+ TestStream(QuicStreamId id, QuicSpdySession* session,
bool should_process_data)
: QuicSpdyStream(id, session, BIDIRECTIONAL),
should_process_data_(should_process_data),
@@ -203,8 +212,7 @@ class TestStream : public QuicSpdyStream {
MOCK_METHOD(void, WriteHeadersMock, (bool fin), ());
- size_t WriteHeadersImpl(spdy::SpdyHeaderBlock header_block,
- bool fin,
+ size_t WriteHeadersImpl(spdy::SpdyHeaderBlock header_block, bool fin,
QuicReferenceCountedPointer<QuicAckListenerInterface>
/*ack_listener*/) override {
saved_headers_ = std::move(header_block);
@@ -226,8 +234,7 @@ class TestStream : public QuicSpdyStream {
return QuicStream::sequencer();
}
- void OnStreamHeaderList(bool fin,
- size_t frame_len,
+ 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);
@@ -259,16 +266,16 @@ class TestSession : public MockQuicSpdySession {
bool ShouldNegotiateWebTransport() override { return enable_webtransport_; }
void EnableWebTransport() { enable_webtransport_ = true; }
- bool ShouldNegotiateHttp3Datagram() override {
- return should_negotiate_h3_datagram_;
+ HttpDatagramSupport LocalHttpDatagramSupport() override {
+ return local_http_datagram_support_;
}
- void set_should_negotiate_h3_datagram(bool value) {
- should_negotiate_h3_datagram_ = value;
+ void set_local_http_datagram_support(HttpDatagramSupport value) {
+ local_http_datagram_support_ = value;
}
private:
bool enable_webtransport_ = false;
- bool should_negotiate_h3_datagram_ = false;
+ HttpDatagramSupport local_http_datagram_support_ = HttpDatagramSupport::kNone;
StrictMock<TestCryptoStream> crypto_stream_;
};
@@ -280,8 +287,7 @@ class TestMockUpdateStreamSession : public MockQuicSpdySession {
spdy::SpdyStreamPrecedence(QuicStream::kDefaultPriority)) {}
void UpdateStreamPriority(
- QuicStreamId id,
- const spdy::SpdyStreamPrecedence& precedence) override {
+ QuicStreamId id, const spdy::SpdyStreamPrecedence& precedence) override {
EXPECT_EQ(id, expected_stream_->id());
EXPECT_EQ(expected_precedence_, precedence);
EXPECT_EQ(expected_precedence_, expected_stream_->precedence());
@@ -491,8 +497,7 @@ class QuicSpdyStreamTest : public QuicTestWithParam<ParsedQuicVersion> {
SpdyHeaderBlock headers_;
};
-INSTANTIATE_TEST_SUITE_P(Tests,
- QuicSpdyStreamTest,
+INSTANTIATE_TEST_SUITE_P(Tests, QuicSpdyStreamTest,
::testing::ValuesIn(AllSupportedVersions()),
::testing::PrintToStringParamName());
@@ -515,8 +520,11 @@ TEST_P(QuicSpdyStreamTest, ProcessTooLargeHeaderList) {
stream_->OnStreamHeadersPriority(
spdy::SpdyStreamPrecedence(kV3HighestPriority));
- EXPECT_CALL(*session_, MaybeSendRstStreamFrame(stream_->id(),
- QUIC_HEADERS_TOO_LARGE, 0));
+ EXPECT_CALL(
+ *session_,
+ MaybeSendRstStreamFrame(
+ stream_->id(),
+ QuicResetStreamError::FromInternal(QUIC_HEADERS_TOO_LARGE), 0));
stream_->OnStreamHeaderList(false, 1 << 20, headers);
EXPECT_THAT(stream_->stream_error(), IsStreamError(QUIC_HEADERS_TOO_LARGE));
@@ -531,10 +539,14 @@ TEST_P(QuicSpdyStreamTest, ProcessTooLargeHeaderList) {
QuicStreamFrame frame(stream_->id(), false, 0, headers);
- EXPECT_CALL(*session_,
- MaybeSendStopSendingFrame(stream_->id(), QUIC_HEADERS_TOO_LARGE));
- EXPECT_CALL(*session_, MaybeSendRstStreamFrame(stream_->id(),
- QUIC_HEADERS_TOO_LARGE, 0));
+ EXPECT_CALL(*session_, MaybeSendStopSendingFrame(
+ stream_->id(), QuicResetStreamError::FromInternal(
+ QUIC_HEADERS_TOO_LARGE)));
+ EXPECT_CALL(
+ *session_,
+ MaybeSendRstStreamFrame(
+ stream_->id(),
+ QuicResetStreamError::FromInternal(QUIC_HEADERS_TOO_LARGE), 0));
auto qpack_decoder_stream =
QuicSpdySessionPeer::GetQpackDecoderSendStream(session_.get());
@@ -2467,10 +2479,14 @@ TEST_P(QuicSpdyStreamTest, HeaderDecodingUnblockedAfterStreamClosed) {
/* offset = */ 1, _, _, _));
// Reset stream by this endpoint, for example, due to stream cancellation.
- EXPECT_CALL(*session_,
- MaybeSendStopSendingFrame(stream_->id(), QUIC_STREAM_CANCELLED));
- EXPECT_CALL(*session_,
- MaybeSendRstStreamFrame(stream_->id(), QUIC_STREAM_CANCELLED, _));
+ EXPECT_CALL(*session_, MaybeSendStopSendingFrame(
+ stream_->id(), QuicResetStreamError::FromInternal(
+ QUIC_STREAM_CANCELLED)));
+ EXPECT_CALL(
+ *session_,
+ MaybeSendRstStreamFrame(
+ stream_->id(),
+ QuicResetStreamError::FromInternal(QUIC_STREAM_CANCELLED), _));
stream_->Reset(QUIC_STREAM_CANCELLED);
// Deliver dynamic table entry to decoder.
@@ -2575,8 +2591,7 @@ class QuicSpdyStreamIncrementalConsumptionTest : public QuicSpdyStreamTest {
QuicStreamOffset consumed_bytes_;
};
-INSTANTIATE_TEST_SUITE_P(Tests,
- QuicSpdyStreamIncrementalConsumptionTest,
+INSTANTIATE_TEST_SUITE_P(Tests, QuicSpdyStreamIncrementalConsumptionTest,
::testing::ValuesIn(AllSupportedVersions()),
::testing::PrintToStringParamName());
@@ -2914,10 +2929,14 @@ TEST_P(QuicSpdyStreamTest, StreamCancellationWhenStreamReset) {
EXPECT_CALL(*session_,
WritevData(qpack_decoder_stream->id(), /* write_length = */ 1,
/* offset = */ 1, _, _, _));
- EXPECT_CALL(*session_,
- MaybeSendStopSendingFrame(stream_->id(), QUIC_STREAM_CANCELLED));
- EXPECT_CALL(*session_,
- MaybeSendRstStreamFrame(stream_->id(), QUIC_STREAM_CANCELLED, _));
+ EXPECT_CALL(*session_, MaybeSendStopSendingFrame(
+ stream_->id(), QuicResetStreamError::FromInternal(
+ QUIC_STREAM_CANCELLED)));
+ EXPECT_CALL(
+ *session_,
+ MaybeSendRstStreamFrame(
+ stream_->id(),
+ QuicResetStreamError::FromInternal(QUIC_STREAM_CANCELLED), _));
stream_->Reset(QUIC_STREAM_CANCELLED);
}
@@ -3009,23 +3028,28 @@ TEST_P(QuicSpdyStreamTest, TwoResetStreamFrames) {
EXPECT_TRUE(stream_->read_side_closed());
EXPECT_FALSE(stream_->write_side_closed());
} else {
- EXPECT_CALL(*session_, MaybeSendRstStreamFrame(
- stream_->id(), QUIC_RST_ACKNOWLEDGEMENT, _));
+ EXPECT_CALL(
+ *session_,
+ MaybeSendRstStreamFrame(
+ stream_->id(),
+ QuicResetStreamError::FromInternal(QUIC_RST_ACKNOWLEDGEMENT), _));
EXPECT_QUIC_BUG(
stream_->OnStreamReset(rst_frame2),
"The stream should've already sent RST in response to STOP_SENDING");
}
}
-TEST_P(QuicSpdyStreamTest, ProcessOutgoingWebTransportHeaders) {
+TEST_P(QuicSpdyStreamTest, ProcessOutgoingWebTransportHeadersDatagramDraft00) {
if (!UsesHttp3()) {
return;
}
InitializeWithPerspective(kShouldProcessData, Perspective::IS_CLIENT);
- session_->set_should_negotiate_h3_datagram(true);
+ session_->set_local_http_datagram_support(HttpDatagramSupport::kDraft00And04);
session_->EnableWebTransport();
- QuicSpdySessionPeer::EnableWebTransport(*session_);
+ QuicSpdySessionPeer::EnableWebTransport(session_.get());
+ QuicSpdySessionPeer::SetHttpDatagramSupport(session_.get(),
+ HttpDatagramSupport::kDraft00);
EXPECT_CALL(*stream_, WriteHeadersMock(false));
EXPECT_CALL(*session_, WritevData(stream_->id(), _, _, _, _, _))
@@ -3040,15 +3064,68 @@ TEST_P(QuicSpdyStreamTest, ProcessOutgoingWebTransportHeaders) {
EXPECT_EQ(stream_->id(), stream_->web_transport()->id());
}
-TEST_P(QuicSpdyStreamTest, ProcessIncomingWebTransportHeaders) {
+TEST_P(QuicSpdyStreamTest, ProcessOutgoingWebTransportHeadersDatagramDraft04) {
+ if (!UsesHttp3()) {
+ return;
+ }
+
+ InitializeWithPerspective(kShouldProcessData, Perspective::IS_CLIENT);
+ session_->set_local_http_datagram_support(HttpDatagramSupport::kDraft00And04);
+ session_->EnableWebTransport();
+ QuicSpdySessionPeer::EnableWebTransport(session_.get());
+ QuicSpdySessionPeer::SetHttpDatagramSupport(session_.get(),
+ HttpDatagramSupport::kDraft04);
+
+ EXPECT_CALL(*stream_, WriteHeadersMock(false));
+ EXPECT_CALL(*session_, WritevData(stream_->id(), _, _, _, _, _))
+ .Times(AnyNumber());
+
+ spdy::SpdyHeaderBlock headers;
+ headers[":method"] = "CONNECT";
+ headers[":protocol"] = "webtransport";
+ stream_->WriteHeaders(std::move(headers), /*fin=*/false, nullptr);
+ ASSERT_TRUE(stream_->web_transport() != nullptr);
+ EXPECT_EQ(stream_->id(), stream_->web_transport()->id());
+}
+
+TEST_P(QuicSpdyStreamTest, ProcessIncomingWebTransportHeadersDatagramDraft04) {
+ if (!UsesHttp3()) {
+ return;
+ }
+
+ Initialize(kShouldProcessData);
+ session_->set_local_http_datagram_support(HttpDatagramSupport::kDraft00And04);
+ session_->EnableWebTransport();
+ QuicSpdySessionPeer::EnableWebTransport(session_.get());
+ QuicSpdySessionPeer::SetHttpDatagramSupport(session_.get(),
+ HttpDatagramSupport::kDraft04);
+
+ headers_[":method"] = "CONNECT";
+ headers_[":protocol"] = "webtransport";
+
+ stream_->OnStreamHeadersPriority(
+ spdy::SpdyStreamPrecedence(kV3HighestPriority));
+ ProcessHeaders(false, headers_);
+ stream_->OnCapsule(
+ Capsule::RegisterDatagramNoContext(DatagramFormatType::WEBTRANSPORT));
+ EXPECT_EQ("", stream_->data());
+ EXPECT_FALSE(stream_->header_list().empty());
+ EXPECT_FALSE(stream_->IsDoneReading());
+ ASSERT_TRUE(stream_->web_transport() != nullptr);
+ EXPECT_EQ(stream_->id(), stream_->web_transport()->id());
+}
+
+TEST_P(QuicSpdyStreamTest, ProcessIncomingWebTransportHeadersDatagramDraft00) {
if (!UsesHttp3()) {
return;
}
Initialize(kShouldProcessData);
- session_->set_should_negotiate_h3_datagram(true);
+ session_->set_local_http_datagram_support(HttpDatagramSupport::kDraft00And04);
session_->EnableWebTransport();
- QuicSpdySessionPeer::EnableWebTransport(*session_);
+ QuicSpdySessionPeer::EnableWebTransport(session_.get());
+ QuicSpdySessionPeer::SetHttpDatagramSupport(session_.get(),
+ HttpDatagramSupport::kDraft00);
headers_[":method"] = "CONNECT";
headers_[":protocol"] = "webtransport";
@@ -3073,9 +3150,11 @@ TEST_P(QuicSpdyStreamTest,
// draft-ietf-masque-h3-datagram-00 in favor of later drafts.
Initialize(kShouldProcessData);
- session_->set_should_negotiate_h3_datagram(true);
+ session_->set_local_http_datagram_support(HttpDatagramSupport::kDraft00And04);
session_->EnableWebTransport();
- QuicSpdySessionPeer::EnableWebTransport(*session_);
+ QuicSpdySessionPeer::EnableWebTransport(session_.get());
+ QuicSpdySessionPeer::SetHttpDatagramSupport(session_.get(),
+ HttpDatagramSupport::kDraft00);
headers_[":method"] = "CONNECT";
headers_[":protocol"] = "webtransport";
@@ -3119,19 +3198,20 @@ TEST_P(QuicSpdyStreamTest, GetNextDatagramContextIdServer) {
stream_->UnregisterHttp3DatagramRegistrationVisitor();
}
-TEST_P(QuicSpdyStreamTest, H3DatagramRegistrationWithoutContext) {
+TEST_P(QuicSpdyStreamTest, HttpDatagramRegistrationWithoutContextDraft00) {
if (!UsesHttp3()) {
return;
}
- Initialize(kShouldProcessData);
- session_->set_should_negotiate_h3_datagram(true);
- QuicSpdySessionPeer::SetH3DatagramSupported(session_.get(), true);
+ InitializeWithPerspective(kShouldProcessData, Perspective::IS_CLIENT);
+ session_->set_local_http_datagram_support(HttpDatagramSupport::kDraft00And04);
+ QuicSpdySessionPeer::SetHttpDatagramSupport(session_.get(),
+ HttpDatagramSupport::kDraft00);
session_->RegisterHttp3DatagramFlowId(stream_->id(), stream_->id());
::testing::NiceMock<MockHttp3DatagramRegistrationVisitor>
h3_datagram_registration_visitor;
SavingHttp3DatagramVisitor h3_datagram_visitor;
absl::optional<QuicDatagramContextId> context_id;
- Http3DatagramContextExtensions extensions;
+ absl::string_view format_additional_data;
ASSERT_EQ(QuicDataWriter::GetVarInt62Len(stream_->id()), 1);
std::array<char, 256> datagram;
datagram[0] = stream_->id();
@@ -3140,8 +3220,9 @@ TEST_P(QuicSpdyStreamTest, H3DatagramRegistrationWithoutContext) {
}
stream_->RegisterHttp3DatagramRegistrationVisitor(
&h3_datagram_registration_visitor);
- stream_->RegisterHttp3DatagramContextId(context_id, extensions,
- &h3_datagram_visitor);
+ stream_->RegisterHttp3DatagramContextId(
+ context_id, DatagramFormatType::UDP_PAYLOAD, format_additional_data,
+ &h3_datagram_visitor);
session_->OnMessageReceived(
absl::string_view(datagram.data(), datagram.size()));
EXPECT_THAT(h3_datagram_visitor.received_h3_datagrams(),
@@ -3168,23 +3249,96 @@ TEST_P(QuicSpdyStreamTest, H3DatagramRegistrationWithoutContext) {
session_->UnregisterHttp3DatagramFlowId(stream_->id());
}
-TEST_P(QuicSpdyStreamTest, H3DatagramRegistrationWithContext) {
+TEST_P(QuicSpdyStreamTest, H3DatagramRegistrationWithoutContextDraft04) {
if (!UsesHttp3()) {
return;
}
- Initialize(kShouldProcessData);
- session_->set_should_negotiate_h3_datagram(true);
- QuicSpdySessionPeer::SetH3DatagramSupported(session_.get(), true);
- session_->RegisterHttp3DatagramFlowId(stream_->id(), stream_->id());
+ InitializeWithPerspective(kShouldProcessData, Perspective::IS_CLIENT);
+ session_->set_local_http_datagram_support(HttpDatagramSupport::kDraft04);
+ QuicSpdySessionPeer::SetHttpDatagramSupport(session_.get(),
+ HttpDatagramSupport::kDraft04);
+ ::testing::NiceMock<MockHttp3DatagramRegistrationVisitor>
+ h3_datagram_registration_visitor;
+ SavingHttp3DatagramVisitor h3_datagram_visitor;
+ absl::optional<QuicDatagramContextId> context_id;
+ absl::string_view format_additional_data;
+ ASSERT_EQ(QuicDataWriter::GetVarInt62Len(stream_->id()), 1);
+ std::array<char, 256> datagram;
+ datagram[0] = stream_->id();
+ for (size_t i = 1; i < datagram.size(); i++) {
+ datagram[i] = i;
+ }
+ stream_->RegisterHttp3DatagramRegistrationVisitor(
+ &h3_datagram_registration_visitor);
+
+ // Expect us to send a REGISTER_DATAGRAM_NO_CONTEXT capsule.
+ EXPECT_CALL(*session_, WritevData(stream_->id(), _, _, _, _, _))
+ .Times(AtLeast(1));
+
+ stream_->RegisterHttp3DatagramContextId(
+ context_id, DatagramFormatType::UDP_PAYLOAD, format_additional_data,
+ &h3_datagram_visitor);
+ session_->OnMessageReceived(
+ absl::string_view(datagram.data(), datagram.size()));
+ EXPECT_THAT(h3_datagram_visitor.received_h3_datagrams(),
+ ElementsAre(SavingHttp3DatagramVisitor::SavedHttp3Datagram{
+ stream_->id(), context_id,
+ std::string(&datagram[1], datagram.size() - 1)}));
+ // Test move.
+ ::testing::NiceMock<MockHttp3DatagramRegistrationVisitor>
+ h3_datagram_registration_visitor2;
+ stream_->MoveHttp3DatagramRegistration(&h3_datagram_registration_visitor2);
+ SavingHttp3DatagramVisitor h3_datagram_visitor2;
+ stream_->MoveHttp3DatagramContextIdRegistration(context_id,
+ &h3_datagram_visitor2);
+ EXPECT_TRUE(h3_datagram_visitor2.received_h3_datagrams().empty());
+ session_->OnMessageReceived(
+ absl::string_view(datagram.data(), datagram.size()));
+ EXPECT_THAT(h3_datagram_visitor2.received_h3_datagrams(),
+ ElementsAre(SavingHttp3DatagramVisitor::SavedHttp3Datagram{
+ stream_->id(), context_id,
+ std::string(&datagram[1], datagram.size() - 1)}));
+ // Cleanup.
+ stream_->UnregisterHttp3DatagramContextId(context_id);
+ stream_->UnregisterHttp3DatagramRegistrationVisitor();
+}
+
+TEST_P(QuicSpdyStreamTest, HttpDatagramRegistrationWithContext) {
+ if (!UsesHttp3()) {
+ return;
+ }
+ InitializeWithPerspective(kShouldProcessData, Perspective::IS_CLIENT);
+ session_->set_local_http_datagram_support(HttpDatagramSupport::kDraft00And04);
+ QuicSpdySessionPeer::SetHttpDatagramSupport(session_.get(),
+ HttpDatagramSupport::kDraft04);
::testing::NiceMock<MockHttp3DatagramRegistrationVisitor>
h3_datagram_registration_visitor;
SavingHttp3DatagramVisitor h3_datagram_visitor;
absl::optional<QuicDatagramContextId> context_id = 42;
- Http3DatagramContextExtensions extensions;
+ absl::string_view format_additional_data;
+ ASSERT_EQ(QuicDataWriter::GetVarInt62Len(stream_->id()), 1);
+ std::array<char, 256> datagram;
+ datagram[0] = stream_->id();
+ datagram[1] = context_id.value();
+ for (size_t i = 2; i < datagram.size(); i++) {
+ datagram[i] = i;
+ }
stream_->RegisterHttp3DatagramRegistrationVisitor(
&h3_datagram_registration_visitor);
- stream_->RegisterHttp3DatagramContextId(context_id, extensions,
- &h3_datagram_visitor);
+
+ // Expect us to send a REGISTER_DATAGRAM_CONTEXT capsule.
+ EXPECT_CALL(*session_, WritevData(stream_->id(), _, _, _, _, _))
+ .Times(AtLeast(1));
+
+ stream_->RegisterHttp3DatagramContextId(
+ context_id, DatagramFormatType::UDP_PAYLOAD, format_additional_data,
+ &h3_datagram_visitor);
+ session_->OnMessageReceived(
+ absl::string_view(datagram.data(), datagram.size()));
+ EXPECT_THAT(h3_datagram_visitor.received_h3_datagrams(),
+ ElementsAre(SavingHttp3DatagramVisitor::SavedHttp3Datagram{
+ stream_->id(), context_id,
+ std::string(&datagram[2], datagram.size() - 2)}));
// Test move.
::testing::NiceMock<MockHttp3DatagramRegistrationVisitor>
h3_datagram_registration_visitor2;
@@ -3192,7 +3346,18 @@ TEST_P(QuicSpdyStreamTest, H3DatagramRegistrationWithContext) {
SavingHttp3DatagramVisitor h3_datagram_visitor2;
stream_->MoveHttp3DatagramContextIdRegistration(context_id,
&h3_datagram_visitor2);
+ EXPECT_TRUE(h3_datagram_visitor2.received_h3_datagrams().empty());
+ session_->OnMessageReceived(
+ absl::string_view(datagram.data(), datagram.size()));
+ EXPECT_THAT(h3_datagram_visitor2.received_h3_datagrams(),
+ ElementsAre(SavingHttp3DatagramVisitor::SavedHttp3Datagram{
+ stream_->id(), context_id,
+ std::string(&datagram[2], datagram.size() - 2)}));
// Cleanup.
+
+ // Expect us to send a CLOSE_DATAGRAM_CONTEXT capsule.
+ EXPECT_CALL(*session_, WritevData(stream_->id(), _, _, _, _, _))
+ .Times(AtLeast(1));
stream_->UnregisterHttp3DatagramContextId(context_id);
stream_->UnregisterHttp3DatagramRegistrationVisitor();
session_->UnregisterHttp3DatagramFlowId(stream_->id());
@@ -3203,8 +3368,9 @@ TEST_P(QuicSpdyStreamTest, SendHttp3Datagram) {
return;
}
Initialize(kShouldProcessData);
- session_->set_should_negotiate_h3_datagram(true);
- QuicSpdySessionPeer::SetH3DatagramSupported(session_.get(), true);
+ session_->set_local_http_datagram_support(HttpDatagramSupport::kDraft00And04);
+ QuicSpdySessionPeer::SetHttpDatagramSupport(session_.get(),
+ HttpDatagramSupport::kDraft04);
absl::optional<QuicDatagramContextId> context_id;
std::string h3_datagram_payload = {1, 2, 3, 4, 5, 6};
EXPECT_CALL(*connection_, SendMessage(1, _, false))
@@ -3213,6 +3379,22 @@ TEST_P(QuicSpdyStreamTest, SendHttp3Datagram) {
MESSAGE_STATUS_SUCCESS);
}
+TEST_P(QuicSpdyStreamTest, GetMaxDatagramSize) {
+ if (!UsesHttp3()) {
+ return;
+ }
+ Initialize(kShouldProcessData);
+ session_->set_local_http_datagram_support(HttpDatagramSupport::kDraft00And04);
+ QuicSpdySessionPeer::SetHttpDatagramSupport(session_.get(),
+ HttpDatagramSupport::kDraft04);
+
+ QuicByteCount size = stream_->GetMaxDatagramSize(absl::nullopt);
+ QuicByteCount size_with_context =
+ stream_->GetMaxDatagramSize(/*context_id=*/1);
+ EXPECT_GT(size, 512u);
+ EXPECT_EQ(size - 1, size_with_context);
+}
+
} // namespace
} // namespace test
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/web_transport_http3.cc b/chromium/net/third_party/quiche/src/quic/core/http/web_transport_http3.cc
index 820950b31bd..a54d210b327 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/web_transport_http3.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/web_transport_http3.cc
@@ -4,13 +4,17 @@
#include "quic/core/http/web_transport_http3.h"
+#include <limits>
#include <memory>
#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
+#include "quic/core/http/capsule.h"
#include "quic/core/http/quic_spdy_session.h"
#include "quic/core/http/quic_spdy_stream.h"
#include "quic/core/quic_data_reader.h"
#include "quic/core/quic_data_writer.h"
+#include "quic/core/quic_error_codes.h"
#include "quic/core/quic_stream.h"
#include "quic/core/quic_types.h"
#include "quic/core/quic_utils.h"
@@ -25,7 +29,9 @@ namespace quic {
namespace {
class QUIC_NO_EXPORT NoopWebTransportVisitor : public WebTransportVisitor {
- void OnSessionReady() override {}
+ void OnSessionReady(const spdy::SpdyHeaderBlock&) override {}
+ void OnSessionClosed(WebTransportSessionError /*error_code*/,
+ const std::string& /*error_message*/) override {}
void OnIncomingBidirectionalStreamAvailable() override {}
void OnIncomingUnidirectionalStreamAvailable() override {}
void OnDatagramReceived(absl::string_view /*datagram*/) override {}
@@ -68,7 +74,7 @@ void WebTransportHttp3::AssociateStream(QuicStreamId stream_id) {
}
}
-void WebTransportHttp3::CloseAllAssociatedStreams() {
+void WebTransportHttp3::OnConnectStreamClosing() {
// Copy the stream list before iterating over it, as calls to ResetStream()
// can potentially mutate the |session_| list.
std::vector<QuicStreamId> streams(streams_.begin(), streams_.end());
@@ -81,22 +87,108 @@ void WebTransportHttp3::CloseAllAssociatedStreams() {
connect_stream_->UnregisterHttp3DatagramContextId(context_id_);
}
connect_stream_->UnregisterHttp3DatagramRegistrationVisitor();
+
+ MaybeNotifyClose();
+}
+
+void WebTransportHttp3::CloseSession(WebTransportSessionError error_code,
+ absl::string_view error_message) {
+ if (close_sent_) {
+ QUIC_BUG(WebTransportHttp3 close sent twice)
+ << "Calling WebTransportHttp3::CloseSession() more than once is not "
+ "allowed.";
+ return;
+ }
+ close_sent_ = true;
+
+ // There can be a race between us trying to send our close and peer sending
+ // one. If we received a close, however, we cannot send ours since we already
+ // closed the stream in response.
+ if (close_received_) {
+ QUIC_DLOG(INFO) << "Not sending CLOSE_WEBTRANSPORT_SESSION as we've "
+ "already sent one from peer.";
+ return;
+ }
+
+ error_code_ = error_code;
+ error_message_ = std::string(error_message);
+ QuicConnection::ScopedPacketFlusher flusher(
+ connect_stream_->spdy_session()->connection());
+ connect_stream_->WriteCapsule(
+ Capsule::CloseWebTransportSession(error_code, error_message),
+ /*fin=*/true);
+}
+
+void WebTransportHttp3::OnCloseReceived(WebTransportSessionError error_code,
+ absl::string_view error_message) {
+ if (close_received_) {
+ QUIC_BUG(WebTransportHttp3 notified of close received twice)
+ << "WebTransportHttp3::OnCloseReceived() may be only called once.";
+ }
+ close_received_ = true;
+
+ // If the peer has sent a close after we sent our own, keep the local error.
+ if (close_sent_) {
+ QUIC_DLOG(INFO) << "Ignoring received CLOSE_WEBTRANSPORT_SESSION as we've "
+ "already sent our own.";
+ return;
+ }
+
+ error_code_ = error_code;
+ error_message_ = std::string(error_message);
+ connect_stream_->WriteOrBufferBody("", /*fin=*/true);
+ MaybeNotifyClose();
+}
+
+void WebTransportHttp3::OnConnectStreamFinReceived() {
+ // If we already received a CLOSE_WEBTRANSPORT_SESSION capsule, we don't need
+ // to do anything about receiving a FIN, since we already sent one in
+ // response.
+ if (close_received_) {
+ return;
+ }
+ close_received_ = true;
+ if (close_sent_) {
+ QUIC_DLOG(INFO) << "Ignoring received FIN as we've already sent our close.";
+ return;
+ }
+
+ connect_stream_->WriteOrBufferBody("", /*fin=*/true);
+ MaybeNotifyClose();
+}
+
+void WebTransportHttp3::CloseSessionWithFinOnlyForTests() {
+ QUICHE_DCHECK(!close_sent_);
+ close_sent_ = true;
+ if (close_received_) {
+ return;
+ }
+
+ connect_stream_->WriteOrBufferBody("", /*fin=*/true);
}
void WebTransportHttp3::HeadersReceived(const spdy::SpdyHeaderBlock& headers) {
if (session_->perspective() == Perspective::IS_CLIENT) {
- auto it = headers.find(":status");
- if (it == headers.end() || it->second != "200") {
+ int status_code;
+ if (!QuicSpdyStream::ParseHeaderStatusCode(headers, &status_code)) {
QUIC_DVLOG(1) << ENDPOINT
<< "Received WebTransport headers from server without "
- "status 200, rejecting.";
+ "a valid status code, rejecting.";
+ return;
+ }
+ bool valid_status = status_code >= 200 && status_code <= 299;
+ if (!valid_status) {
+ QUIC_DVLOG(1) << ENDPOINT
+ << "Received WebTransport headers from server with "
+ "status code "
+ << status_code << ", rejecting.";
return;
}
}
QUIC_DVLOG(1) << ENDPOINT << "WebTransport session " << id_ << " ready.";
ready_ = true;
- visitor_->OnSessionReady();
+ visitor_->OnSessionReady(headers);
session_->ProcessBufferedWebTransportStreamsForSession(this);
}
@@ -163,6 +255,10 @@ MessageStatus WebTransportHttp3::SendOrQueueDatagram(QuicMemSlice datagram) {
context_id_, absl::string_view(datagram.data(), datagram.length()));
}
+QuicByteCount WebTransportHttp3::GetMaxDatagramSize() const {
+ return connect_stream_->GetMaxDatagramSize(context_id_);
+}
+
void WebTransportHttp3::SetDatagramMaxTimeInQueue(
QuicTime::Delta max_time_in_queue) {
connect_stream_->SetMaxDatagramTimeInQueue(max_time_in_queue);
@@ -178,13 +274,27 @@ void WebTransportHttp3::OnHttp3Datagram(
void WebTransportHttp3::OnContextReceived(
QuicStreamId stream_id, absl::optional<QuicDatagramContextId> context_id,
- const Http3DatagramContextExtensions& /*extensions*/) {
+ DatagramFormatType format_type, absl::string_view format_additional_data) {
if (stream_id != connect_stream_->id()) {
QUIC_BUG(WT3 bad datagram context registration)
<< ENDPOINT << "Registered stream ID " << stream_id << ", expected "
<< connect_stream_->id();
return;
}
+ if (format_type != DatagramFormatType::WEBTRANSPORT) {
+ QUIC_DLOG(INFO) << ENDPOINT << "Ignoring unexpected datagram format type "
+ << DatagramFormatTypeToString(format_type);
+ return;
+ }
+ if (!format_additional_data.empty()) {
+ QUIC_DLOG(ERROR)
+ << ENDPOINT
+ << "Received non-empty format additional data for context ID "
+ << (context_id_.has_value() ? context_id_.value() : 0)
+ << " on stream ID " << connect_stream_->id();
+ session_->ResetStream(connect_stream_->id(), QUIC_BAD_APPLICATION_PAYLOAD);
+ return;
+ }
if (!context_is_known_) {
context_is_known_ = true;
context_id_ = context_id;
@@ -206,15 +316,14 @@ void WebTransportHttp3::OnContextReceived(
return;
}
context_currently_registered_ = true;
- Http3DatagramContextExtensions reply_extensions;
- connect_stream_->RegisterHttp3DatagramContextId(context_id_,
- reply_extensions, this);
+ connect_stream_->RegisterHttp3DatagramContextId(
+ context_id_, format_type, format_additional_data, this);
}
}
void WebTransportHttp3::OnContextClosed(
QuicStreamId stream_id, absl::optional<QuicDatagramContextId> context_id,
- const Http3DatagramContextExtensions& /*extensions*/) {
+ ContextCloseCode close_code, absl::string_view close_details) {
if (stream_id != connect_stream_->id()) {
QUIC_BUG(WT3 bad datagram context registration)
<< ENDPOINT << "Closed context on stream ID " << stream_id
@@ -229,23 +338,31 @@ void WebTransportHttp3::OnContextClosed(
<< " on stream ID " << connect_stream_->id();
return;
}
- QUIC_DLOG(INFO) << ENDPOINT << "Received datagram context close on stream ID "
- << connect_stream_->id() << ", resetting stream";
- session_->ResetStream(connect_stream_->id(), QUIC_STREAM_CANCELLED);
+ QUIC_DLOG(INFO) << ENDPOINT
+ << "Received datagram context close with close code "
+ << close_code << " close details \"" << close_details
+ << "\" on stream ID " << connect_stream_->id()
+ << ", resetting stream";
+ session_->ResetStream(connect_stream_->id(), QUIC_BAD_APPLICATION_PAYLOAD);
+}
+
+void WebTransportHttp3::MaybeNotifyClose() {
+ if (close_notified_) {
+ return;
+ }
+ close_notified_ = true;
+ visitor_->OnSessionClosed(error_code_, error_message_);
}
WebTransportHttp3UnidirectionalStream::WebTransportHttp3UnidirectionalStream(
- PendingStream* pending,
- QuicSpdySession* session)
- : QuicStream(pending, session, READ_UNIDIRECTIONAL, /*is_static=*/false),
+ PendingStream* pending, QuicSpdySession* session)
+ : QuicStream(pending, session, /*is_static=*/false),
session_(session),
adapter_(session, this, sequencer()),
needs_to_send_preamble_(false) {}
WebTransportHttp3UnidirectionalStream::WebTransportHttp3UnidirectionalStream(
- QuicStreamId id,
- QuicSpdySession* session,
- WebTransportSessionId session_id)
+ QuicStreamId id, QuicSpdySession* session, WebTransportSessionId session_id)
: QuicStream(id, session, /*is_static=*/false, WRITE_UNIDIRECTIONAL),
session_(session),
adapter_(session, this, sequencer()),
@@ -334,4 +451,65 @@ void WebTransportHttp3UnidirectionalStream::OnClose() {
session->OnStreamClosed(id());
}
+void WebTransportHttp3UnidirectionalStream::OnStreamReset(
+ const QuicRstStreamFrame& frame) {
+ if (adapter_.visitor() != nullptr) {
+ adapter_.visitor()->OnResetStreamReceived(
+ Http3ErrorToWebTransportOrDefault(frame.ietf_error_code));
+ }
+ QuicStream::OnStreamReset(frame);
+}
+bool WebTransportHttp3UnidirectionalStream::OnStopSending(
+ QuicResetStreamError error) {
+ if (adapter_.visitor() != nullptr) {
+ adapter_.visitor()->OnStopSendingReceived(
+ Http3ErrorToWebTransportOrDefault(error.ietf_application_code()));
+ }
+ return QuicStream::OnStopSending(error);
+}
+void WebTransportHttp3UnidirectionalStream::OnWriteSideInDataRecvdState() {
+ if (adapter_.visitor() != nullptr) {
+ adapter_.visitor()->OnWriteSideInDataRecvdState();
+ }
+
+ QuicStream::OnWriteSideInDataRecvdState();
+}
+
+namespace {
+constexpr uint64_t kWebTransportMappedErrorCodeFirst = 0x52e4a40fa8db;
+constexpr uint64_t kWebTransportMappedErrorCodeLast = 0x52e4a40fa9e2;
+constexpr WebTransportStreamError kDefaultWebTransportError = 0;
+} // namespace
+
+absl::optional<WebTransportStreamError> Http3ErrorToWebTransport(
+ uint64_t http3_error_code) {
+ // Ensure the code is within the valid range.
+ if (http3_error_code < kWebTransportMappedErrorCodeFirst ||
+ http3_error_code > kWebTransportMappedErrorCodeLast) {
+ return absl::nullopt;
+ }
+ // Exclude GREASE codepoints.
+ if ((http3_error_code - 0x21) % 0x1f == 0) {
+ return absl::nullopt;
+ }
+
+ uint64_t shifted = http3_error_code - kWebTransportMappedErrorCodeFirst;
+ uint64_t result = shifted - shifted / 0x1f;
+ QUICHE_DCHECK_LE(result, std::numeric_limits<uint8_t>::max());
+ return result;
+}
+
+WebTransportStreamError Http3ErrorToWebTransportOrDefault(
+ uint64_t http3_error_code) {
+ absl::optional<WebTransportStreamError> result =
+ Http3ErrorToWebTransport(http3_error_code);
+ return result.has_value() ? *result : kDefaultWebTransportError;
+}
+
+uint64_t WebTransportErrorToHttp3(
+ WebTransportStreamError webtransport_error_code) {
+ return kWebTransportMappedErrorCodeFirst + webtransport_error_code +
+ webtransport_error_code / 0x1e;
+}
+
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/web_transport_http3.h b/chromium/net/third_party/quiche/src/quic/core/http/web_transport_http3.h
index df5c4f61bf7..7a72931874c 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/web_transport_http3.h
+++ b/chromium/net/third_party/quiche/src/quic/core/http/web_transport_http3.h
@@ -7,13 +7,15 @@
#include <memory>
+#include "absl/base/attributes.h"
#include "absl/container/flat_hash_set.h"
#include "absl/types/optional.h"
#include "quic/core/http/quic_spdy_session.h"
+#include "quic/core/http/web_transport_stream_adapter.h"
+#include "quic/core/quic_error_codes.h"
#include "quic/core/quic_stream.h"
#include "quic/core/quic_types.h"
#include "quic/core/web_transport_interface.h"
-#include "quic/core/web_transport_stream_adapter.h"
#include "spdy/core/spdy_header_block.h"
namespace quic {
@@ -47,10 +49,21 @@ class QUIC_EXPORT_PRIVATE WebTransportHttp3
void AssociateStream(QuicStreamId stream_id);
void OnStreamClosed(QuicStreamId stream_id) { streams_.erase(stream_id); }
- void CloseAllAssociatedStreams();
+ void OnConnectStreamClosing();
size_t NumberOfAssociatedStreams() { return streams_.size(); }
+ void CloseSession(WebTransportSessionError error_code,
+ absl::string_view error_message) override;
+ void OnCloseReceived(WebTransportSessionError error_code,
+ absl::string_view error_message);
+ void OnConnectStreamFinReceived();
+
+ // It is legal for WebTransport to be closed without a
+ // CLOSE_WEBTRANSPORT_SESSION capsule. We always send a capsule, but we still
+ // need to ensure we handle this case correctly.
+ void CloseSessionWithFinOnlyForTests();
+
// Return the earliest incoming stream that has been received by the session
// but has not been accepted. Returns nullptr if there are no incoming
// streams.
@@ -63,6 +76,7 @@ class QUIC_EXPORT_PRIVATE WebTransportHttp3
WebTransportStream* OpenOutgoingUnidirectionalStream() override;
MessageStatus SendOrQueueDatagram(QuicMemSlice datagram) override;
+ QuicByteCount GetMaxDatagramSize() const override;
void SetDatagramMaxTimeInQueue(QuicTime::Delta max_time_in_queue) override;
// From QuicSpdyStream::Http3DatagramVisitor.
@@ -71,14 +85,22 @@ class QUIC_EXPORT_PRIVATE WebTransportHttp3
absl::string_view payload) override;
// From QuicSpdyStream::Http3DatagramRegistrationVisitor.
- void OnContextReceived(
- QuicStreamId stream_id, absl::optional<QuicDatagramContextId> context_id,
- const Http3DatagramContextExtensions& extensions) override;
- void OnContextClosed(
- QuicStreamId stream_id, absl::optional<QuicDatagramContextId> context_id,
- const Http3DatagramContextExtensions& extensions) override;
+ void OnContextReceived(QuicStreamId stream_id,
+ absl::optional<QuicDatagramContextId> context_id,
+ DatagramFormatType format_type,
+ absl::string_view format_additional_data) override;
+ void OnContextClosed(QuicStreamId stream_id,
+ absl::optional<QuicDatagramContextId> context_id,
+ ContextCloseCode close_code,
+ absl::string_view close_details) override;
+
+ bool close_received() const { return close_received_; }
private:
+ // Notifies the visitor that the connection has been closed. Ensures that the
+ // visitor is only ever called once.
+ void MaybeNotifyClose();
+
QuicSpdySession* const session_; // Unowned.
QuicSpdyStream* const connect_stream_; // Unowned.
const WebTransportSessionId id_;
@@ -95,6 +117,15 @@ class QUIC_EXPORT_PRIVATE WebTransportHttp3
absl::flat_hash_set<QuicStreamId> streams_;
quiche::QuicheCircularDeque<QuicStreamId> incoming_bidirectional_streams_;
quiche::QuicheCircularDeque<QuicStreamId> incoming_unidirectional_streams_;
+
+ bool close_sent_ = false;
+ bool close_received_ = false;
+ bool close_notified_ = false;
+
+ // Those are set to default values, which are used if the session is not
+ // closed cleanly using an appropriate capsule.
+ WebTransportSessionError error_code_ = 0;
+ std::string error_message_ = "";
};
class QUIC_EXPORT_PRIVATE WebTransportHttp3UnidirectionalStream
@@ -115,6 +146,9 @@ class QUIC_EXPORT_PRIVATE WebTransportHttp3UnidirectionalStream
void OnDataAvailable() override;
void OnCanWriteNewData() override;
void OnClose() override;
+ void OnStreamReset(const QuicRstStreamFrame& frame) override;
+ bool OnStopSending(QuicResetStreamError error) override;
+ void OnWriteSideInDataRecvdState() override;
WebTransportStream* interface() { return &adapter_; }
void SetUnblocked() { sequencer()->SetUnblocked(); }
@@ -130,6 +164,20 @@ class QUIC_EXPORT_PRIVATE WebTransportHttp3UnidirectionalStream
void MaybeCloseIncompleteStream();
};
+// Remaps HTTP/3 error code into a WebTransport error code. Returns nullopt if
+// the provided code is outside of valid range.
+QUIC_EXPORT_PRIVATE absl::optional<WebTransportStreamError>
+Http3ErrorToWebTransport(uint64_t http3_error_code);
+
+// Same as above, but returns default error value (zero) when none could be
+// mapped.
+QUIC_EXPORT_PRIVATE WebTransportStreamError
+Http3ErrorToWebTransportOrDefault(uint64_t http3_error_code);
+
+// Remaps WebTransport error code into an HTTP/3 error code.
+QUIC_EXPORT_PRIVATE uint64_t
+WebTransportErrorToHttp3(WebTransportStreamError webtransport_error_code);
+
} // namespace quic
#endif // QUICHE_QUIC_CORE_HTTP_WEB_TRANSPORT_HTTP3_H_
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/web_transport_http3_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/web_transport_http3_test.cc
new file mode 100644
index 00000000000..0cf5b946200
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/http/web_transport_http3_test.cc
@@ -0,0 +1,52 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "quic/core/http/web_transport_http3.h"
+
+#include <cstdint>
+#include <limits>
+
+#include "absl/types/optional.h"
+#include "quic/platform/api/quic_test.h"
+
+namespace quic {
+namespace {
+
+using ::testing::Optional;
+
+TEST(WebTransportHttp3Test, ErrorCodesToHttp3) {
+ EXPECT_EQ(0x52e4a40fa8dbu, WebTransportErrorToHttp3(0x00));
+ EXPECT_EQ(0x52e4a40fa9e2u, WebTransportErrorToHttp3(0xff));
+
+ EXPECT_EQ(0x52e4a40fa8f7u, WebTransportErrorToHttp3(0x1c));
+ EXPECT_EQ(0x52e4a40fa8f8u, WebTransportErrorToHttp3(0x1d));
+ // 0x52e4a40fa8f9 is a GREASE codepoint
+ EXPECT_EQ(0x52e4a40fa8fau, WebTransportErrorToHttp3(0x1e));
+}
+
+TEST(WebTransportHttp3Test, ErrorCodesToWebTransport) {
+ EXPECT_THAT(Http3ErrorToWebTransport(0x52e4a40fa8db), Optional(0x00));
+ EXPECT_THAT(Http3ErrorToWebTransport(0x52e4a40fa9e2), Optional(0xff));
+
+ EXPECT_THAT(Http3ErrorToWebTransport(0x52e4a40fa8f7), Optional(0x1cu));
+ EXPECT_THAT(Http3ErrorToWebTransport(0x52e4a40fa8f8), Optional(0x1du));
+ EXPECT_THAT(Http3ErrorToWebTransport(0x52e4a40fa8f9), absl::nullopt);
+ EXPECT_THAT(Http3ErrorToWebTransport(0x52e4a40fa8fa), Optional(0x1eu));
+
+ EXPECT_EQ(Http3ErrorToWebTransport(0), absl::nullopt);
+ EXPECT_EQ(Http3ErrorToWebTransport(std::numeric_limits<uint64_t>::max()),
+ absl::nullopt);
+}
+
+TEST(WebTransportHttp3Test, ErrorCodeRoundTrip) {
+ for (int error = 0; error < 256; error++) {
+ uint64_t http_error = WebTransportErrorToHttp3(error);
+ absl::optional<WebTransportStreamError> mapped_back =
+ quic::Http3ErrorToWebTransport(http_error);
+ EXPECT_THAT(mapped_back, Optional(error));
+ }
+}
+
+} // namespace
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/web_transport_stream_adapter.cc b/chromium/net/third_party/quiche/src/quic/core/http/web_transport_stream_adapter.cc
index 2470aacf4cc..bea13770756 100644
--- a/chromium/net/third_party/quiche/src/quic/core/web_transport_stream_adapter.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/web_transport_stream_adapter.cc
@@ -2,7 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "quic/core/web_transport_stream_adapter.h"
+#include "quic/core/http/web_transport_stream_adapter.h"
+
+#include "quic/core/http/web_transport_http3.h"
+#include "quic/core/quic_error_codes.h"
namespace quic {
@@ -45,7 +48,7 @@ bool WebTransportStreamAdapter::Write(absl::string_view data) {
QuicMemSlice memslice(QuicBuffer::Copy(
session_->connection()->helper()->GetStreamSendBufferAllocator(), data));
QuicConsumedData consumed =
- stream_->WriteMemSlices(QuicMemSliceSpan(&memslice), /*fin=*/false);
+ stream_->WriteMemSlices(absl::MakeSpan(&memslice, 1), /*fin=*/false);
if (consumed.bytes_consumed == data.size()) {
return true;
@@ -75,7 +78,7 @@ bool WebTransportStreamAdapter::SendFin() {
QuicMemSlice empty;
QuicConsumedData consumed =
- stream_->WriteMemSlices(QuicMemSliceSpan(&empty), /*fin=*/true);
+ stream_->WriteMemSlices(absl::MakeSpan(&empty, 1), /*fin=*/true);
QUICHE_DCHECK_EQ(consumed.bytes_consumed, 0u);
return consumed.fin_consumed;
}
@@ -110,4 +113,15 @@ void WebTransportStreamAdapter::OnCanWriteNewData() {
}
}
+void WebTransportStreamAdapter::ResetWithUserCode(
+ WebTransportStreamError error) {
+ stream_->ResetWriteSide(QuicResetStreamError(
+ QUIC_STREAM_CANCELLED, WebTransportErrorToHttp3(error)));
+}
+
+void WebTransportStreamAdapter::SendStopSending(WebTransportStreamError error) {
+ stream_->SendStopSending(QuicResetStreamError(
+ QUIC_STREAM_CANCELLED, WebTransportErrorToHttp3(error)));
+}
+
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/web_transport_stream_adapter.h b/chromium/net/third_party/quiche/src/quic/core/http/web_transport_stream_adapter.h
index 2e4704ba3e4..a761f6fac03 100644
--- a/chromium/net/third_party/quiche/src/quic/core/web_transport_stream_adapter.h
+++ b/chromium/net/third_party/quiche/src/quic/core/http/web_transport_stream_adapter.h
@@ -8,6 +8,7 @@
#include "quic/core/quic_session.h"
#include "quic/core/quic_stream.h"
#include "quic/core/quic_stream_sequencer.h"
+#include "quic/core/quic_types.h"
#include "quic/core/web_transport_interface.h"
namespace quic {
@@ -34,12 +35,11 @@ class QUIC_EXPORT_PRIVATE WebTransportStreamAdapter
}
QuicStreamId GetStreamId() const override { return stream_->id(); }
- void ResetWithUserCode(QuicRstStreamErrorCode error) override {
- stream_->Reset(error);
- }
+ void ResetWithUserCode(WebTransportStreamError error) override;
void ResetDueToInternalError() override {
stream_->Reset(QUIC_STREAM_INTERNAL_ERROR);
}
+ void SendStopSending(WebTransportStreamError error) override;
void MaybeResetDueToStreamObjectGone() override {
if (stream_->write_side_closed() && stream_->read_side_closed()) {
return;
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 9a5af7e42c3..4e50e728ee4 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
@@ -67,13 +67,13 @@ void QpackDecodedHeadersAccumulator::OnDecodingCompleted() {
}
void QpackDecodedHeadersAccumulator::OnDecodingErrorDetected(
- absl::string_view error_message) {
+ QuicErrorCode error_code, absl::string_view error_message) {
QUICHE_DCHECK(!error_detected_);
QUICHE_DCHECK(!headers_decoded_);
error_detected_ = true;
// Might destroy |this|.
- visitor_->OnHeaderDecodingError(error_message);
+ visitor_->OnHeaderDecodingError(error_code, error_message);
}
void QpackDecodedHeadersAccumulator::Decode(absl::string_view data) {
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator.h
index b22da2a9d92..57d1839d904 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator.h
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator.h
@@ -11,6 +11,7 @@
#include "absl/strings/string_view.h"
#include "quic/core/http/quic_header_list.h"
#include "quic/core/qpack/qpack_progressive_decoder.h"
+#include "quic/core/quic_error_codes.h"
#include "quic/core/quic_types.h"
#include "quic/platform/api/quic_export.h"
@@ -45,7 +46,8 @@ class QUIC_EXPORT_PRIVATE QpackDecodedHeadersAccumulator
bool header_list_size_limit_exceeded) = 0;
// Called when an error has occurred.
- virtual void OnHeaderDecodingError(absl::string_view error_message) = 0;
+ virtual void OnHeaderDecodingError(QuicErrorCode error_code,
+ absl::string_view error_message) = 0;
};
QpackDecodedHeadersAccumulator(QuicStreamId id,
@@ -59,7 +61,8 @@ class QUIC_EXPORT_PRIVATE QpackDecodedHeadersAccumulator
void OnHeaderDecoded(absl::string_view name,
absl::string_view value) override;
void OnDecodingCompleted() override;
- void OnDecodingErrorDetected(absl::string_view error_message) override;
+ void OnDecodingErrorDetected(QuicErrorCode error_code,
+ absl::string_view error_message) override;
// Decode payload data.
// Must not be called if an error has been detected.
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 217f866dce1..0aa08a05d5c 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
@@ -46,9 +46,8 @@ class MockVisitor : public QpackDecodedHeadersAccumulator::Visitor {
OnHeadersDecoded,
(QuicHeaderList headers, bool header_list_size_limit_exceeded),
(override));
- MOCK_METHOD(void,
- OnHeaderDecodingError,
- (absl::string_view error_message),
+ MOCK_METHOD(void, OnHeaderDecodingError,
+ (QuicErrorCode error_code, absl::string_view error_message),
(override));
};
@@ -78,7 +77,8 @@ class QpackDecodedHeadersAccumulatorTest : public QuicTest {
// HEADERS frame payload must have a complete Header Block Prefix.
TEST_F(QpackDecodedHeadersAccumulatorTest, EmptyPayload) {
EXPECT_CALL(visitor_,
- OnHeaderDecodingError(Eq("Incomplete header data prefix.")));
+ OnHeaderDecodingError(QUIC_QPACK_DECOMPRESSION_FAILED,
+ Eq("Incomplete header data prefix.")));
accumulator_.EndHeaderBlock();
}
@@ -87,7 +87,8 @@ TEST_F(QpackDecodedHeadersAccumulatorTest, TruncatedHeaderBlockPrefix) {
accumulator_.Decode(absl::HexStringToBytes("00"));
EXPECT_CALL(visitor_,
- OnHeaderDecodingError(Eq("Incomplete header data prefix.")));
+ OnHeaderDecodingError(QUIC_QPACK_DECOMPRESSION_FAILED,
+ Eq("Incomplete header data prefix.")));
accumulator_.EndHeaderBlock();
}
@@ -110,14 +111,16 @@ TEST_F(QpackDecodedHeadersAccumulatorTest, EmptyHeaderList) {
TEST_F(QpackDecodedHeadersAccumulatorTest, TruncatedPayload) {
accumulator_.Decode(absl::HexStringToBytes("00002366"));
- EXPECT_CALL(visitor_, OnHeaderDecodingError(Eq("Incomplete header block.")));
+ EXPECT_CALL(visitor_, OnHeaderDecodingError(QUIC_QPACK_DECOMPRESSION_FAILED,
+ Eq("Incomplete header block.")));
accumulator_.EndHeaderBlock();
}
// This payload is invalid because it refers to a non-existing static entry.
TEST_F(QpackDecodedHeadersAccumulatorTest, InvalidPayload) {
EXPECT_CALL(visitor_,
- OnHeaderDecodingError(Eq("Static table entry not found.")));
+ OnHeaderDecodingError(QUIC_QPACK_DECOMPRESSION_FAILED,
+ Eq("Static table entry not found.")));
accumulator_.Decode(absl::HexStringToBytes("0000ff23ff24"));
}
@@ -241,7 +244,8 @@ TEST_F(QpackDecodedHeadersAccumulatorTest,
qpack_decoder_.OnSetDynamicTableCapacity(kMaxDynamicTableCapacity);
// Adding dynamic table entry unblocks decoding. Error is detected.
- EXPECT_CALL(visitor_, OnHeaderDecodingError(Eq("Invalid relative index.")));
+ EXPECT_CALL(visitor_, OnHeaderDecodingError(QUIC_QPACK_DECOMPRESSION_FAILED,
+ Eq("Invalid relative index.")));
qpack_decoder_.OnInsertWithoutNameReference("foo", "bar");
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test.cc
index 772b1d25480..8f4b092ad51 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test.cc
@@ -49,8 +49,9 @@ class QpackDecoderTest : public QuicTestWithParam<FragmentMode> {
void SetUp() override {
// Destroy QpackProgressiveDecoder on error to test that it does not crash.
// See https://crbug.com/1025209.
- ON_CALL(handler_, OnDecodingErrorDetected(_))
- .WillByDefault(Invoke([this](absl::string_view /* error_message */) {
+ ON_CALL(handler_, OnDecodingErrorDetected(_, _))
+ .WillByDefault(Invoke([this](QuicErrorCode /* error_code */,
+ absl::string_view /* error_message */) {
progressive_decoder_.reset();
}));
}
@@ -114,7 +115,8 @@ INSTANTIATE_TEST_SUITE_P(All,
TEST_P(QpackDecoderTest, NoPrefix) {
EXPECT_CALL(handler_,
- OnDecodingErrorDetected(Eq("Incomplete header data prefix.")));
+ OnDecodingErrorDetected(QUIC_QPACK_DECOMPRESSION_FAILED,
+ Eq("Incomplete header data prefix.")));
// Header Data Prefix is at least two bytes long.
DecodeHeaderBlock(absl::HexStringToBytes("00"));
@@ -126,7 +128,8 @@ TEST_P(QpackDecoderTest, InvalidPrefix) {
StartDecoding();
EXPECT_CALL(handler_,
- OnDecodingErrorDetected(Eq("Encoded integer too large.")));
+ OnDecodingErrorDetected(QUIC_QPACK_DECOMPRESSION_FAILED,
+ Eq("Encoded integer too large.")));
// Encoded Required Insert Count in Header Data Prefix is too large.
DecodeData(absl::HexStringToBytes("ffffffffffffffffffffffffffff"));
@@ -188,7 +191,8 @@ TEST_P(QpackDecoderTest, MultipleLiteralEntries) {
// Name Length value is too large for varint decoder to decode.
TEST_P(QpackDecoderTest, NameLenTooLargeForVarintDecoder) {
EXPECT_CALL(handler_,
- OnDecodingErrorDetected(Eq("Encoded integer too large.")));
+ OnDecodingErrorDetected(QUIC_QPACK_DECOMPRESSION_FAILED,
+ Eq("Encoded integer too large.")));
DecodeHeaderBlock(absl::HexStringToBytes("000027ffffffffffffffffffff"));
}
@@ -196,7 +200,8 @@ TEST_P(QpackDecoderTest, NameLenTooLargeForVarintDecoder) {
// Name Length value can be decoded by varint decoder but exceeds 1 MB limit.
TEST_P(QpackDecoderTest, NameLenExceedsLimit) {
EXPECT_CALL(handler_,
- OnDecodingErrorDetected(Eq("String literal too long.")));
+ OnDecodingErrorDetected(QUIC_QPACK_DECOMPRESSION_FAILED,
+ Eq("String literal too long.")));
DecodeHeaderBlock(absl::HexStringToBytes("000027ffff7f"));
}
@@ -204,7 +209,8 @@ TEST_P(QpackDecoderTest, NameLenExceedsLimit) {
// Value Length value is too large for varint decoder to decode.
TEST_P(QpackDecoderTest, ValueLenTooLargeForVarintDecoder) {
EXPECT_CALL(handler_,
- OnDecodingErrorDetected(Eq("Encoded integer too large.")));
+ OnDecodingErrorDetected(QUIC_QPACK_DECOMPRESSION_FAILED,
+ Eq("Encoded integer too large.")));
DecodeHeaderBlock(
absl::HexStringToBytes("000023666f6f7fffffffffffffffffffff"));
@@ -213,14 +219,29 @@ TEST_P(QpackDecoderTest, ValueLenTooLargeForVarintDecoder) {
// Value Length value can be decoded by varint decoder but exceeds 1 MB limit.
TEST_P(QpackDecoderTest, ValueLenExceedsLimit) {
EXPECT_CALL(handler_,
- OnDecodingErrorDetected(Eq("String literal too long.")));
+ OnDecodingErrorDetected(QUIC_QPACK_DECOMPRESSION_FAILED,
+ Eq("String literal too long.")));
DecodeHeaderBlock(absl::HexStringToBytes("000023666f6f7fffff7f"));
}
+TEST_P(QpackDecoderTest, LineFeedInValue) {
+ if (GetQuicReloadableFlag(quic_reject_invalid_chars_in_field_value)) {
+ EXPECT_CALL(handler_,
+ OnDecodingErrorDetected(QUIC_INVALID_CHARACTER_IN_FIELD_VALUE,
+ "Invalid character in field value."));
+ } else {
+ EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("ba\nr")));
+ EXPECT_CALL(handler_, OnDecodingCompleted());
+ }
+
+ DecodeHeaderBlock(absl::HexStringToBytes("000023666f6f0462610a72"));
+}
+
TEST_P(QpackDecoderTest, IncompleteHeaderBlock) {
EXPECT_CALL(handler_,
- OnDecodingErrorDetected(Eq("Incomplete header block.")));
+ OnDecodingErrorDetected(QUIC_QPACK_DECOMPRESSION_FAILED,
+ Eq("Incomplete header block.")));
DecodeHeaderBlock(absl::HexStringToBytes("00002366"));
}
@@ -251,8 +272,9 @@ TEST_P(QpackDecoderTest, AlternatingHuffmanNonHuffman) {
}
TEST_P(QpackDecoderTest, HuffmanNameDoesNotHaveEOSPrefix) {
- EXPECT_CALL(handler_, OnDecodingErrorDetected(absl::string_view(
- "Error in Huffman-encoded string.")));
+ EXPECT_CALL(handler_,
+ OnDecodingErrorDetected(QUIC_QPACK_DECOMPRESSION_FAILED,
+ Eq("Error in Huffman-encoded string.")));
// 'y' ends in 0b0 on the most significant bit of the last byte.
// The remaining 7 bits must be a prefix of EOS, which is all 1s.
@@ -261,8 +283,9 @@ TEST_P(QpackDecoderTest, HuffmanNameDoesNotHaveEOSPrefix) {
}
TEST_P(QpackDecoderTest, HuffmanValueDoesNotHaveEOSPrefix) {
- EXPECT_CALL(handler_, OnDecodingErrorDetected(absl::string_view(
- "Error in Huffman-encoded string.")));
+ EXPECT_CALL(handler_,
+ OnDecodingErrorDetected(QUIC_QPACK_DECOMPRESSION_FAILED,
+ Eq("Error in Huffman-encoded string.")));
// 'e' ends in 0b101, taking up the 3 most significant bits of the last byte.
// The remaining 5 bits must be a prefix of EOS, which is all 1s.
@@ -271,8 +294,9 @@ TEST_P(QpackDecoderTest, HuffmanValueDoesNotHaveEOSPrefix) {
}
TEST_P(QpackDecoderTest, HuffmanNameEOSPrefixTooLong) {
- EXPECT_CALL(handler_, OnDecodingErrorDetected(absl::string_view(
- "Error in Huffman-encoded string.")));
+ EXPECT_CALL(handler_,
+ OnDecodingErrorDetected(QUIC_QPACK_DECOMPRESSION_FAILED,
+ Eq("Error in Huffman-encoded string.")));
// The trailing EOS prefix must be at most 7 bits long. Appending one octet
// with value 0xff is invalid, even though 0b111111111111111 (15 bits) is a
@@ -282,8 +306,9 @@ TEST_P(QpackDecoderTest, HuffmanNameEOSPrefixTooLong) {
}
TEST_P(QpackDecoderTest, HuffmanValueEOSPrefixTooLong) {
- EXPECT_CALL(handler_, OnDecodingErrorDetected(absl::string_view(
- "Error in Huffman-encoded string.")));
+ EXPECT_CALL(handler_,
+ OnDecodingErrorDetected(QUIC_QPACK_DECOMPRESSION_FAILED,
+ Eq("Error in Huffman-encoded string.")));
// The trailing EOS prefix must be at most 7 bits long. Appending one octet
// with value 0xff is invalid, even though 0b1111111111111 (13 bits) is a
@@ -321,7 +346,8 @@ TEST_P(QpackDecoderTest, TooHighStaticTableIndex) {
// Addressing entry 99 should trigger an error.
EXPECT_CALL(handler_,
- OnDecodingErrorDetected(Eq("Static table entry not found.")));
+ OnDecodingErrorDetected(QUIC_QPACK_DECOMPRESSION_FAILED,
+ Eq("Static table entry not found.")));
DecodeHeaderBlock(absl::HexStringToBytes("0000ff23ff24"));
}
@@ -430,6 +456,7 @@ TEST_P(QpackDecoderTest, DecreasingDynamicTableCapacityEvictsEntries) {
DecodeEncoderStreamData(absl::HexStringToBytes("3f01"));
EXPECT_CALL(handler_, OnDecodingErrorDetected(
+ QUIC_QPACK_DECOMPRESSION_FAILED,
Eq("Dynamic table entry already evicted.")));
DecodeHeaderBlock(absl::HexStringToBytes(
@@ -497,7 +524,8 @@ TEST_P(QpackDecoderTest, EncoderStreamErrorTooLargeInteger) {
}
TEST_P(QpackDecoderTest, InvalidDynamicEntryWhenBaseIsZero) {
- EXPECT_CALL(handler_, OnDecodingErrorDetected(Eq("Invalid relative index.")));
+ EXPECT_CALL(handler_, OnDecodingErrorDetected(QUIC_QPACK_DECOMPRESSION_FAILED,
+ Eq("Invalid relative index.")));
// Set dynamic table capacity to 1024.
DecodeEncoderStreamData(absl::HexStringToBytes("3fe107"));
@@ -512,7 +540,8 @@ TEST_P(QpackDecoderTest, InvalidDynamicEntryWhenBaseIsZero) {
}
TEST_P(QpackDecoderTest, InvalidNegativeBase) {
- EXPECT_CALL(handler_, OnDecodingErrorDetected(Eq("Error calculating Base.")));
+ EXPECT_CALL(handler_, OnDecodingErrorDetected(QUIC_QPACK_DECOMPRESSION_FAILED,
+ Eq("Error calculating Base.")));
// Required Insert Count 1, Delta Base 1 with sign bit set, Base would
// be 1 - 1 - 1 = -1, but it is not allowed to be negative.
@@ -525,7 +554,8 @@ TEST_P(QpackDecoderTest, InvalidDynamicEntryByRelativeIndex) {
// Add literal entry with name "foo" and value "bar".
DecodeEncoderStreamData(absl::HexStringToBytes("6294e703626172"));
- EXPECT_CALL(handler_, OnDecodingErrorDetected(Eq("Invalid relative index.")));
+ EXPECT_CALL(handler_, OnDecodingErrorDetected(QUIC_QPACK_DECOMPRESSION_FAILED,
+ Eq("Invalid relative index.")));
DecodeHeaderBlock(absl::HexStringToBytes(
"0200" // Required Insert Count 1 and Delta Base 0.
@@ -533,7 +563,8 @@ TEST_P(QpackDecoderTest, InvalidDynamicEntryByRelativeIndex) {
"81")); // Indexed Header Field instruction addressing relative index 1.
// This is absolute index -1, which is invalid.
- EXPECT_CALL(handler_, OnDecodingErrorDetected(Eq("Invalid relative index.")));
+ EXPECT_CALL(handler_, OnDecodingErrorDetected(QUIC_QPACK_DECOMPRESSION_FAILED,
+ Eq("Invalid relative index.")));
DecodeHeaderBlock(absl::HexStringToBytes(
"0200" // Required Insert Count 1 and Delta Base 0.
@@ -554,6 +585,7 @@ TEST_P(QpackDecoderTest, EvictedDynamicTableEntry) {
DecodeEncoderStreamData(absl::HexStringToBytes("00000000"));
EXPECT_CALL(handler_, OnDecodingErrorDetected(
+ QUIC_QPACK_DECOMPRESSION_FAILED,
Eq("Dynamic table entry already evicted.")));
DecodeHeaderBlock(absl::HexStringToBytes(
@@ -563,6 +595,7 @@ TEST_P(QpackDecoderTest, EvictedDynamicTableEntry) {
// This is absolute index 1. Such entry does not exist.
EXPECT_CALL(handler_, OnDecodingErrorDetected(
+ QUIC_QPACK_DECOMPRESSION_FAILED,
Eq("Dynamic table entry already evicted.")));
DecodeHeaderBlock(absl::HexStringToBytes(
@@ -573,6 +606,7 @@ TEST_P(QpackDecoderTest, EvictedDynamicTableEntry) {
// entry does not exist.
EXPECT_CALL(handler_, OnDecodingErrorDetected(
+ QUIC_QPACK_DECOMPRESSION_FAILED,
Eq("Dynamic table entry already evicted.")));
DecodeHeaderBlock(absl::HexStringToBytes(
@@ -583,6 +617,7 @@ TEST_P(QpackDecoderTest, EvictedDynamicTableEntry) {
// does not exist.
EXPECT_CALL(handler_, OnDecodingErrorDetected(
+ QUIC_QPACK_DECOMPRESSION_FAILED,
Eq("Dynamic table entry already evicted.")));
DecodeHeaderBlock(absl::HexStringToBytes(
@@ -614,6 +649,7 @@ TEST_P(QpackDecoderTest, InvalidEncodedRequiredInsertCount) {
// Required Insert Count is decoded modulo 2 * MaxEntries, that is, modulo 64.
// A value of 1 cannot be encoded as 65 even though it has the same remainder.
EXPECT_CALL(handler_, OnDecodingErrorDetected(
+ QUIC_QPACK_DECOMPRESSION_FAILED,
Eq("Error decoding Required Insert Count.")));
DecodeHeaderBlock(absl::HexStringToBytes("4100"));
}
@@ -622,6 +658,7 @@ TEST_P(QpackDecoderTest, InvalidEncodedRequiredInsertCount) {
// after a Header Block Prefix with an invalid Encoded Required Insert Count.
TEST_P(QpackDecoderTest, DataAfterInvalidEncodedRequiredInsertCount) {
EXPECT_CALL(handler_, OnDecodingErrorDetected(
+ QUIC_QPACK_DECOMPRESSION_FAILED,
Eq("Error decoding Required Insert Count.")));
// Header Block Prefix followed by some extra data.
DecodeHeaderBlock(absl::HexStringToBytes("410000"));
@@ -666,7 +703,8 @@ TEST_P(QpackDecoderTest, NonZeroRequiredInsertCountButNoDynamicEntries) {
EXPECT_CALL(handler_, OnHeaderDecoded(Eq(":method"), Eq("GET")));
EXPECT_CALL(handler_,
- OnDecodingErrorDetected(Eq("Required Insert Count too large.")));
+ OnDecodingErrorDetected(QUIC_QPACK_DECOMPRESSION_FAILED,
+ Eq("Required Insert Count too large.")));
DecodeHeaderBlock(absl::HexStringToBytes(
"0200" // Required Insert Count is 1.
@@ -682,6 +720,7 @@ TEST_P(QpackDecoderTest, AddressEntryNotAllowedByRequiredInsertCount) {
EXPECT_CALL(
handler_,
OnDecodingErrorDetected(
+ QUIC_QPACK_DECOMPRESSION_FAILED,
Eq("Absolute Index must be smaller than Required Insert Count.")));
DecodeHeaderBlock(absl::HexStringToBytes(
@@ -694,6 +733,7 @@ TEST_P(QpackDecoderTest, AddressEntryNotAllowedByRequiredInsertCount) {
EXPECT_CALL(
handler_,
OnDecodingErrorDetected(
+ QUIC_QPACK_DECOMPRESSION_FAILED,
Eq("Absolute Index must be smaller than Required Insert Count.")));
DecodeHeaderBlock(absl::HexStringToBytes(
@@ -707,6 +747,7 @@ TEST_P(QpackDecoderTest, AddressEntryNotAllowedByRequiredInsertCount) {
EXPECT_CALL(
handler_,
OnDecodingErrorDetected(
+ QUIC_QPACK_DECOMPRESSION_FAILED,
Eq("Absolute Index must be smaller than Required Insert Count.")));
DecodeHeaderBlock(absl::HexStringToBytes(
@@ -720,6 +761,7 @@ TEST_P(QpackDecoderTest, AddressEntryNotAllowedByRequiredInsertCount) {
EXPECT_CALL(
handler_,
OnDecodingErrorDetected(
+ QUIC_QPACK_DECOMPRESSION_FAILED,
Eq("Absolute Index must be smaller than Required Insert Count.")));
DecodeHeaderBlock(absl::HexStringToBytes(
@@ -743,7 +785,8 @@ TEST_P(QpackDecoderTest, PromisedRequiredInsertCountLargerThanActual) {
EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("bar")));
EXPECT_CALL(handler_,
- OnDecodingErrorDetected(Eq("Required Insert Count too large.")));
+ OnDecodingErrorDetected(QUIC_QPACK_DECOMPRESSION_FAILED,
+ Eq("Required Insert Count too large.")));
DecodeHeaderBlock(absl::HexStringToBytes(
"0300" // Required Insert Count 2 and Delta Base 0.
@@ -755,7 +798,8 @@ TEST_P(QpackDecoderTest, PromisedRequiredInsertCountLargerThanActual) {
EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("")));
EXPECT_CALL(handler_,
- OnDecodingErrorDetected(Eq("Required Insert Count too large.")));
+ OnDecodingErrorDetected(QUIC_QPACK_DECOMPRESSION_FAILED,
+ Eq("Required Insert Count too large.")));
DecodeHeaderBlock(absl::HexStringToBytes(
"0300" // Required Insert Count 2 and Delta Base 0.
@@ -767,7 +811,8 @@ TEST_P(QpackDecoderTest, PromisedRequiredInsertCountLargerThanActual) {
EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("bar")));
EXPECT_CALL(handler_,
- OnDecodingErrorDetected(Eq("Required Insert Count too large.")));
+ OnDecodingErrorDetected(QUIC_QPACK_DECOMPRESSION_FAILED,
+ Eq("Required Insert Count too large.")));
DecodeHeaderBlock(absl::HexStringToBytes(
"0481" // Required Insert Count 3 and Delta Base 1 with sign bit set.
@@ -779,7 +824,8 @@ TEST_P(QpackDecoderTest, PromisedRequiredInsertCountLargerThanActual) {
EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("")));
EXPECT_CALL(handler_,
- OnDecodingErrorDetected(Eq("Required Insert Count too large.")));
+ OnDecodingErrorDetected(QUIC_QPACK_DECOMPRESSION_FAILED,
+ Eq("Required Insert Count too large.")));
DecodeHeaderBlock(absl::HexStringToBytes(
"0481" // Required Insert Count 3 and Delta Base 1 with sign bit set.
@@ -864,7 +910,8 @@ TEST_P(QpackDecoderTest,
// Count of the header block. |handler_| methods are called immediately for
// the already consumed part of the header block.
EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("bar")));
- EXPECT_CALL(handler_, OnDecodingErrorDetected(Eq("Invalid relative index.")));
+ EXPECT_CALL(handler_, OnDecodingErrorDetected(QUIC_QPACK_DECOMPRESSION_FAILED,
+ Eq("Invalid relative index.")));
DecodeEncoderStreamData(absl::HexStringToBytes("6294e703626172"));
}
@@ -905,8 +952,10 @@ TEST_P(QpackDecoderTest, TooManyBlockedStreams) {
auto progressive_decoder1 = CreateProgressiveDecoder(/* stream_id = */ 1);
progressive_decoder1->Decode(data);
- EXPECT_CALL(handler_, OnDecodingErrorDetected(Eq(
- "Limit on number of blocked streams exceeded.")));
+ EXPECT_CALL(handler_,
+ OnDecodingErrorDetected(
+ QUIC_QPACK_DECOMPRESSION_FAILED,
+ Eq("Limit on number of blocked streams exceeded.")));
auto progressive_decoder2 = CreateProgressiveDecoder(/* stream_id = */ 2);
progressive_decoder2->Decode(data);
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.cc
index 3e7d0ad5127..96a3da5103c 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.cc
@@ -12,20 +12,27 @@
#include "quic/core/qpack/qpack_index_conversions.h"
#include "quic/core/qpack/qpack_instructions.h"
#include "quic/core/qpack/qpack_required_insert_count.h"
+#include "quic/platform/api/quic_flag_utils.h"
+#include "quic/platform/api/quic_flags.h"
#include "quic/platform/api/quic_logging.h"
namespace quic {
+namespace {
+
+// The value argument passed to OnHeaderDecoded() is from an entry in the static
+// table.
+constexpr bool kValueFromStaticTable = true;
+
+} // anonymous namespace
+
QpackProgressiveDecoder::QpackProgressiveDecoder(
- QuicStreamId stream_id,
- BlockedStreamLimitEnforcer* enforcer,
- DecodingCompletedVisitor* visitor,
- QpackDecoderHeaderTable* header_table,
+ QuicStreamId stream_id, BlockedStreamLimitEnforcer* enforcer,
+ DecodingCompletedVisitor* visitor, QpackDecoderHeaderTable* header_table,
HeadersHandlerInterface* handler)
: stream_id_(stream_id),
- prefix_decoder_(
- std::make_unique<QpackInstructionDecoder>(QpackPrefixLanguage(),
- this)),
+ prefix_decoder_(std::make_unique<QpackInstructionDecoder>(
+ QpackPrefixLanguage(), this)),
instruction_decoder_(QpackRequestStreamLanguage(), this),
enforcer_(enforcer),
visitor_(visitor),
@@ -38,7 +45,13 @@ QpackProgressiveDecoder::QpackProgressiveDecoder(
blocked_(false),
decoding_(true),
error_detected_(false),
- cancelled_(false) {}
+ cancelled_(false),
+ reject_invalid_chars_in_field_value_(
+ GetQuicReloadableFlag(quic_reject_invalid_chars_in_field_value)) {
+ if (reject_invalid_chars_in_field_value_) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_reject_invalid_chars_in_field_value);
+ }
+}
QpackProgressiveDecoder::~QpackProgressiveDecoder() {
if (blocked_ && !cancelled_) {
@@ -89,14 +102,6 @@ void QpackProgressiveDecoder::EndHeaderBlock() {
}
}
-void QpackProgressiveDecoder::OnError(absl::string_view error_message) {
- QUICHE_DCHECK(!error_detected_);
-
- error_detected_ = true;
- // Might destroy |this|.
- handler_->OnDecodingErrorDetected(error_message);
-}
-
bool QpackProgressiveDecoder::OnInstructionDecoded(
const QpackInstruction* instruction) {
if (instruction == QpackPrefixInstruction()) {
@@ -126,10 +131,9 @@ bool QpackProgressiveDecoder::OnInstructionDecoded(
void QpackProgressiveDecoder::OnInstructionDecodingError(
QpackInstructionDecoder::ErrorCode /* error_code */,
absl::string_view error_message) {
- // Ignore |error_code|, because header block decoding errors trigger a
- // RESET_STREAM frame which cannot carry an error code more granular than
- // QPACK_DECOMPRESSION_FAILED.
- OnError(error_message);
+ // Ignore |error_code| and always use QUIC_QPACK_DECOMPRESSION_FAILED to avoid
+ // having to define a new QuicErrorCode for every instruction decoder error.
+ OnError(QUIC_QPACK_DECOMPRESSION_FAILED, error_message);
}
void QpackProgressiveDecoder::OnInsertCountReachedThreshold() {
@@ -164,12 +168,13 @@ bool QpackProgressiveDecoder::DoIndexedHeaderFieldInstruction() {
uint64_t absolute_index;
if (!QpackRequestStreamRelativeIndexToAbsoluteIndex(
instruction_decoder_.varint(), base_, &absolute_index)) {
- OnError("Invalid relative index.");
+ OnError(QUIC_QPACK_DECOMPRESSION_FAILED, "Invalid relative index.");
return false;
}
if (absolute_index >= required_insert_count_) {
- OnError("Absolute Index must be smaller than Required Insert Count.");
+ OnError(QUIC_QPACK_DECOMPRESSION_FAILED,
+ "Absolute Index must be smaller than Required Insert Count.");
return false;
}
@@ -180,36 +185,37 @@ bool QpackProgressiveDecoder::DoIndexedHeaderFieldInstruction() {
auto entry =
header_table_->LookupEntry(/* is_static = */ false, absolute_index);
if (!entry) {
- OnError("Dynamic table entry already evicted.");
+ OnError(QUIC_QPACK_DECOMPRESSION_FAILED,
+ "Dynamic table entry already evicted.");
return false;
}
header_table_->set_dynamic_table_entry_referenced();
- handler_->OnHeaderDecoded(entry->name(), entry->value());
- return true;
+ return OnHeaderDecoded(!kValueFromStaticTable, entry->name(),
+ entry->value());
}
auto entry = header_table_->LookupEntry(/* is_static = */ true,
instruction_decoder_.varint());
if (!entry) {
- OnError("Static table entry not found.");
+ OnError(QUIC_QPACK_DECOMPRESSION_FAILED, "Static table entry not found.");
return false;
}
- handler_->OnHeaderDecoded(entry->name(), entry->value());
- return true;
+ return OnHeaderDecoded(kValueFromStaticTable, entry->name(), entry->value());
}
bool QpackProgressiveDecoder::DoIndexedHeaderFieldPostBaseInstruction() {
uint64_t absolute_index;
if (!QpackPostBaseIndexToAbsoluteIndex(instruction_decoder_.varint(), base_,
&absolute_index)) {
- OnError("Invalid post-base index.");
+ OnError(QUIC_QPACK_DECOMPRESSION_FAILED, "Invalid post-base index.");
return false;
}
if (absolute_index >= required_insert_count_) {
- OnError("Absolute Index must be smaller than Required Insert Count.");
+ OnError(QUIC_QPACK_DECOMPRESSION_FAILED,
+ "Absolute Index must be smaller than Required Insert Count.");
return false;
}
@@ -220,13 +226,13 @@ bool QpackProgressiveDecoder::DoIndexedHeaderFieldPostBaseInstruction() {
auto entry =
header_table_->LookupEntry(/* is_static = */ false, absolute_index);
if (!entry) {
- OnError("Dynamic table entry already evicted.");
+ OnError(QUIC_QPACK_DECOMPRESSION_FAILED,
+ "Dynamic table entry already evicted.");
return false;
}
header_table_->set_dynamic_table_entry_referenced();
- handler_->OnHeaderDecoded(entry->name(), entry->value());
- return true;
+ return OnHeaderDecoded(!kValueFromStaticTable, entry->name(), entry->value());
}
bool QpackProgressiveDecoder::DoLiteralHeaderFieldNameReferenceInstruction() {
@@ -234,12 +240,13 @@ bool QpackProgressiveDecoder::DoLiteralHeaderFieldNameReferenceInstruction() {
uint64_t absolute_index;
if (!QpackRequestStreamRelativeIndexToAbsoluteIndex(
instruction_decoder_.varint(), base_, &absolute_index)) {
- OnError("Invalid relative index.");
+ OnError(QUIC_QPACK_DECOMPRESSION_FAILED, "Invalid relative index.");
return false;
}
if (absolute_index >= required_insert_count_) {
- OnError("Absolute Index must be smaller than Required Insert Count.");
+ OnError(QUIC_QPACK_DECOMPRESSION_FAILED,
+ "Absolute Index must be smaller than Required Insert Count.");
return false;
}
@@ -250,36 +257,38 @@ bool QpackProgressiveDecoder::DoLiteralHeaderFieldNameReferenceInstruction() {
auto entry =
header_table_->LookupEntry(/* is_static = */ false, absolute_index);
if (!entry) {
- OnError("Dynamic table entry already evicted.");
+ OnError(QUIC_QPACK_DECOMPRESSION_FAILED,
+ "Dynamic table entry already evicted.");
return false;
}
header_table_->set_dynamic_table_entry_referenced();
- handler_->OnHeaderDecoded(entry->name(), instruction_decoder_.value());
- return true;
+ return OnHeaderDecoded(!kValueFromStaticTable, entry->name(),
+ instruction_decoder_.value());
}
auto entry = header_table_->LookupEntry(/* is_static = */ true,
instruction_decoder_.varint());
if (!entry) {
- OnError("Static table entry not found.");
+ OnError(QUIC_QPACK_DECOMPRESSION_FAILED, "Static table entry not found.");
return false;
}
- handler_->OnHeaderDecoded(entry->name(), instruction_decoder_.value());
- return true;
+ return OnHeaderDecoded(kValueFromStaticTable, entry->name(),
+ instruction_decoder_.value());
}
bool QpackProgressiveDecoder::DoLiteralHeaderFieldPostBaseInstruction() {
uint64_t absolute_index;
if (!QpackPostBaseIndexToAbsoluteIndex(instruction_decoder_.varint(), base_,
&absolute_index)) {
- OnError("Invalid post-base index.");
+ OnError(QUIC_QPACK_DECOMPRESSION_FAILED, "Invalid post-base index.");
return false;
}
if (absolute_index >= required_insert_count_) {
- OnError("Absolute Index must be smaller than Required Insert Count.");
+ OnError(QUIC_QPACK_DECOMPRESSION_FAILED,
+ "Absolute Index must be smaller than Required Insert Count.");
return false;
}
@@ -290,20 +299,19 @@ bool QpackProgressiveDecoder::DoLiteralHeaderFieldPostBaseInstruction() {
auto entry =
header_table_->LookupEntry(/* is_static = */ false, absolute_index);
if (!entry) {
- OnError("Dynamic table entry already evicted.");
+ OnError(QUIC_QPACK_DECOMPRESSION_FAILED,
+ "Dynamic table entry already evicted.");
return false;
}
header_table_->set_dynamic_table_entry_referenced();
- handler_->OnHeaderDecoded(entry->name(), instruction_decoder_.value());
- return true;
+ return OnHeaderDecoded(!kValueFromStaticTable, entry->name(),
+ instruction_decoder_.value());
}
bool QpackProgressiveDecoder::DoLiteralHeaderFieldInstruction() {
- handler_->OnHeaderDecoded(instruction_decoder_.name(),
- instruction_decoder_.value());
-
- return true;
+ return OnHeaderDecoded(!kValueFromStaticTable, instruction_decoder_.name(),
+ instruction_decoder_.value());
}
bool QpackProgressiveDecoder::DoPrefixInstruction() {
@@ -312,14 +320,15 @@ bool QpackProgressiveDecoder::DoPrefixInstruction() {
if (!QpackDecodeRequiredInsertCount(
prefix_decoder_->varint(), header_table_->max_entries(),
header_table_->inserted_entry_count(), &required_insert_count_)) {
- OnError("Error decoding Required Insert Count.");
+ OnError(QUIC_QPACK_DECOMPRESSION_FAILED,
+ "Error decoding Required Insert Count.");
return false;
}
const bool sign = prefix_decoder_->s_bit();
const uint64_t delta_base = prefix_decoder_->varint2();
if (!DeltaBaseToBase(sign, delta_base, &base_)) {
- OnError("Error calculating Base.");
+ OnError(QUIC_QPACK_DECOMPRESSION_FAILED, "Error calculating Base.");
return false;
}
@@ -327,7 +336,8 @@ bool QpackProgressiveDecoder::DoPrefixInstruction() {
if (required_insert_count_ > header_table_->inserted_entry_count()) {
if (!enforcer_->OnStreamBlocked(stream_id_)) {
- OnError("Limit on number of blocked streams exceeded.");
+ OnError(QUIC_QPACK_DECOMPRESSION_FAILED,
+ "Limit on number of blocked streams exceeded.");
return false;
}
blocked_ = true;
@@ -337,6 +347,32 @@ bool QpackProgressiveDecoder::DoPrefixInstruction() {
return true;
}
+bool QpackProgressiveDecoder::OnHeaderDecoded(bool value_from_static_table,
+ absl::string_view name,
+ absl::string_view value) {
+ // Skip test for static table entries as they are all known to be valid.
+ if (reject_invalid_chars_in_field_value_ && !value_from_static_table) {
+ // According to Section 10.3 of
+ // https://quicwg.org/base-drafts/draft-ietf-quic-http.html,
+ // "[...] HTTP/3 can transport field values that are not valid. While most
+ // values that can be encoded will not alter field parsing, carriage return
+ // (CR, ASCII 0x0d), line feed (LF, ASCII 0x0a), and the zero character
+ // (NUL, ASCII 0x00) might be exploited by an attacker if they are
+ // translated verbatim. Any request or response that contains a character
+ // not permitted in a field value MUST be treated as malformed [...]"
+ for (const auto c : value) {
+ if (c == '\0' || c == '\n' || c == '\r') {
+ OnError(QUIC_INVALID_CHARACTER_IN_FIELD_VALUE,
+ "Invalid character in field value.");
+ return false;
+ }
+ }
+ }
+
+ handler_->OnHeaderDecoded(name, value);
+ return true;
+}
+
void QpackProgressiveDecoder::FinishDecoding() {
QUICHE_DCHECK(buffer_.empty());
QUICHE_DCHECK(!blocked_);
@@ -347,17 +383,18 @@ void QpackProgressiveDecoder::FinishDecoding() {
}
if (!instruction_decoder_.AtInstructionBoundary()) {
- OnError("Incomplete header block.");
+ OnError(QUIC_QPACK_DECOMPRESSION_FAILED, "Incomplete header block.");
return;
}
if (!prefix_decoded_) {
- OnError("Incomplete header data prefix.");
+ OnError(QUIC_QPACK_DECOMPRESSION_FAILED, "Incomplete header data prefix.");
return;
}
if (required_insert_count_ != required_insert_count_so_far_) {
- OnError("Required Insert Count too large.");
+ OnError(QUIC_QPACK_DECOMPRESSION_FAILED,
+ "Required Insert Count too large.");
return;
}
@@ -365,6 +402,15 @@ void QpackProgressiveDecoder::FinishDecoding() {
handler_->OnDecodingCompleted();
}
+void QpackProgressiveDecoder::OnError(QuicErrorCode error_code,
+ absl::string_view error_message) {
+ QUICHE_DCHECK(!error_detected_);
+
+ error_detected_ = true;
+ // Might destroy |this|.
+ handler_->OnDecodingErrorDetected(error_code, error_message);
+}
+
bool QpackProgressiveDecoder::DeltaBaseToBase(bool sign,
uint64_t delta_base,
uint64_t* base) {
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.h
index ced6bf0c2dd..b077ab186cb 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.h
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.h
@@ -13,6 +13,7 @@
#include "quic/core/qpack/qpack_encoder_stream_receiver.h"
#include "quic/core/qpack/qpack_header_table.h"
#include "quic/core/qpack/qpack_instruction_decoder.h"
+#include "quic/core/quic_error_codes.h"
#include "quic/core/quic_types.h"
#include "quic/platform/api/quic_export.h"
@@ -46,7 +47,8 @@ class QUIC_EXPORT_PRIVATE QpackProgressiveDecoder
// Called when a decoding error has occurred. No other methods will be
// called afterwards. Implementations are allowed to destroy
// the QpackProgressiveDecoder instance synchronously.
- virtual void OnDecodingErrorDetected(absl::string_view error_message) = 0;
+ virtual void OnDecodingErrorDetected(QuicErrorCode error_code,
+ absl::string_view error_message) = 0;
};
// Interface for keeping track of blocked streams for the purpose of enforcing
@@ -95,9 +97,6 @@ class QUIC_EXPORT_PRIVATE QpackProgressiveDecoder
// through Decode(). No methods must be called afterwards.
void EndHeaderBlock();
- // Called on error.
- void OnError(absl::string_view error_message);
-
// QpackInstructionDecoder::Delegate implementation.
bool OnInstructionDecoded(const QpackInstruction* instruction) override;
void OnInstructionDecodingError(QpackInstructionDecoder::ErrorCode error_code,
@@ -115,9 +114,20 @@ class QUIC_EXPORT_PRIVATE QpackProgressiveDecoder
bool DoLiteralHeaderFieldInstruction();
bool DoPrefixInstruction();
+ // Called when an entry is decoded. Performs validation and calls
+ // HeadersHandlerInterface::OnHeaderDecoded() or OnError() as needed. Returns
+ // true if header value is valid, false otherwise. Skips validation if
+ // |value_from_static_table| is true, because static table entries are always
+ // valid.
+ bool OnHeaderDecoded(bool value_from_static_table, absl::string_view name,
+ absl::string_view value);
+
// Called as soon as EndHeaderBlock() is called and decoding is not blocked.
void FinishDecoding();
+ // Called on error.
+ void OnError(QuicErrorCode error_code, absl::string_view error_message);
+
// Calculates Base from |required_insert_count_|, which must be set before
// calling this method, and sign bit and Delta Base in the Header Data Prefix,
// which are passed in as arguments. Returns true on success, false on
@@ -166,6 +176,10 @@ class QUIC_EXPORT_PRIVATE QpackProgressiveDecoder
// True if QpackDecoderHeaderTable has been destroyed
// while decoding is still blocked.
bool cancelled_;
+
+ // Latched value of
+ // gfe2_reloadable_flag_quic_reject_invalid_chars_in_field_value
+ const bool reject_invalid_chars_in_field_value_;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_receive_stream.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_receive_stream.cc
index 65e290f380d..1f75919d8f8 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_receive_stream.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_receive_stream.cc
@@ -11,8 +11,7 @@ namespace quic {
QpackReceiveStream::QpackReceiveStream(PendingStream* pending,
QuicSession* session,
QpackStreamReceiver* receiver)
- : QuicStream(pending, session, READ_UNIDIRECTIONAL, /*is_static=*/true),
- receiver_(receiver) {}
+ : QuicStream(pending, session, /*is_static=*/true), receiver_(receiver) {}
void QpackReceiveStream::OnStreamReset(const QuicRstStreamFrame& /*frame*/) {
stream_delegate()->OnStreamError(
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_send_stream.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_send_stream.cc
index 0d5d8af79ef..626d0639bf5 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_send_stream.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_send_stream.cc
@@ -21,7 +21,7 @@ void QpackSendStream::OnStreamReset(const QuicRstStreamFrame& /*frame*/) {
<< "OnStreamReset() called for write unidirectional stream.";
}
-bool QpackSendStream::OnStopSending(QuicRstStreamErrorCode /* code */) {
+bool QpackSendStream::OnStopSending(QuicResetStreamError /* code */) {
stream_delegate()->OnStreamError(
QUIC_HTTP_CLOSED_CRITICAL_STREAM,
"STOP_SENDING received for QPACK send stream");
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_send_stream.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_send_stream.h
index fad159c30fe..086ad638d46 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_send_stream.h
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_send_stream.h
@@ -33,7 +33,7 @@ class QUIC_EXPORT_PRIVATE QpackSendStream : public QuicStream,
// Overriding QuicStream::OnStopSending() to make sure QPACK stream is never
// closed before connection.
void OnStreamReset(const QuicRstStreamFrame& frame) override;
- bool OnStopSending(QuicRstStreamErrorCode code) override;
+ bool OnStopSending(QuicResetStreamError code) override;
// The send QPACK stream is write unidirectional, so this method
// should never be called.
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_send_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_send_stream_test.cc
index df4668b07b2..5a98951a630 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_send_stream_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_send_stream_test.cc
@@ -119,7 +119,8 @@ TEST_P(QpackSendStreamTest, WriteStreamTypeOnlyFirstTime) {
TEST_P(QpackSendStreamTest, StopSendingQpackStream) {
EXPECT_CALL(*connection_,
CloseConnection(QUIC_HTTP_CLOSED_CRITICAL_STREAM, _, _));
- qpack_send_stream_->OnStopSending(QUIC_STREAM_CANCELLED);
+ qpack_send_stream_->OnStopSending(
+ QuicResetStreamError::FromInternal(QUIC_STREAM_CANCELLED));
}
TEST_P(QpackSendStreamTest, ReceiveDataOnSendStream) {
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_alarm.cc b/chromium/net/third_party/quiche/src/quic/core/quic_alarm.cc
index 81640a4c68e..7419159d18a 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_alarm.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_alarm.cc
@@ -4,6 +4,8 @@
#include "quic/core/quic_alarm.h"
+#include <atomic>
+
#include "quic/platform/api/quic_bug_tracker.h"
#include "quic/platform/api/quic_flag_utils.h"
#include "quic/platform/api/quic_flags.h"
@@ -15,14 +17,8 @@ QuicAlarm::QuicAlarm(QuicArenaScopedPtr<Delegate> delegate)
: delegate_(std::move(delegate)), deadline_(QuicTime::Zero()) {}
QuicAlarm::~QuicAlarm() {
- if (GetQuicRestartFlag(quic_alarm_add_permanent_cancel) && IsSet()) {
+ if (IsSet()) {
QUIC_CODE_COUNT(quic_alarm_not_cancelled_in_dtor);
- static uint64_t hit_count = 0;
- ++hit_count;
- if ((hit_count & (hit_count - 1)) == 0) {
- QUIC_LOG(ERROR) << "QuicAlarm not cancelled at destruction. "
- << QuicStackTrace();
- }
}
}
@@ -42,16 +38,6 @@ void QuicAlarm::Set(QuicTime new_deadline) {
}
void QuicAlarm::CancelInternal(bool permanent) {
- if (!GetQuicRestartFlag(quic_alarm_add_permanent_cancel)) {
- if (!IsSet()) {
- // Don't try to cancel an alarm that hasn't been set.
- return;
- }
- deadline_ = QuicTime::Zero();
- CancelImpl();
- return;
- }
-
if (IsSet()) {
deadline_ = QuicTime::Zero();
CancelImpl();
@@ -100,6 +86,11 @@ void QuicAlarm::Fire() {
deadline_ = QuicTime::Zero();
if (!IsPermanentlyCancelled()) {
+ absl::optional<QuicConnectionContextSwitcher> context_switcher;
+ if (GetQuicReloadableFlag(quic_restore_connection_context_in_alarms)) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_restore_connection_context_in_alarms);
+ context_switcher.emplace(delegate_->GetConnectionContext());
+ }
delegate_->OnAlarm();
}
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_alarm.h b/chromium/net/third_party/quiche/src/quic/core/quic_alarm.h
index 5080fd4b263..26ebfe8ca4d 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_alarm.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_alarm.h
@@ -6,6 +6,7 @@
#define QUICHE_QUIC_CORE_QUIC_ALARM_H_
#include "quic/core/quic_arena_scoped_ptr.h"
+#include "quic/core/quic_connection_context.h"
#include "quic/core/quic_time.h"
#include "quic/platform/api/quic_export.h"
@@ -22,10 +23,39 @@ class QUIC_EXPORT_PRIVATE QuicAlarm {
public:
virtual ~Delegate() {}
+ // If the alarm belongs to a single QuicConnection, return the corresponding
+ // QuicConnection.context_. Note the context_ is the first member of
+ // QuicConnection, so it should outlive the delegate.
+ // Otherwise return nullptr.
+ // The OnAlarm function will be called under the connection context, if any.
+ virtual QuicConnectionContext* GetConnectionContext() = 0;
+
// Invoked when the alarm fires.
virtual void OnAlarm() = 0;
};
+ // DelegateWithContext is a Delegate with a QuicConnectionContext* stored as a
+ // member variable.
+ class QUIC_EXPORT_PRIVATE DelegateWithContext : public Delegate {
+ public:
+ explicit DelegateWithContext(QuicConnectionContext* context)
+ : context_(context) {}
+ ~DelegateWithContext() override {}
+ QuicConnectionContext* GetConnectionContext() override { return context_; }
+
+ private:
+ QuicConnectionContext* context_;
+ };
+
+ // DelegateWithoutContext is a Delegate that does not have a corresponding
+ // context. Typically this means one object of the child class deals with many
+ // connections.
+ class QUIC_EXPORT_PRIVATE DelegateWithoutContext : public Delegate {
+ public:
+ ~DelegateWithoutContext() override {}
+ QuicConnectionContext* GetConnectionContext() override { return nullptr; }
+ };
+
explicit QuicAlarm(QuicArenaScopedPtr<Delegate> delegate);
QuicAlarm(const QuicAlarm&) = delete;
QuicAlarm& operator=(const QuicAlarm&) = delete;
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 ab070022eec..c5f0327d9c6 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
@@ -4,21 +4,41 @@
#include "quic/core/quic_alarm.h"
+#include "quic/core/quic_connection_context.h"
#include "quic/platform/api/quic_expect_bug.h"
#include "quic/platform/api/quic_test.h"
+using testing::ElementsAre;
using testing::Invoke;
+using testing::Return;
namespace quic {
namespace test {
namespace {
+class TraceCollector : public QuicConnectionTracer {
+ public:
+ ~TraceCollector() override = default;
+
+ void PrintLiteral(const char* literal) override { trace_.push_back(literal); }
+
+ void PrintString(absl::string_view s) override {
+ trace_.push_back(std::string(s));
+ }
+
+ const std::vector<std::string>& trace() const { return trace_; }
+
+ private:
+ std::vector<std::string> trace_;
+};
+
class MockDelegate : public QuicAlarm::Delegate {
public:
+ MOCK_METHOD(QuicConnectionContext*, GetConnectionContext, (), (override));
MOCK_METHOD(void, OnAlarm, (), (override));
};
-class DestructiveDelegate : public QuicAlarm::Delegate {
+class DestructiveDelegate : public QuicAlarm::DelegateWithoutContext {
public:
DestructiveDelegate() : alarm_(nullptr) {}
@@ -120,35 +140,16 @@ TEST_F(QuicAlarmTest, PermanentCancel) {
EXPECT_FALSE(alarm_.scheduled());
EXPECT_EQ(QuicTime::Zero(), alarm_.deadline());
- if (!GetQuicRestartFlag(quic_alarm_add_permanent_cancel)) {
- alarm_.Set(deadline);
- // When flag is false, PermanentCancel should work like a normal Cancel.
- EXPECT_TRUE(alarm_.IsSet());
- EXPECT_TRUE(alarm_.scheduled());
- EXPECT_EQ(deadline, alarm_.deadline());
- EXPECT_FALSE(alarm_.IsPermanentlyCancelled());
- alarm_.PermanentCancel();
- } else {
- EXPECT_QUIC_BUG(alarm_.Set(deadline),
- "Set called after alarm is permanently cancelled");
- EXPECT_TRUE(alarm_.IsPermanentlyCancelled());
- }
+ EXPECT_QUIC_BUG(alarm_.Set(deadline),
+ "Set called after alarm is permanently cancelled");
+ EXPECT_TRUE(alarm_.IsPermanentlyCancelled());
EXPECT_FALSE(alarm_.IsSet());
EXPECT_FALSE(alarm_.scheduled());
EXPECT_EQ(QuicTime::Zero(), alarm_.deadline());
- if (!GetQuicRestartFlag(quic_alarm_add_permanent_cancel)) {
- alarm_.Update(deadline, QuicTime::Delta::Zero());
- EXPECT_TRUE(alarm_.IsSet());
- EXPECT_TRUE(alarm_.scheduled());
- EXPECT_EQ(deadline, alarm_.deadline());
- EXPECT_FALSE(alarm_.IsPermanentlyCancelled());
- alarm_.PermanentCancel();
- } else {
- EXPECT_QUIC_BUG(alarm_.Update(deadline, QuicTime::Delta::Zero()),
- "Update called after alarm is permanently cancelled");
- EXPECT_TRUE(alarm_.IsPermanentlyCancelled());
- }
+ EXPECT_QUIC_BUG(alarm_.Update(deadline, QuicTime::Delta::Zero()),
+ "Update called after alarm is permanently cancelled");
+ EXPECT_TRUE(alarm_.IsPermanentlyCancelled());
EXPECT_FALSE(alarm_.IsSet());
EXPECT_FALSE(alarm_.scheduled());
EXPECT_EQ(QuicTime::Zero(), alarm_.deadline());
@@ -204,6 +205,67 @@ TEST_F(QuicAlarmTest, FireDestroysAlarm) {
alarm->FireAlarm();
}
+TEST_F(QuicAlarmTest, NullAlarmContext) {
+ QuicTime deadline = QuicTime::Zero() + QuicTime::Delta::FromSeconds(7);
+ alarm_.Set(deadline);
+
+ if (GetQuicReloadableFlag(quic_restore_connection_context_in_alarms)) {
+ EXPECT_CALL(*delegate_, GetConnectionContext()).WillOnce(Return(nullptr));
+ }
+
+ EXPECT_CALL(*delegate_, OnAlarm()).WillOnce(Invoke([] {
+ QUIC_TRACELITERAL("Alarm fired.");
+ }));
+ alarm_.FireAlarm();
+}
+
+TEST_F(QuicAlarmTest, AlarmContextWithNullTracer) {
+ QuicConnectionContext context;
+ ASSERT_EQ(context.tracer, nullptr);
+
+ QuicTime deadline = QuicTime::Zero() + QuicTime::Delta::FromSeconds(7);
+ alarm_.Set(deadline);
+
+ if (GetQuicReloadableFlag(quic_restore_connection_context_in_alarms)) {
+ EXPECT_CALL(*delegate_, GetConnectionContext()).WillOnce(Return(&context));
+ }
+
+ EXPECT_CALL(*delegate_, OnAlarm()).WillOnce(Invoke([] {
+ QUIC_TRACELITERAL("Alarm fired.");
+ }));
+ alarm_.FireAlarm();
+}
+
+TEST_F(QuicAlarmTest, AlarmContextWithTracer) {
+ QuicConnectionContext context;
+ std::unique_ptr<TraceCollector> tracer = std::make_unique<TraceCollector>();
+ const TraceCollector& tracer_ref = *tracer;
+ context.tracer = std::move(tracer);
+
+ QuicTime deadline = QuicTime::Zero() + QuicTime::Delta::FromSeconds(7);
+ alarm_.Set(deadline);
+
+ if (GetQuicReloadableFlag(quic_restore_connection_context_in_alarms)) {
+ EXPECT_CALL(*delegate_, GetConnectionContext()).WillOnce(Return(&context));
+ }
+
+ EXPECT_CALL(*delegate_, OnAlarm()).WillOnce(Invoke([] {
+ QUIC_TRACELITERAL("Alarm fired.");
+ }));
+
+ // Since |context| is not installed in the current thread, the messages before
+ // and after FireAlarm() should not be collected by |tracer|.
+ QUIC_TRACELITERAL("Should not be collected before alarm.");
+ alarm_.FireAlarm();
+ QUIC_TRACELITERAL("Should not be collected after alarm.");
+
+ if (GetQuicReloadableFlag(quic_restore_connection_context_in_alarms)) {
+ EXPECT_THAT(tracer_ref.trace(), ElementsAre("Alarm fired."));
+ } else {
+ EXPECT_TRUE(tracer_ref.trace().empty());
+ }
+}
+
} // namespace
} // namespace test
} // namespace quic
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 9312ea5deae..f235e45b30f 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
@@ -24,7 +24,7 @@ static const size_t kMaxConnectionsWithoutCHLO =
namespace {
// This alarm removes expired entries in map each time this alarm fires.
-class ConnectionExpireAlarm : public QuicAlarm::Delegate {
+class ConnectionExpireAlarm : public QuicAlarm::DelegateWithoutContext {
public:
explicit ConnectionExpireAlarm(QuicBufferedPacketStore* store)
: connection_store_(store) {}
@@ -77,8 +77,7 @@ QuicBufferedPacketStore::QuicBufferedPacketStore(
alarm_factory->CreateAlarm(new ConnectionExpireAlarm(this))) {}
QuicBufferedPacketStore::~QuicBufferedPacketStore() {
- if (GetQuicRestartFlag(quic_alarm_add_permanent_cancel) &&
- expiration_alarm_ != nullptr) {
+ if (expiration_alarm_ != nullptr) {
expiration_alarm_->PermanentCancel();
}
}
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 12bf186d318..f152e6e799a 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
@@ -47,6 +47,7 @@
#include "quic/platform/api/quic_logging.h"
#include "quic/platform/api/quic_server_stats.h"
#include "quic/platform/api/quic_socket_address.h"
+#include "common/platform/api/quiche_flag_utils.h"
#include "common/quiche_text_utils.h"
namespace quic {
@@ -71,6 +72,10 @@ class QuicConnectionAlarmDelegate : public QuicAlarm::Delegate {
QuicConnectionAlarmDelegate& operator=(const QuicConnectionAlarmDelegate&) =
delete;
+ QuicConnectionContext* GetConnectionContext() override {
+ return (connection_ == nullptr) ? nullptr : connection_->context();
+ }
+
protected:
QuicConnection* connection_;
};
@@ -215,16 +220,11 @@ QuicConnection::QuicConnection(
QuicConnectionId server_connection_id,
QuicSocketAddress initial_self_address,
QuicSocketAddress initial_peer_address,
- QuicConnectionHelperInterface* helper,
- QuicAlarmFactory* alarm_factory,
- QuicPacketWriter* writer,
- bool owns_writer,
- Perspective perspective,
+ QuicConnectionHelperInterface* helper, QuicAlarmFactory* alarm_factory,
+ QuicPacketWriter* writer, bool owns_writer, Perspective perspective,
const ParsedQuicVersionVector& supported_versions)
- : framer_(supported_versions,
- helper->GetClock()->ApproximateNow(),
- perspective,
- server_connection_id.length()),
+ : framer_(supported_versions, helper->GetClock()->ApproximateNow(),
+ perspective, server_connection_id.length()),
current_packet_content_(NO_FRAMES_RECEIVED),
is_current_packet_connectivity_probing_(false),
has_path_challenge_in_current_packet_(false),
@@ -239,8 +239,7 @@ QuicConnection::QuicConnection(
random_generator_(helper->GetRandomGenerator()),
client_connection_id_is_set_(false),
direct_peer_address_(initial_peer_address),
- default_path_(initial_self_address,
- QuicSocketAddress(),
+ default_path_(initial_self_address, QuicSocketAddress(),
/*client_connection_id=*/EmptyQuicConnectionId(),
server_connection_id,
/*stateless_reset_token_received=*/false,
@@ -269,23 +268,17 @@ QuicConnection::QuicConnection(
ack_alarm_(alarm_factory_->CreateAlarm(arena_.New<AckAlarmDelegate>(this),
&arena_)),
retransmission_alarm_(alarm_factory_->CreateAlarm(
- arena_.New<RetransmissionAlarmDelegate>(this),
- &arena_)),
- send_alarm_(
- alarm_factory_->CreateAlarm(arena_.New<SendAlarmDelegate>(this),
- &arena_)),
- ping_alarm_(
- alarm_factory_->CreateAlarm(arena_.New<PingAlarmDelegate>(this),
- &arena_)),
+ arena_.New<RetransmissionAlarmDelegate>(this), &arena_)),
+ send_alarm_(alarm_factory_->CreateAlarm(
+ arena_.New<SendAlarmDelegate>(this), &arena_)),
+ ping_alarm_(alarm_factory_->CreateAlarm(
+ arena_.New<PingAlarmDelegate>(this), &arena_)),
mtu_discovery_alarm_(alarm_factory_->CreateAlarm(
- arena_.New<MtuDiscoveryAlarmDelegate>(this),
- &arena_)),
+ arena_.New<MtuDiscoveryAlarmDelegate>(this), &arena_)),
process_undecryptable_packets_alarm_(alarm_factory_->CreateAlarm(
- arena_.New<ProcessUndecryptablePacketsAlarmDelegate>(this),
- &arena_)),
+ arena_.New<ProcessUndecryptablePacketsAlarmDelegate>(this), &arena_)),
discard_previous_one_rtt_keys_alarm_(alarm_factory_->CreateAlarm(
- arena_.New<DiscardPreviousOneRttKeysAlarmDelegate>(this),
- &arena_)),
+ arena_.New<DiscardPreviousOneRttKeysAlarmDelegate>(this), &arena_)),
discard_zero_rtt_decryption_keys_alarm_(alarm_factory_->CreateAlarm(
arena_.New<DiscardZeroRttDecryptionKeysAlarmDelegate>(this),
&arena_)),
@@ -293,10 +286,7 @@ QuicConnection::QuicConnection(
debug_visitor_(nullptr),
packet_creator_(server_connection_id, &framer_, random_generator_, this),
last_received_packet_info_(clock_->ApproximateNow()),
- sent_packet_manager_(perspective,
- clock_,
- random_generator_,
- &stats_,
+ sent_packet_manager_(perspective, clock_, random_generator_, &stats_,
GetDefaultCongestionControlType()),
version_negotiated_(false),
perspective_(perspective),
@@ -319,12 +309,11 @@ QuicConnection::QuicConnection(
processing_ack_frame_(false),
supports_release_time_(false),
release_time_into_future_(QuicTime::Delta::Zero()),
- blackhole_detector_(this, &arena_, alarm_factory_),
- idle_network_detector_(this,
- clock_->ApproximateNow(),
- &arena_,
- alarm_factory_),
- path_validator_(alarm_factory_, &arena_, this, random_generator_),
+ blackhole_detector_(this, &arena_, alarm_factory_, &context_),
+ idle_network_detector_(this, clock_->ApproximateNow(), &arena_,
+ alarm_factory_, &context_),
+ path_validator_(alarm_factory_, &arena_, this, random_generator_,
+ &context_),
most_recent_frame_type_(NUM_FRAME_TYPES) {
QUICHE_DCHECK(perspective_ == Perspective::IS_CLIENT ||
default_path_.self_address.IsInitialized());
@@ -335,10 +324,8 @@ QuicConnection::QuicConnection(
support_multiple_connection_ids_ =
version().HasIetfQuicFrames() &&
- GetQuicRestartFlag(quic_time_wait_list_support_multiple_cid_v2) &&
GetQuicRestartFlag(
- quic_dispatcher_support_multiple_cid_per_connection_v2) &&
- GetQuicReloadableFlag(quic_connection_support_multiple_cids_v4);
+ quic_dispatcher_support_multiple_cid_per_connection_v2);
QUIC_DLOG(INFO) << ENDPOINT << "Created connection with server connection ID "
<< server_connection_id
@@ -535,8 +522,8 @@ void QuicConnection::SetFromConfig(const QuicConfig& config) {
} else {
SetNetworkTimeouts(config.max_time_before_crypto_handshake(),
config.max_idle_time_before_crypto_handshake());
- if (config.HasClientRequestedIndependentOption(kCHSP, perspective_)) {
- packet_creator_.set_chaos_protection_enabled(true);
+ if (config.HasClientRequestedIndependentOption(kNCHP, perspective_)) {
+ packet_creator_.set_chaos_protection_enabled(false);
}
}
@@ -650,10 +637,17 @@ void QuicConnection::SetFromConfig(const QuicConfig& config) {
if (config.HasClientSentConnectionOption(kDFER, perspective_)) {
defer_send_in_response_to_packets_ = false;
}
+ const bool remove_connection_migration_connection_option =
+ GetQuicReloadableFlag(quic_remove_connection_migration_connection_option);
+ if (remove_connection_migration_connection_option) {
+ QUIC_RELOADABLE_FLAG_COUNT(
+ quic_remove_connection_migration_connection_option);
+ }
if (framer_.version().HasIetfQuicFrames() && use_path_validator_ &&
count_bytes_on_alternative_path_separately_ &&
GetQuicReloadableFlag(quic_server_reverse_validate_new_path3) &&
- config.HasClientSentConnectionOption(kRVCM, perspective_)) {
+ (remove_connection_migration_connection_option ||
+ config.HasClientSentConnectionOption(kRVCM, perspective_))) {
QUIC_CODE_COUNT_N(quic_server_reverse_validate_new_path3, 6, 6);
validate_client_addresses_ = true;
}
@@ -664,7 +658,6 @@ void QuicConnection::SetFromConfig(const QuicConfig& config) {
// 2) Client side's rollout can be protected by the same connection option.
connection_migration_use_new_cid_ =
support_multiple_connection_ids_ && validate_client_addresses_ &&
- group_path_response_and_challenge_sending_closer_ &&
GetQuicReloadableFlag(quic_drop_unsent_path_response) &&
GetQuicReloadableFlag(quic_connection_migration_use_new_cid_v2);
if (config.HasReceivedMaxPacketSize()) {
@@ -1705,17 +1698,8 @@ bool QuicConnection::OnPathChallengeFrame(const QuicPathChallengeFrame& frame) {
}
QUIC_CODE_COUNT_N(quic_server_reverse_validate_new_path3, 1, 6);
{
- // UpdatePacketStateAndReplyPathChallenge() may start reverse path
- // validation, if so bundle the PATH_CHALLENGE together with the
- // PATH_RESPONSE. This context needs to be out of scope before returning.
// TODO(danzh) inline OnPathChallengeFrameInternal() once
- // support_reverse_path_validation_ is deprecated.
- auto context =
- group_path_response_and_challenge_sending_closer_
- ? nullptr
- : std::make_unique<QuicPacketCreator::ScopedPeerAddressContext>(
- &packet_creator_, last_received_packet_info_.source_address,
- /*update_connection_id=*/false);
+ // validate_client_addresses_ is deprecated.
if (!OnPathChallengeFrameInternal(frame)) {
return false;
}
@@ -1734,21 +1718,16 @@ bool QuicConnection::OnPathChallengeFrameInternal(
debug_visitor_->OnPathChallengeFrame(frame);
}
- std::unique_ptr<QuicPacketCreator::ScopedPeerAddressContext> context;
const QuicSocketAddress current_effective_peer_address =
GetEffectivePeerAddressFromCurrentPacket();
- if (group_path_response_and_challenge_sending_closer_) {
- QuicConnectionId client_cid, server_cid;
- FindOnPathConnectionIds(last_received_packet_info_.destination_address,
- current_effective_peer_address, &client_cid,
- &server_cid);
- context = std::make_unique<QuicPacketCreator::ScopedPeerAddressContext>(
- &packet_creator_, last_received_packet_info_.source_address, client_cid,
- server_cid, connection_migration_use_new_cid_);
- }
+ QuicConnectionId client_cid, server_cid;
+ FindOnPathConnectionIds(last_received_packet_info_.destination_address,
+ current_effective_peer_address, &client_cid,
+ &server_cid);
+ QuicPacketCreator::ScopedPeerAddressContext context(
+ &packet_creator_, last_received_packet_info_.source_address, client_cid,
+ server_cid, connection_migration_use_new_cid_);
if (should_proactively_validate_peer_address_on_path_challenge_) {
- QUIC_RELOADABLE_FLAG_COUNT(
- quic_group_path_response_and_challenge_sending_closer);
// Conditions to proactively validate peer address:
// The perspective is server
// The PATH_CHALLENGE is received on an unvalidated alternative path.
@@ -2042,11 +2021,7 @@ bool QuicConnection::OnNewConnectionIdFrameInner(
if (perspective_ == Perspective::IS_SERVER) {
OnClientConnectionIdAvailable();
}
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_connection_support_multiple_cids_v4, 1, 2);
- if (ack_cid_frames_) {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_ack_cid_frames, 1, 2);
- MaybeUpdateAckTimeout();
- }
+ MaybeUpdateAckTimeout();
return true;
}
@@ -2104,13 +2079,9 @@ bool QuicConnection::OnRetireConnectionIdFrame(
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
return false;
}
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_connection_support_multiple_cids_v4, 2, 2);
// Count successfully received RETIRE_CONNECTION_ID frames.
QUIC_RELOADABLE_FLAG_COUNT_N(quic_connection_migration_use_new_cid_v2, 5, 6);
- if (ack_cid_frames_) {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_ack_cid_frames, 2, 2);
- MaybeUpdateAckTimeout();
- }
+ MaybeUpdateAckTimeout();
return true;
}
@@ -2717,19 +2688,12 @@ void QuicConnection::OnUndecryptablePacket(const QuicEncryptedPacket& packet,
bool QuicConnection::ShouldEnqueueUnDecryptablePacket(
EncryptionLevel decryption_level, bool has_decryption_key) const {
- if (!GetQuicReloadableFlag(quic_queue_until_handshake_complete) &&
- encryption_level_ == ENCRYPTION_FORWARD_SECURE) {
- // We do not expect to install any further keys.
- return false;
- }
if (has_decryption_key) {
// We already have the key for this decryption level, therefore no
// future keys will allow it be decrypted.
return false;
}
- if (GetQuicReloadableFlag(quic_queue_until_handshake_complete) &&
- IsHandshakeComplete()) {
- QUICHE_RELOADABLE_FLAG_COUNT(quic_queue_until_handshake_complete);
+ if (IsHandshakeComplete()) {
// We do not expect to install any further keys.
return false;
}
@@ -3007,7 +2971,7 @@ void QuicConnection::ReplaceInitialServerConnectionId(
peer_issued_cid_manager_ =
std::make_unique<QuicPeerIssuedConnectionIdManager>(
kMinNumOfActiveConnectionIds, new_server_connection_id, clock_,
- alarm_factory_, this);
+ alarm_factory_, this, context());
}
}
}
@@ -3158,7 +3122,11 @@ bool QuicConnection::ProcessValidatedPacket(const QuicPacketHeader& header) {
if (perspective_ == Perspective::IS_SERVER &&
encryption_level_ == ENCRYPTION_INITIAL &&
last_size_ > packet_creator_.max_packet_length()) {
- SetMaxPacketLength(last_size_);
+ if (GetQuicFlag(FLAGS_quic_use_lower_server_response_mtu_for_test)) {
+ SetMaxPacketLength(std::min(last_size_, QuicByteCount(1250)));
+ } else {
+ SetMaxPacketLength(last_size_);
+ }
}
return true;
}
@@ -3334,6 +3302,20 @@ bool QuicConnection::CanWrite(HasRetransmittableData retransmittable) {
return false;
}
+ if (GetQuicReloadableFlag(quic_suppress_write_mid_packet_processing) &&
+ version().CanSendCoalescedPackets() &&
+ framer_.HasEncrypterOfEncryptionLevel(ENCRYPTION_INITIAL) &&
+ framer_.is_processing_packet()) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_suppress_write_mid_packet_processing);
+ // While we still have initial keys, suppress sending in mid of packet
+ // processing.
+ // TODO(fayang): always suppress sending while in the mid of packet
+ // processing.
+ QUIC_DVLOG(1) << ENDPOINT
+ << "Suppress sending in the mid of packet processing";
+ return false;
+ }
+
if (fill_coalesced_packet_) {
// Try to coalesce packet, only allow to write when creator is on soft max
// packet length. Given the next created packet is going to fill current
@@ -4080,7 +4062,7 @@ QuicConnection::MakeSelfIssuedConnectionIdManager() {
perspective_ == Perspective::IS_CLIENT
? default_path_.client_connection_id
: default_path_.server_connection_id,
- clock_, alarm_factory_, this);
+ clock_, alarm_factory_, this, context());
}
void QuicConnection::MaybeSendConnectionIdToClient() {
@@ -4489,10 +4471,17 @@ void QuicConnection::MaybeProcessUndecryptablePackets() {
iter = undecryptable_packets_.erase(iter);
}
- // Once forward secure encryption is in use, there will be no
- // new keys installed and hence any undecryptable packets will
- // never be able to be decrypted.
- if (encryption_level_ == ENCRYPTION_FORWARD_SECURE) {
+ // Once handshake is complete, there will be no new keys installed and hence
+ // any undecryptable packets will never be able to be decrypted.
+ bool clear_undecryptable_packets =
+ encryption_level_ == ENCRYPTION_FORWARD_SECURE;
+ if (GetQuicReloadableFlag(
+ quic_clear_undecryptable_packets_on_handshake_complete)) {
+ QUIC_RELOADABLE_FLAG_COUNT(
+ quic_clear_undecryptable_packets_on_handshake_complete);
+ clear_undecryptable_packets = IsHandshakeComplete();
+ }
+ if (clear_undecryptable_packets) {
if (debug_visitor_ != nullptr) {
for (const auto& undecryptable_packet : undecryptable_packets_) {
debug_visitor_->OnUndecryptablePacket(
@@ -5299,14 +5288,13 @@ void QuicConnection::StartEffectivePeerMigration(AddressChangeType type) {
<< "EffectivePeerMigration started without address change.";
return;
}
+ // There could be pending NEW_TOKEN_FRAME triggered by non-probing
+ // PATH_RESPONSE_FRAME in the same packet.
if (packet_creator_.HasPendingFrames()) {
- QUIC_BUG(bug_731_2)
- << "Starts effective peer migration with pending frame types: "
- << packet_creator_.GetPendingFramesInfo() << ". Address change type is "
- << AddressChangeTypeToString(type)
- << ". Current frame type: " << framer_.current_received_frame_type()
- << ". Previous frame type: "
- << framer_.previously_received_frame_type();
+ packet_creator_.FlushCurrentPacket();
+ if (!connected_) {
+ return;
+ }
}
// Action items:
@@ -5363,17 +5351,18 @@ void QuicConnection::StartEffectivePeerMigration(AddressChangeType type) {
std::move(alternative_path_.rtt_stats).value());
}
}
-
- // Update to the new peer address.
- if (packet_creator_.HasPendingFrames()) {
- QUIC_BUG(bug_731_1)
+ if (packet_creator_.HasPendingFrames() ||
+ packet_creator_.pending_padding_bytes() > 0) {
+ QUIC_BUG(quic_bug_5196)
<< "Starts effective peer migration with pending frame types: "
- << packet_creator_.GetPendingFramesInfo() << ". Address change type is "
- << AddressChangeTypeToString(type)
+ << packet_creator_.GetPendingFramesInfo() << ". pending_padding_bytes: "
+ << packet_creator_.pending_padding_bytes()
+ << ". Address change type is " << AddressChangeTypeToString(type)
<< ". Current frame type: " << framer_.current_received_frame_type()
<< ". Previous frame type: "
<< framer_.previously_received_frame_type();
}
+ // Update to the new peer address.
UpdatePeerAddress(last_received_packet_info_.source_address);
// Update the default path.
if (IsAlternativePath(last_received_packet_info_.destination_address,
@@ -5641,24 +5630,7 @@ bool QuicConnection::UpdatePacketContent(QuicFrameType type) {
current_effective_peer_address, client_connection_id,
last_packet_destination_connection_id_,
stateless_reset_token_received, stateless_reset_token);
- if (group_path_response_and_challenge_sending_closer_) {
- should_proactively_validate_peer_address_on_path_challenge_ = true;
- } else {
- // Conditions to proactively validate peer address:
- // The perspective is server
- // The PATH_CHALLENGE is received on an unvalidated alternative path.
- // The connection isn't validating migrated peer address, which is of
- // higher prority.
- QUIC_DVLOG(1) << "Proactively validate the effective peer address "
- << current_effective_peer_address;
- QUIC_CODE_COUNT_N(quic_kick_off_client_address_validation, 1, 6);
- ValidatePath(std::make_unique<ReversePathValidationContext>(
- default_path_.self_address,
- last_received_packet_info_.source_address,
- current_effective_peer_address, this),
- std::make_unique<ReversePathValidationResultDelegate>(
- this, peer_address()));
- }
+ should_proactively_validate_peer_address_on_path_challenge_ = true;
}
}
MaybeUpdateBytesReceivedFromAlternativeAddress(last_size_);
@@ -6075,6 +6047,9 @@ bool QuicConnection::FlushCoalescedPacket() {
if (length == 0) {
return false;
}
+ if (debug_visitor_ != nullptr) {
+ debug_visitor_->OnCoalescedPacketSent(coalesced_packet_, length);
+ }
QUIC_DVLOG(1) << ENDPOINT << "Sending coalesced packet "
<< coalesced_packet_.ToString(length);
@@ -6084,9 +6059,6 @@ bool QuicConnection::FlushCoalescedPacket() {
buffered_packets_.emplace_back(
buffer, static_cast<QuicPacketLength>(length),
coalesced_packet_.self_address(), coalesced_packet_.peer_address());
- if (debug_visitor_ != nullptr) {
- debug_visitor_->OnCoalescedPacketSent(coalesced_packet_, length);
- }
return true;
}
@@ -6107,9 +6079,6 @@ bool QuicConnection::FlushCoalescedPacket() {
coalesced_packet_.self_address(), coalesced_packet_.peer_address());
}
}
- if (debug_visitor_ != nullptr) {
- debug_visitor_->OnCoalescedPacketSent(coalesced_packet_, length);
- }
// Account for added padding.
if (length > coalesced_packet_.length()) {
size_t padding_size = length - coalesced_packet_.length();
@@ -6167,7 +6136,7 @@ void QuicConnection::SetLargestReceivedPacketWithAck(
}
void QuicConnection::OnForwardProgressMade() {
- if (GetQuicRestartFlag(quic_alarm_add_permanent_cancel) && !connected_) {
+ if (!connected_) {
return;
}
if (is_path_degrading_) {
@@ -6298,7 +6267,7 @@ void QuicConnection::set_client_connection_id(
peer_issued_cid_manager_ =
std::make_unique<QuicPeerIssuedConnectionIdManager>(
kMinNumOfActiveConnectionIds, client_connection_id, clock_,
- alarm_factory_, this);
+ alarm_factory_, this, context());
} else {
// Note in Chromium client, set_client_connection_id is not called and
// thus self_issued_cid_manager_ should be null.
@@ -6872,6 +6841,24 @@ void QuicConnection::OnPathValidationFailureAtClient() {
RetirePeerIssuedConnectionIdsNoLongerOnPath();
}
+QuicConnectionId QuicConnection::GetOneActiveServerConnectionId() const {
+ if (perspective_ == Perspective::IS_CLIENT ||
+ self_issued_cid_manager_ == nullptr) {
+ return connection_id();
+ }
+ auto active_connection_ids = GetActiveServerConnectionIds();
+ QUIC_BUG_IF(quic_bug_6944, active_connection_ids.empty());
+ if (active_connection_ids.empty() ||
+ std::find(active_connection_ids.begin(), active_connection_ids.end(),
+ connection_id()) != active_connection_ids.end()) {
+ return connection_id();
+ }
+ QUICHE_CODE_COUNT(connection_id_on_default_path_has_been_retired);
+ auto active_connection_id =
+ self_issued_cid_manager_->GetOneActiveConnectionId();
+ return active_connection_id;
+}
+
std::vector<QuicConnectionId> QuicConnection::GetActiveServerConnectionIds()
const {
if (!support_multiple_connection_ids_ ||
@@ -6891,7 +6878,7 @@ void QuicConnection::CreateConnectionIdManager() {
peer_issued_cid_manager_ =
std::make_unique<QuicPeerIssuedConnectionIdManager>(
kMinNumOfActiveConnectionIds, default_path_.server_connection_id,
- clock_, alarm_factory_, this);
+ clock_, alarm_factory_, this, context());
}
} else {
if (!default_path_.server_connection_id.IsEmpty()) {
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 dea513a1768..5d8ff2717ca 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
@@ -263,10 +263,9 @@ class QUIC_EXPORT_PRIVATE QuicConnectionDebugVisitor
const QuicFrames& /*nonretransmittable_frames*/,
QuicTime /*sent_time*/) {}
- // Called when a coalesced packet has been sent.
+ // Called when a coalesced packet is successfully serialized.
virtual void OnCoalescedPacketSent(
- const QuicCoalescedPacket& /*coalesced_packet*/,
- size_t /*length*/) {}
+ const QuicCoalescedPacket& /*coalesced_packet*/, size_t /*length*/) {}
// Called when a PING frame has been sent.
virtual void OnPingSent() {}
@@ -778,9 +777,12 @@ class QUIC_EXPORT_PRIVATE QuicConnection
const QuicSocketAddress& effective_peer_address() const {
return default_path_.peer_address;
}
+
+ // Returns the server connection ID used on the default path.
const QuicConnectionId& connection_id() const {
return default_path_.server_connection_id;
}
+
const QuicConnectionId& client_connection_id() const {
return default_path_.client_connection_id;
}
@@ -1225,6 +1227,12 @@ class QUIC_EXPORT_PRIVATE QuicConnection
SendPingAtLevel(framer().GetEncryptionLevelToSendApplicationData());
}
+ // Returns one server connection ID that associates the current session in the
+ // session map.
+ virtual QuicConnectionId GetOneActiveServerConnectionId() const;
+
+ // Returns all server connection IDs that have not been removed from the
+ // session map.
virtual std::vector<QuicConnectionId> GetActiveServerConnectionIds() const;
bool validate_client_address() const { return validate_client_addresses_; }
@@ -2267,18 +2275,12 @@ class QUIC_EXPORT_PRIVATE QuicConnection
// Enable this via reloadable flag once this feature is complete.
bool connection_migration_use_new_cid_ = false;
- const bool group_path_response_and_challenge_sending_closer_ =
- GetQuicReloadableFlag(
- quic_group_path_response_and_challenge_sending_closer);
-
const bool reset_per_packet_state_for_undecryptable_packets_ =
GetQuicReloadableFlag(
quic_reset_per_packet_state_for_undecryptable_packets);
const bool add_missing_update_ack_timeout_ =
GetQuicReloadableFlag(quic_add_missing_update_ack_timeout);
-
- const bool ack_cid_frames_ = GetQuicReloadableFlag(quic_ack_cid_frames);
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_connection_id_manager.cc b/chromium/net/third_party/quiche/src/quic/core/quic_connection_id_manager.cc
index f7089b7ebfd..1138a2ed5d4 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_connection_id_manager.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_connection_id_manager.cc
@@ -3,12 +3,14 @@
// found in the LICENSE file.
#include "quic/core/quic_connection_id_manager.h"
+
#include <cstdio>
#include "quic/core/quic_clock.h"
#include "quic/core/quic_connection_id.h"
#include "quic/core/quic_error_codes.h"
#include "quic/core/quic_utils.h"
+#include "common/platform/api/quiche_logging.h"
namespace quic {
@@ -22,11 +24,13 @@ QuicConnectionIdData::QuicConnectionIdData(
namespace {
-class RetirePeerIssuedConnectionIdAlarm : public QuicAlarm::Delegate {
+class RetirePeerIssuedConnectionIdAlarm
+ : public QuicAlarm::DelegateWithContext {
public:
explicit RetirePeerIssuedConnectionIdAlarm(
- QuicConnectionIdManagerVisitorInterface* visitor)
- : visitor_(visitor) {}
+ QuicConnectionIdManagerVisitorInterface* visitor,
+ QuicConnectionContext* context)
+ : QuicAlarm::DelegateWithContext(context), visitor_(visitor) {}
RetirePeerIssuedConnectionIdAlarm(const RetirePeerIssuedConnectionIdAlarm&) =
delete;
RetirePeerIssuedConnectionIdAlarm& operator=(
@@ -61,13 +65,13 @@ std::vector<QuicConnectionIdData>::iterator FindConnectionIdData(
QuicPeerIssuedConnectionIdManager::QuicPeerIssuedConnectionIdManager(
size_t active_connection_id_limit,
const QuicConnectionId& initial_peer_issued_connection_id,
- const QuicClock* clock,
- QuicAlarmFactory* alarm_factory,
- QuicConnectionIdManagerVisitorInterface* visitor)
+ const QuicClock* clock, QuicAlarmFactory* alarm_factory,
+ QuicConnectionIdManagerVisitorInterface* visitor,
+ QuicConnectionContext* context)
: active_connection_id_limit_(active_connection_id_limit),
clock_(clock),
retire_connection_id_alarm_(alarm_factory->CreateAlarm(
- new RetirePeerIssuedConnectionIdAlarm(visitor))) {
+ new RetirePeerIssuedConnectionIdAlarm(visitor, context))) {
QUICHE_DCHECK_GE(active_connection_id_limit_, 2u);
QUICHE_DCHECK(!initial_peer_issued_connection_id.IsEmpty());
active_connection_id_data_.emplace_back<const QuicConnectionId&, uint64_t,
@@ -249,11 +253,14 @@ void QuicPeerIssuedConnectionIdManager::ReplaceConnectionId(
namespace {
-class RetireSelfIssuedConnectionIdAlarmDelegate : public QuicAlarm::Delegate {
+class RetireSelfIssuedConnectionIdAlarmDelegate
+ : public QuicAlarm::DelegateWithContext {
public:
explicit RetireSelfIssuedConnectionIdAlarmDelegate(
- QuicSelfIssuedConnectionIdManager* connection_id_manager)
- : connection_id_manager_(connection_id_manager) {}
+ QuicSelfIssuedConnectionIdManager* connection_id_manager,
+ QuicConnectionContext* context)
+ : QuicAlarm::DelegateWithContext(context),
+ connection_id_manager_(connection_id_manager) {}
RetireSelfIssuedConnectionIdAlarmDelegate(
const RetireSelfIssuedConnectionIdAlarmDelegate&) = delete;
RetireSelfIssuedConnectionIdAlarmDelegate& operator=(
@@ -269,15 +276,15 @@ class RetireSelfIssuedConnectionIdAlarmDelegate : public QuicAlarm::Delegate {
QuicSelfIssuedConnectionIdManager::QuicSelfIssuedConnectionIdManager(
size_t active_connection_id_limit,
- const QuicConnectionId& initial_connection_id,
- const QuicClock* clock,
+ const QuicConnectionId& initial_connection_id, const QuicClock* clock,
QuicAlarmFactory* alarm_factory,
- QuicConnectionIdManagerVisitorInterface* visitor)
+ QuicConnectionIdManagerVisitorInterface* visitor,
+ QuicConnectionContext* context)
: active_connection_id_limit_(active_connection_id_limit),
clock_(clock),
visitor_(visitor),
retire_connection_id_alarm_(alarm_factory->CreateAlarm(
- new RetireSelfIssuedConnectionIdAlarmDelegate(this))),
+ new RetireSelfIssuedConnectionIdAlarmDelegate(this, context))),
last_connection_id_(initial_connection_id),
next_connection_id_sequence_number_(1u),
last_connection_id_consumed_by_self_sequence_number_(0u) {
@@ -372,6 +379,12 @@ QuicSelfIssuedConnectionIdManager::GetUnretiredConnectionIds() const {
return unretired_ids;
}
+QuicConnectionId QuicSelfIssuedConnectionIdManager::GetOneActiveConnectionId()
+ const {
+ QUICHE_DCHECK(!active_connection_ids_.empty());
+ return active_connection_ids_.front().first;
+}
+
void QuicSelfIssuedConnectionIdManager::RetireConnectionId() {
if (to_be_retired_connection_ids_.empty()) {
QUIC_BUG(quic_bug_12420_1)
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_connection_id_manager.h b/chromium/net/third_party/quiche/src/quic/core/quic_connection_id_manager.h
index 5e7fc8ccf72..e23668df2c9 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_connection_id_manager.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_connection_id_manager.h
@@ -60,9 +60,9 @@ class QUIC_EXPORT_PRIVATE QuicPeerIssuedConnectionIdManager {
QuicPeerIssuedConnectionIdManager(
size_t active_connection_id_limit,
const QuicConnectionId& initial_peer_issued_connection_id,
- const QuicClock* clock,
- QuicAlarmFactory* alarm_factory,
- QuicConnectionIdManagerVisitorInterface* visitor);
+ const QuicClock* clock, QuicAlarmFactory* alarm_factory,
+ QuicConnectionIdManagerVisitorInterface* visitor,
+ QuicConnectionContext* context);
~QuicPeerIssuedConnectionIdManager();
@@ -123,10 +123,10 @@ class QUIC_EXPORT_PRIVATE QuicSelfIssuedConnectionIdManager {
public:
QuicSelfIssuedConnectionIdManager(
size_t active_connection_id_limit,
- const QuicConnectionId& initial_connection_id,
- const QuicClock* clock,
+ const QuicConnectionId& initial_connection_id, const QuicClock* clock,
QuicAlarmFactory* alarm_factory,
- QuicConnectionIdManagerVisitorInterface* visitor);
+ QuicConnectionIdManagerVisitorInterface* visitor,
+ QuicConnectionContext* context);
virtual ~QuicSelfIssuedConnectionIdManager();
@@ -139,6 +139,8 @@ class QUIC_EXPORT_PRIVATE QuicSelfIssuedConnectionIdManager {
std::vector<QuicConnectionId> GetUnretiredConnectionIds() const;
+ QuicConnectionId GetOneActiveConnectionId() const;
+
// Called when the retire_connection_id alarm_ fires. Removes the to be
// retired connection ID locally.
void RetireConnectionId();
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_connection_id_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_connection_id_manager_test.cc
index 7baeb2b247e..fdb73daa85b 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_connection_id_manager_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_connection_id_manager_test.cc
@@ -78,11 +78,9 @@ class TestPeerIssuedConnectionIdManagerVisitor
class QuicPeerIssuedConnectionIdManagerTest : public QuicTest {
public:
QuicPeerIssuedConnectionIdManagerTest()
- : peer_issued_cid_manager_(/*active_connection_id_limit=*/2,
- initial_connection_id_,
- &clock_,
- &alarm_factory_,
- &cid_manager_visitor_) {
+ : peer_issued_cid_manager_(
+ /*active_connection_id_limit=*/2, initial_connection_id_, &clock_,
+ &alarm_factory_, &cid_manager_visitor_, /*context=*/nullptr) {
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10));
cid_manager_visitor_.SetPeerIssuedConnectionIdManager(
&peer_issued_cid_manager_);
@@ -538,11 +536,9 @@ class TestSelfIssuedConnectionIdManagerVisitor
class QuicSelfIssuedConnectionIdManagerTest : public QuicTest {
public:
QuicSelfIssuedConnectionIdManagerTest()
- : cid_manager_(/*active_connection_id_limit*/ 2,
- initial_connection_id_,
- &clock_,
- &alarm_factory_,
- &cid_manager_visitor_) {
+ : cid_manager_(/*active_connection_id_limit*/ 2, initial_connection_id_,
+ &clock_, &alarm_factory_, &cid_manager_visitor_,
+ /*context=*/nullptr) {
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10));
retire_self_issued_cid_alarm_ =
QuicConnectionIdManagerPeer::GetRetireSelfIssuedConnectionIdAlarm(
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 69666301c59..e525fd12683 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
@@ -179,33 +179,6 @@ class TestConnectionHelper : public QuicConnectionHelperInterface {
SimpleBufferAllocator buffer_allocator_;
};
-class TestAlarmFactory : public QuicAlarmFactory {
- public:
- class TestAlarm : public QuicAlarm {
- public:
- explicit TestAlarm(QuicArenaScopedPtr<QuicAlarm::Delegate> delegate)
- : QuicAlarm(std::move(delegate)) {}
-
- void SetImpl() override {}
- void CancelImpl() override {}
- using QuicAlarm::Fire;
- };
-
- TestAlarmFactory() {}
- TestAlarmFactory(const TestAlarmFactory&) = delete;
- TestAlarmFactory& operator=(const TestAlarmFactory&) = delete;
-
- QuicAlarm* CreateAlarm(QuicAlarm::Delegate* delegate) override {
- return new TestAlarm(QuicArenaScopedPtr<QuicAlarm::Delegate>(delegate));
- }
-
- QuicArenaScopedPtr<QuicAlarm> CreateAlarm(
- QuicArenaScopedPtr<QuicAlarm::Delegate> delegate,
- QuicConnectionArena* arena) override {
- return arena->New<TestAlarm>(std::move(delegate));
- }
-};
-
class TestConnection : public QuicConnection {
public:
TestConnection(QuicConnectionId connection_id,
@@ -826,10 +799,10 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> {
level);
}
- void ProcessFramesPacketWithAddresses(QuicFrames frames,
- QuicSocketAddress self_address,
- QuicSocketAddress peer_address,
- EncryptionLevel level) {
+ std::unique_ptr<QuicReceivedPacket> ConstructPacket(QuicFrames frames,
+ EncryptionLevel level,
+ char* buffer,
+ size_t buffer_len) {
QUICHE_DCHECK(peer_framer_.HasEncrypterOfEncryptionLevel(level));
peer_creator_.set_encryption_level(level);
QuicPacketCreatorPeer::SetSendVersionInPacket(
@@ -837,14 +810,23 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> {
level < ENCRYPTION_FORWARD_SECURE &&
connection_.perspective() == Perspective::IS_SERVER);
- char buffer[kMaxOutgoingPacketSize];
SerializedPacket serialized_packet =
- QuicPacketCreatorPeer::SerializeAllFrames(
- &peer_creator_, frames, buffer, kMaxOutgoingPacketSize);
+ QuicPacketCreatorPeer::SerializeAllFrames(&peer_creator_, frames,
+ buffer, buffer_len);
+ return std::make_unique<QuicReceivedPacket>(
+ serialized_packet.encrypted_buffer, serialized_packet.encrypted_length,
+ clock_.Now());
+ }
+
+ void ProcessFramesPacketWithAddresses(QuicFrames frames,
+ QuicSocketAddress self_address,
+ QuicSocketAddress peer_address,
+ EncryptionLevel level) {
+ char buffer[kMaxOutgoingPacketSize];
connection_.ProcessUdpPacket(
self_address, peer_address,
- QuicReceivedPacket(serialized_packet.encrypted_buffer,
- serialized_packet.encrypted_length, clock_.Now()));
+ *ConstructPacket(std::move(frames), level, buffer,
+ kMaxOutgoingPacketSize));
if (connection_.GetSendAlarm()->IsSet()) {
connection_.GetSendAlarm()->Fire();
}
@@ -1338,12 +1320,15 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> {
void set_perspective(Perspective perspective) {
connection_.set_perspective(perspective);
if (perspective == Perspective::IS_SERVER) {
- QuicConfig config;
- QuicTagVector connection_options;
- connection_options.push_back(kRVCM);
- config.SetInitialReceivedConnectionOptions(connection_options);
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
- connection_.SetFromConfig(config);
+ if (!GetQuicReloadableFlag(
+ quic_remove_connection_migration_connection_option)) {
+ QuicConfig config;
+ QuicTagVector connection_options;
+ connection_options.push_back(kRVCM);
+ config.SetInitialReceivedConnectionOptions(connection_options);
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ connection_.SetFromConfig(config);
+ }
connection_.set_can_truncate_connection_ids(true);
QuicConnectionPeer::SetNegotiatedVersion(&connection_);
@@ -1442,6 +1427,9 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> {
}
connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
peer_creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE);
+ // Discard INITIAL key.
+ connection_.RemoveEncrypter(ENCRYPTION_INITIAL);
+ connection_.NeuterUnencryptedPackets();
// Prevent packets from being coalesced.
EXPECT_CALL(visitor_, GetHandshakeState())
.WillRepeatedly(Return(HANDSHAKE_CONFIRMED));
@@ -1753,6 +1741,9 @@ TEST_P(QuicConnectionTest, PeerIpAddressChangeAtServer) {
QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false);
EXPECT_EQ(Perspective::IS_SERVER, connection_.perspective());
connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+ // Discard INITIAL key.
+ connection_.RemoveEncrypter(ENCRYPTION_INITIAL);
+ connection_.NeuterUnencryptedPackets();
// Prevent packets from being coalesced.
EXPECT_CALL(visitor_, GetHandshakeState())
.WillRepeatedly(Return(HANDSHAKE_CONFIRMED));
@@ -1966,6 +1957,9 @@ TEST_P(QuicConnectionTest, EffectivePeerAddressChangeAtServer) {
QuicConnectionPeer::SetAddressValidated(&connection_);
}
connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+ // Discard INITIAL key.
+ connection_.RemoveEncrypter(ENCRYPTION_INITIAL);
+ connection_.NeuterUnencryptedPackets();
EXPECT_CALL(visitor_, GetHandshakeState())
.WillRepeatedly(Return(HANDSHAKE_CONFIRMED));
@@ -2073,6 +2067,66 @@ TEST_P(QuicConnectionTest, EffectivePeerAddressChangeAtServer) {
}
}
+// Regression test for b/196208556.
+TEST_P(QuicConnectionTest,
+ ReversePathValidationResponseReceivedFromUnexpectedPeerAddress) {
+ set_perspective(Perspective::IS_SERVER);
+ if (!connection_.connection_migration_use_new_cid()) {
+ return;
+ }
+ QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false);
+ connection_.CreateConnectionIdManager();
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+ QuicConnectionPeer::SetPeerAddress(&connection_, kPeerAddress);
+ QuicConnectionPeer::SetEffectivePeerAddress(&connection_, kPeerAddress);
+ QuicConnectionPeer::SetAddressValidated(&connection_);
+ EXPECT_EQ(kPeerAddress, connection_.peer_address());
+ EXPECT_EQ(kPeerAddress, connection_.effective_peer_address());
+
+ // Sends new server CID to client.
+ QuicConnectionId new_cid;
+ EXPECT_CALL(visitor_, OnServerConnectionIdIssued(_))
+ .WillOnce(Invoke([&](const QuicConnectionId& cid) { new_cid = cid; }));
+ EXPECT_CALL(visitor_, SendNewConnectionId(_));
+ // Discard INITIAL key.
+ connection_.RemoveEncrypter(ENCRYPTION_INITIAL);
+ connection_.NeuterUnencryptedPackets();
+ connection_.OnHandshakeComplete();
+ EXPECT_CALL(visitor_, GetHandshakeState())
+ .WillRepeatedly(Return(HANDSHAKE_CONFIRMED));
+
+ // Process a non-probing packet to migrate to path 2 and kick off reverse path
+ // validation.
+ EXPECT_CALL(visitor_, OnConnectionMigration(IPV6_TO_IPV4_CHANGE)).Times(1);
+ const QuicSocketAddress kPeerAddress2 =
+ QuicSocketAddress(QuicIpAddress::Loopback4(), /*port=*/23456);
+ peer_creator_.SetServerConnectionId(new_cid);
+ ProcessFramesPacketWithAddresses({QuicFrame(QuicPingFrame())}, kSelfAddress,
+ kPeerAddress2, ENCRYPTION_FORWARD_SECURE);
+ EXPECT_FALSE(writer_->path_challenge_frames().empty());
+ QuicPathFrameBuffer reverse_path_challenge_payload =
+ writer_->path_challenge_frames().front().data_buffer;
+
+ // Receiveds a packet from path 3 with PATH_RESPONSE frame intended to
+ // validate path 2 and a non-probing frame.
+ {
+ QuicConnection::ScopedPacketFlusher flusher(&connection_);
+ const QuicSocketAddress kPeerAddress3 =
+ QuicSocketAddress(QuicIpAddress::Loopback6(), /*port=*/56789);
+ auto ack_frame = InitAckFrame(1);
+ EXPECT_CALL(visitor_, OnConnectionMigration(IPV4_TO_IPV6_CHANGE)).Times(1);
+ EXPECT_CALL(visitor_, MaybeSendAddressToken()).WillOnce(Invoke([this]() {
+ connection_.SendControlFrame(
+ QuicFrame(new QuicNewTokenFrame(1, "new_token")));
+ }));
+ ProcessFramesPacketWithAddresses({QuicFrame(new QuicPathResponseFrame(
+ 0, reverse_path_challenge_payload)),
+ QuicFrame(&ack_frame)},
+ kSelfAddress, kPeerAddress3,
+ ENCRYPTION_FORWARD_SECURE);
+ }
+}
+
TEST_P(QuicConnectionTest, ReversePathValidationFailureAtServer) {
set_perspective(Perspective::IS_SERVER);
if (!connection_.connection_migration_use_new_cid()) {
@@ -2083,6 +2137,9 @@ TEST_P(QuicConnectionTest, ReversePathValidationFailureAtServer) {
SetClientConnectionId(TestConnectionId(1));
connection_.CreateConnectionIdManager();
connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+ // Discard INITIAL key.
+ connection_.RemoveEncrypter(ENCRYPTION_INITIAL);
+ connection_.NeuterUnencryptedPackets();
// Prevent packets from being coalesced.
EXPECT_CALL(visitor_, GetHandshakeState())
.WillRepeatedly(Return(HANDSHAKE_CONFIRMED));
@@ -2739,7 +2796,7 @@ TEST_P(QuicConnectionTest, PeerAddressChangeAtClient) {
TEST_P(QuicConnectionTest, MaxPacketSize) {
EXPECT_EQ(Perspective::IS_CLIENT, connection_.perspective());
- EXPECT_EQ(1350u, connection_.max_packet_length());
+ EXPECT_EQ(1250u, connection_.max_packet_length());
}
TEST_P(QuicConnectionTest, PeerLowersMaxPacketSize) {
@@ -2776,6 +2833,18 @@ TEST_P(QuicConnectionTest, SmallerServerMaxPacketSize) {
EXPECT_EQ(1000u, connection.max_packet_length());
}
+TEST_P(QuicConnectionTest, LowerServerResponseMtuTest) {
+ set_perspective(Perspective::IS_SERVER);
+ connection_.SetMaxPacketLength(1000);
+ EXPECT_EQ(1000u, connection_.max_packet_length());
+
+ SetQuicFlag(FLAGS_quic_use_lower_server_response_mtu_for_test, true);
+ EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(::testing::AtMost(1));
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(::testing::AtMost(1));
+ ProcessCryptoPacketAtLevel(1, ENCRYPTION_INITIAL);
+ EXPECT_EQ(1250u, connection_.max_packet_length());
+}
+
TEST_P(QuicConnectionTest, IncreaseServerMaxPacketSize) {
set_perspective(Perspective::IS_SERVER);
connection_.SetMaxPacketLength(1000);
@@ -3706,7 +3775,7 @@ TEST_P(QuicConnectionTest, LargeSendWithPendingAck) {
EXPECT_TRUE(connection_.HasPendingAcks());
// Send data and ensure the ack is bundled.
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(8);
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(9);
size_t len = 10000;
std::unique_ptr<char[]> data_array(new char[len]);
memset(data_array.get(), '?', len);
@@ -6485,7 +6554,6 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationUnlimitedAggregation) {
EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
QuicConfig config;
QuicTagVector connection_options;
- connection_options.push_back(kACKD);
// No limit on the number of packets received before sending an ack.
connection_options.push_back(kAKDU);
config.SetConnectionOptionsToSend(connection_options);
@@ -8816,7 +8884,7 @@ TEST_P(QuicConnectionTest, GetCurrentLargestMessagePayload) {
// that the encryption overhead is constant across versions.
connection_.SetEncrypter(ENCRYPTION_INITIAL,
std::make_unique<TaggingEncrypter>(0x00));
- QuicPacketLength expected_largest_payload = 1319;
+ QuicPacketLength expected_largest_payload = 1219;
if (connection_.version().SendsVariableLengthPacketNumberInLongHeader()) {
expected_largest_payload += 3;
}
@@ -8851,7 +8919,7 @@ TEST_P(QuicConnectionTest, GetGuaranteedLargestMessagePayload) {
// that the encryption overhead is constant across versions.
connection_.SetEncrypter(ENCRYPTION_INITIAL,
std::make_unique<TaggingEncrypter>(0x00));
- QuicPacketLength expected_largest_payload = 1319;
+ QuicPacketLength expected_largest_payload = 1219;
if (connection_.version().HasLongHeaderLengths()) {
expected_largest_payload -= 2;
}
@@ -10026,12 +10094,13 @@ TEST_P(QuicConnectionTest, AntiAmplificationLimit) {
EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
// Receives packet 1.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
ProcessCryptoPacketAtLevel(1, ENCRYPTION_INITIAL);
const size_t anti_amplification_factor =
GetQuicFlag(FLAGS_quic_anti_amplification_factor);
// Verify now packets can be sent.
- for (size_t i = 0; i < anti_amplification_factor; ++i) {
+ for (size_t i = 1; i < anti_amplification_factor; ++i) {
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
connection_.SendCryptoDataWithString("foo", i * 3);
// Verify retransmission alarm is not set if throttled by anti-amplification
@@ -10044,10 +10113,11 @@ TEST_P(QuicConnectionTest, AntiAmplificationLimit) {
connection_.SendCryptoDataWithString("foo", anti_amplification_factor * 3);
// Receives packet 2.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
ProcessCryptoPacketAtLevel(2, ENCRYPTION_INITIAL);
// Verify more packets can be sent.
- for (size_t i = anti_amplification_factor; i < anti_amplification_factor * 2;
- ++i) {
+ for (size_t i = anti_amplification_factor + 1;
+ i < anti_amplification_factor * 2; ++i) {
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
connection_.SendCryptoDataWithString("foo", i * 3);
}
@@ -10056,6 +10126,7 @@ TEST_P(QuicConnectionTest, AntiAmplificationLimit) {
connection_.SendCryptoDataWithString("foo",
2 * anti_amplification_factor * 3);
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
ProcessPacket(3);
// Verify anti-amplification limit is gone after address validation.
for (size_t i = 0; i < 100; ++i) {
@@ -10092,11 +10163,12 @@ TEST_P(QuicConnectionTest, 3AntiAmplificationLimit) {
EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
// Receives packet 1.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
ProcessCryptoPacketAtLevel(1, ENCRYPTION_INITIAL);
const size_t anti_amplification_factor = 3;
// Verify now packets can be sent.
- for (size_t i = 0; i < anti_amplification_factor; ++i) {
+ for (size_t i = 1; i < anti_amplification_factor; ++i) {
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
connection_.SendCryptoDataWithString("foo", i * 3);
// Verify retransmission alarm is not set if throttled by anti-amplification
@@ -10109,10 +10181,11 @@ TEST_P(QuicConnectionTest, 3AntiAmplificationLimit) {
connection_.SendCryptoDataWithString("foo", anti_amplification_factor * 3);
// Receives packet 2.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
ProcessCryptoPacketAtLevel(2, ENCRYPTION_INITIAL);
// Verify more packets can be sent.
- for (size_t i = anti_amplification_factor; i < anti_amplification_factor * 2;
- ++i) {
+ for (size_t i = anti_amplification_factor + 1;
+ i < anti_amplification_factor * 2; ++i) {
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
connection_.SendCryptoDataWithString("foo", i * 3);
}
@@ -10121,6 +10194,7 @@ TEST_P(QuicConnectionTest, 3AntiAmplificationLimit) {
connection_.SendCryptoDataWithString("foo",
2 * anti_amplification_factor * 3);
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
ProcessPacket(3);
// Verify anti-amplification limit is gone after address validation.
for (size_t i = 0; i < 100; ++i) {
@@ -10157,11 +10231,12 @@ TEST_P(QuicConnectionTest, 10AntiAmplificationLimit) {
EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
// Receives packet 1.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
ProcessCryptoPacketAtLevel(1, ENCRYPTION_INITIAL);
const size_t anti_amplification_factor = 10;
// Verify now packets can be sent.
- for (size_t i = 0; i < anti_amplification_factor; ++i) {
+ for (size_t i = 1; i < anti_amplification_factor; ++i) {
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
connection_.SendCryptoDataWithString("foo", i * 3);
// Verify retransmission alarm is not set if throttled by anti-amplification
@@ -10174,10 +10249,11 @@ TEST_P(QuicConnectionTest, 10AntiAmplificationLimit) {
connection_.SendCryptoDataWithString("foo", anti_amplification_factor * 3);
// Receives packet 2.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
ProcessCryptoPacketAtLevel(2, ENCRYPTION_INITIAL);
// Verify more packets can be sent.
- for (size_t i = anti_amplification_factor; i < anti_amplification_factor * 2;
- ++i) {
+ for (size_t i = anti_amplification_factor + 1;
+ i < anti_amplification_factor * 2; ++i) {
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
connection_.SendCryptoDataWithString("foo", i * 3);
}
@@ -10186,6 +10262,7 @@ TEST_P(QuicConnectionTest, 10AntiAmplificationLimit) {
connection_.SendCryptoDataWithString("foo",
2 * anti_amplification_factor * 3);
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
ProcessPacket(3);
// Verify anti-amplification limit is gone after address validation.
for (size_t i = 0; i < 100; ++i) {
@@ -10941,6 +11018,11 @@ TEST_P(QuicConnectionTest, DonotChangeQueuedAcks) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
EXPECT_CALL(*send_algorithm_, OnCongestionEvent(_, _, _, _, _));
connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+ // Discard INITIAL key.
+ connection_.RemoveEncrypter(ENCRYPTION_INITIAL);
+ connection_.NeuterUnencryptedPackets();
+ EXPECT_CALL(visitor_, GetHandshakeState())
+ .WillRepeatedly(Return(HANDSHAKE_COMPLETE));
ProcessPacket(2);
ProcessPacket(3);
@@ -10996,7 +11078,7 @@ TEST_P(QuicConnectionTest, BundleAckWithImmediateResponse) {
connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
EXPECT_CALL(visitor_, OnStreamFrame(_)).WillOnce(Invoke([this]() {
- connection_.SendControlFrame(QuicFrame(new QuicWindowUpdateFrame(1, 0, 0)));
+ notifier_.WriteOrBufferWindowUpate(0, 0);
}));
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
ProcessDataPacket(1);
@@ -12104,13 +12186,9 @@ TEST_P(QuicConnectionTest, SendPathChallengeUsingBlockedNewSocket) {
new_writer.SetWritable();
// Write event on the default socket shouldn't make any difference.
connection_.OnCanWrite();
- if (GetQuicReloadableFlag(quic_ack_cid_frames)) {
- // A NEW_CONNECTION_ID frame is received in PathProbeTestInit and OnCanWrite
- // will write a acking packet.
- EXPECT_EQ(1u, writer_->packets_write_attempts());
- } else {
- EXPECT_EQ(0u, writer_->packets_write_attempts());
- }
+ // A NEW_CONNECTION_ID frame is received in PathProbeTestInit and OnCanWrite
+ // will write a acking packet.
+ EXPECT_EQ(1u, writer_->packets_write_attempts());
EXPECT_EQ(1u, new_writer.packets_write_attempts());
}
@@ -12691,7 +12769,7 @@ TEST_P(QuicConnectionTest, CoalescerHandlesInitialKeyDiscard) {
connection_.SetEncrypter(ENCRYPTION_HANDSHAKE,
std::make_unique<TaggingEncrypter>(0x02));
connection_.SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE);
- connection_.SendCryptoDataWithString(std::string(1300, 'a'), 0);
+ connection_.SendCryptoDataWithString(std::string(1200, 'a'), 0);
// Verify this packet is on hold.
EXPECT_EQ(0u, writer_->packets_write_attempts());
}
@@ -12718,7 +12796,7 @@ TEST_P(QuicConnectionTest, ZeroRttRejectionAndMissingInitialKeys) {
connection_.SetEncrypter(ENCRYPTION_HANDSHAKE,
std::make_unique<TaggingEncrypter>(0x03));
connection_.SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE);
- connection_.SendCryptoStreamData();
+ connection_.SendCryptoDataWithString("foo", 0, ENCRYPTION_HANDSHAKE);
connection_.SetEncrypter(ENCRYPTION_FORWARD_SECURE,
std::make_unique<TaggingEncrypter>(0x04));
connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
@@ -12733,7 +12811,7 @@ TEST_P(QuicConnectionTest, ZeroRttRejectionAndMissingInitialKeys) {
use_tagging_decrypter();
connection_.SetEncrypter(ENCRYPTION_INITIAL,
std::make_unique<TaggingEncrypter>(0x01));
- connection_.SendCryptoStreamData();
+ connection_.SendCryptoDataWithString("foo", 0, ENCRYPTION_INITIAL);
// Send 0-RTT packet.
connection_.SetEncrypter(ENCRYPTION_ZERO_RTT,
std::make_unique<TaggingEncrypter>(0x02));
@@ -13702,6 +13780,8 @@ TEST_P(QuicConnectionTest, SingleAckInPacket) {
connection_.RemoveEncrypter(ENCRYPTION_INITIAL);
connection_.NeuterUnencryptedPackets();
connection_.OnHandshakeComplete();
+ EXPECT_CALL(visitor_, GetHandshakeState())
+ .WillRepeatedly(Return(HANDSHAKE_COMPLETE));
EXPECT_CALL(visitor_, OnStreamFrame(_)).WillOnce(Invoke([=]() {
connection_.SendStreamData3();
@@ -14102,6 +14182,8 @@ TEST_P(QuicConnectionTest, PathChallengeBeforePeerIpAddressChangeAtServer) {
// Verify the anti-amplification limit is lifted by sending a packet larger
// than the anti-amplification limit.
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ EXPECT_CALL(*send_algorithm_, PacingRate(_))
+ .WillRepeatedly(Return(QuicBandwidth::Zero()));
connection_.SendCryptoDataWithString(std::string(1200, 'a'), 0);
EXPECT_EQ(1u, connection_.GetStats().num_validated_peer_migration);
}
@@ -14287,10 +14369,13 @@ TEST_P(QuicConnectionTest,
TEST_P(QuicConnectionTest,
PathValidationFailedOnClientDueToLackOfServerConnectionId) {
- QuicConfig config;
- config.SetConnectionOptionsToSend({kRVCM});
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
- connection_.SetFromConfig(config);
+ if (!GetQuicReloadableFlag(
+ quic_remove_connection_migration_connection_option)) {
+ QuicConfig config;
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ connection_.SetFromConfig(config);
+ config.SetConnectionOptionsToSend({kRVCM});
+ }
if (!connection_.connection_migration_use_new_cid()) {
return;
}
@@ -14312,10 +14397,13 @@ TEST_P(QuicConnectionTest,
TEST_P(QuicConnectionTest,
PathValidationFailedOnClientDueToLackOfClientConnectionIdTheSecondTime) {
- QuicConfig config;
- config.SetConnectionOptionsToSend({kRVCM});
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
- connection_.SetFromConfig(config);
+ if (!GetQuicReloadableFlag(
+ quic_remove_connection_migration_connection_option)) {
+ QuicConfig config;
+ config.SetConnectionOptionsToSend({kRVCM});
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ connection_.SetFromConfig(config);
+ }
if (!connection_.connection_migration_use_new_cid()) {
return;
}
@@ -14401,10 +14489,13 @@ TEST_P(QuicConnectionTest,
}
TEST_P(QuicConnectionTest, ServerConnectionIdRetiredUponPathValidationFailure) {
- QuicConfig config;
- config.SetConnectionOptionsToSend({kRVCM});
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
- connection_.SetFromConfig(config);
+ if (!GetQuicReloadableFlag(
+ quic_remove_connection_migration_connection_option)) {
+ QuicConfig config;
+ config.SetConnectionOptionsToSend({kRVCM});
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ connection_.SetFromConfig(config);
+ }
if (!connection_.connection_migration_use_new_cid()) {
return;
}
@@ -14448,10 +14539,13 @@ TEST_P(QuicConnectionTest, ServerConnectionIdRetiredUponPathValidationFailure) {
TEST_P(QuicConnectionTest,
MigratePathDirectlyFailedDueToLackOfServerConnectionId) {
- QuicConfig config;
- config.SetConnectionOptionsToSend({kRVCM});
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
- connection_.SetFromConfig(config);
+ if (!GetQuicReloadableFlag(
+ quic_remove_connection_migration_connection_option)) {
+ QuicConfig config;
+ config.SetConnectionOptionsToSend({kRVCM});
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ connection_.SetFromConfig(config);
+ }
if (!connection_.connection_migration_use_new_cid()) {
return;
}
@@ -14468,10 +14562,13 @@ TEST_P(QuicConnectionTest,
TEST_P(QuicConnectionTest,
MigratePathDirectlyFailedDueToLackOfClientConnectionIdTheSecondTime) {
- QuicConfig config;
- config.SetConnectionOptionsToSend({kRVCM});
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
- connection_.SetFromConfig(config);
+ if (!GetQuicReloadableFlag(
+ quic_remove_connection_migration_connection_option)) {
+ QuicConfig config;
+ config.SetConnectionOptionsToSend({kRVCM});
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ connection_.SetFromConfig(config);
+ }
if (!connection_.connection_migration_use_new_cid()) {
return;
}
@@ -14793,11 +14890,16 @@ TEST_P(QuicConnectionTest,
}
TEST_P(QuicConnectionTest, ServerRetireSelfIssuedConnectionId) {
- if (!version().HasIetfQuicFrames() ||
- !connection_.connection_migration_use_new_cid()) {
+ if (!GetQuicReloadableFlag(
+ quic_remove_connection_migration_connection_option)) {
+ QuicConfig config;
+ config.SetConnectionOptionsToSend({kRVCM});
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ connection_.SetFromConfig(config);
+ }
+ if (!connection_.connection_migration_use_new_cid()) {
return;
}
- QuicConnectionPeer::EnableMultipleConnectionIdSupport(&connection_);
set_perspective(Perspective::IS_SERVER);
connection_.CreateConnectionIdManager();
QuicConnectionId recorded_cid;
@@ -14807,7 +14909,10 @@ TEST_P(QuicConnectionTest, ServerRetireSelfIssuedConnectionId) {
QuicConnectionId cid0 = connection_id_;
QuicConnectionId cid1;
QuicConnectionId cid2;
+ EXPECT_EQ(connection_.connection_id(), cid0);
+ EXPECT_EQ(connection_.GetOneActiveServerConnectionId(), cid0);
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
EXPECT_CALL(visitor_, OnServerConnectionIdIssued(_))
.WillOnce(Invoke(cid_recorder));
EXPECT_CALL(visitor_, SendNewConnectionId(_));
@@ -14818,23 +14923,63 @@ TEST_P(QuicConnectionTest, ServerRetireSelfIssuedConnectionId) {
connection_.GetRetireSelfIssuedConnectionIdAlarm();
ASSERT_FALSE(retire_self_issued_cid_alarm->IsSet());
- QuicRetireConnectionIdFrame frame;
- frame.sequence_number = 0u;
+ // Generate three packets with different connection IDs that will arrive out
+ // of order (2, 1, 3) later.
+ char buffers[3][kMaxOutgoingPacketSize];
+ // Destination connection ID of packet1 is cid0.
+ auto packet1 =
+ ConstructPacket({QuicFrame(QuicPingFrame())}, ENCRYPTION_FORWARD_SECURE,
+ buffers[0], kMaxOutgoingPacketSize);
+ peer_creator_.SetServerConnectionId(cid1);
+ auto retire_cid_frame = std::make_unique<QuicRetireConnectionIdFrame>();
+ retire_cid_frame->sequence_number = 0u;
+ // Destination connection ID of packet2 is cid1.
+ auto packet2 = ConstructPacket({QuicFrame(retire_cid_frame.release())},
+ ENCRYPTION_FORWARD_SECURE, buffers[1],
+ kMaxOutgoingPacketSize);
+ // Destination connection ID of packet3 is cid1.
+ auto packet3 =
+ ConstructPacket({QuicFrame(QuicPingFrame())}, ENCRYPTION_FORWARD_SECURE,
+ buffers[2], kMaxOutgoingPacketSize);
+
+ // Packet2 with RetireConnectionId frame trigers sending NewConnectionId
+ // immediately.
EXPECT_CALL(visitor_, OnServerConnectionIdIssued(_))
.WillOnce(Invoke(cid_recorder));
- // RetireConnectionId trigers sending NewConnectionId immediately.
EXPECT_CALL(visitor_, SendNewConnectionId(_));
- EXPECT_TRUE(connection_.OnRetireConnectionIdFrame(frame));
+ peer_creator_.SetServerConnectionId(cid1);
+ connection_.ProcessUdpPacket(kSelfAddress, kPeerAddress, *packet2);
cid2 = recorded_cid;
// cid0 is not retired immediately.
EXPECT_THAT(connection_.GetActiveServerConnectionIds(),
ElementsAre(cid0, cid1, cid2));
ASSERT_TRUE(retire_self_issued_cid_alarm->IsSet());
+ EXPECT_EQ(connection_.connection_id(), cid1);
+ EXPECT_TRUE(connection_.GetOneActiveServerConnectionId() == cid0 ||
+ connection_.GetOneActiveServerConnectionId() == cid1 ||
+ connection_.GetOneActiveServerConnectionId() == cid2);
+
+ // Packet1 updates the connection ID on the default path but not the active
+ // connection ID.
+ connection_.ProcessUdpPacket(kSelfAddress, kPeerAddress, *packet1);
+ EXPECT_EQ(connection_.connection_id(), cid0);
+ EXPECT_TRUE(connection_.GetOneActiveServerConnectionId() == cid0 ||
+ connection_.GetOneActiveServerConnectionId() == cid1 ||
+ connection_.GetOneActiveServerConnectionId() == cid2);
+
// cid0 is retired when the retire CID alarm fires.
EXPECT_CALL(visitor_, OnServerConnectionIdRetired(cid0));
retire_self_issued_cid_alarm->Fire();
EXPECT_THAT(connection_.GetActiveServerConnectionIds(),
ElementsAre(cid1, cid2));
+ EXPECT_TRUE(connection_.GetOneActiveServerConnectionId() == cid1 ||
+ connection_.GetOneActiveServerConnectionId() == cid2);
+
+ // Packet3 updates the connection ID on the default path.
+ connection_.ProcessUdpPacket(kSelfAddress, kPeerAddress, *packet3);
+ EXPECT_EQ(connection_.connection_id(), cid1);
+ EXPECT_TRUE(connection_.GetOneActiveServerConnectionId() == cid1 ||
+ connection_.GetOneActiveServerConnectionId() == cid2);
}
TEST_P(QuicConnectionTest, PatchMissingClientConnectionIdOntoAlternativePath) {
@@ -14962,6 +15107,9 @@ TEST_P(QuicConnectionTest, LostDataThenGetAcknowledged) {
QuicConnectionPeer::SetAddressValidated(&connection_);
}
connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+ // Discard INITIAL key.
+ connection_.RemoveEncrypter(ENCRYPTION_INITIAL);
+ connection_.NeuterUnencryptedPackets();
EXPECT_CALL(visitor_, GetHandshakeState())
.WillRepeatedly(Return(HANDSHAKE_CONFIRMED));
@@ -15202,13 +15350,15 @@ TEST_P(QuicConnectionTest, PingNotSentAt0RTTLevelWhenInitialAvailable) {
}
TEST_P(QuicConnectionTest, AckElicitingFrames) {
- QuicConfig config;
- config.SetConnectionOptionsToSend({kRVCM});
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
- connection_.SetFromConfig(config);
+ if (!GetQuicReloadableFlag(
+ quic_remove_connection_migration_connection_option)) {
+ QuicConfig config;
+ config.SetConnectionOptionsToSend({kRVCM});
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ connection_.SetFromConfig(config);
+ }
if (!version().HasIetfQuicFrames() ||
!connection_.connection_migration_use_new_cid() ||
- !GetQuicReloadableFlag(quic_ack_cid_frames) ||
!GetQuicReloadableFlag(quic_add_missing_update_ack_timeout)) {
return;
}
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 162de8909bd..c53459cf70d 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
@@ -28,7 +28,7 @@ const uint64_t kNumMicrosPerSecond = kNumMicrosPerMilli * kNumMillisPerSecond;
// Default number of connections for N-connection emulation.
const uint32_t kDefaultNumConnections = 2;
// Default initial maximum size in bytes of a QUIC packet.
-const QuicByteCount kDefaultMaxPacketSize = 1350;
+const QuicByteCount kDefaultMaxPacketSize = 1250;
// Default initial maximum size in bytes of a QUIC packet for servers.
const QuicByteCount kDefaultServerMaxPacketSize = 1000;
// Maximum transmission unit on Ethernet.
@@ -301,6 +301,10 @@ enum : QuicDatagramContextId {
kDatagramContextIdIncrement = 2,
};
+enum : uint64_t {
+ kHttpDatagramStreamIdDivisor = 4,
+};
+
} // namespace quic
#endif // QUICHE_QUIC_CORE_QUIC_CONSTANTS_H_
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 42862494745..39e768c9ed5 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
@@ -59,8 +59,7 @@ void QuicControlFrameManager::WriteOrBufferQuicFrame(QuicFrame frame) {
}
void QuicControlFrameManager::WriteOrBufferRstStream(
- QuicStreamId id,
- QuicRstStreamErrorCode error,
+ QuicStreamId id, QuicResetStreamError error,
QuicStreamOffset bytes_written) {
QUIC_DVLOG(1) << "Writing RST_STREAM_FRAME";
WriteOrBufferQuicFrame((QuicFrame(new QuicRstStreamFrame(
@@ -68,8 +67,7 @@ void QuicControlFrameManager::WriteOrBufferRstStream(
}
void QuicControlFrameManager::WriteOrBufferGoAway(
- QuicErrorCode error,
- QuicStreamId last_good_stream_id,
+ QuicErrorCode error, QuicStreamId last_good_stream_id,
const std::string& reason) {
QUIC_DVLOG(1) << "Writing GOAWAY_FRAME";
WriteOrBufferQuicFrame(QuicFrame(new QuicGoAwayFrame(
@@ -77,8 +75,7 @@ void QuicControlFrameManager::WriteOrBufferGoAway(
}
void QuicControlFrameManager::WriteOrBufferWindowUpdate(
- QuicStreamId id,
- QuicStreamOffset byte_offset) {
+ QuicStreamId id, QuicStreamOffset byte_offset) {
QUIC_DVLOG(1) << "Writing WINDOW_UPDATE_FRAME";
WriteOrBufferQuicFrame(QuicFrame(
new QuicWindowUpdateFrame(++last_control_frame_id_, id, byte_offset)));
@@ -107,11 +104,10 @@ void QuicControlFrameManager::WriteOrBufferMaxStreams(QuicStreamCount count,
}
void QuicControlFrameManager::WriteOrBufferStopSending(
- QuicRstStreamErrorCode code,
- QuicStreamId stream_id) {
+ QuicResetStreamError error, QuicStreamId stream_id) {
QUIC_DVLOG(1) << "Writing STOP_SENDING_FRAME";
WriteOrBufferQuicFrame(QuicFrame(
- new QuicStopSendingFrame(++last_control_frame_id_, stream_id, code)));
+ new QuicStopSendingFrame(++last_control_frame_id_, stream_id, error)));
}
void QuicControlFrameManager::WriteOrBufferHandshakeDone() {
@@ -134,8 +130,7 @@ void QuicControlFrameManager::WriteOrBufferAckFrequency(
}
void QuicControlFrameManager::WriteOrBufferNewConnectionId(
- const QuicConnectionId& connection_id,
- uint64_t sequence_number,
+ const QuicConnectionId& connection_id, uint64_t sequence_number,
uint64_t retire_prior_to,
const StatelessResetToken& stateless_reset_token) {
QUIC_DVLOG(1) << "Writing NEW_CONNECTION_ID frame";
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager.h b/chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager.h
index 962733a147d..e83fc3b1760 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager.h
@@ -11,6 +11,7 @@
#include "absl/container/flat_hash_map.h"
#include "quic/core/frames/quic_frame.h"
#include "quic/core/quic_connection_id.h"
+#include "quic/core/quic_error_codes.h"
#include "quic/core/quic_types.h"
#include "common/quiche_circular_deque.h"
#include "common/quiche_linked_hash_map.h"
@@ -53,8 +54,7 @@ class QUIC_EXPORT_PRIVATE QuicControlFrameManager {
// Tries to send a WINDOW_UPDATE_FRAME. Buffers the frame if it cannot be sent
// immediately.
- void WriteOrBufferRstStream(QuicControlFrameId id,
- QuicRstStreamErrorCode error,
+ void WriteOrBufferRstStream(QuicControlFrameId id, QuicResetStreamError error,
QuicStreamOffset bytes_written);
// Tries to send a GOAWAY_FRAME. Buffers the frame if it cannot be sent
@@ -81,7 +81,7 @@ class QUIC_EXPORT_PRIVATE QuicControlFrameManager {
// Tries to send an IETF-QUIC STOP_SENDING frame. The frame is buffered if it
// can not be sent immediately.
- void WriteOrBufferStopSending(QuicRstStreamErrorCode code,
+ void WriteOrBufferStopSending(QuicResetStreamError error,
QuicStreamId stream_id);
// Tries to send an HANDSHAKE_DONE frame. The frame is buffered if it can not
@@ -96,8 +96,7 @@ class QUIC_EXPORT_PRIVATE QuicControlFrameManager {
// Tries to send a NEW_CONNECTION_ID frame. The frame is buffered if it cannot
// be sent immediately.
void WriteOrBufferNewConnectionId(
- const QuicConnectionId& connection_id,
- uint64_t sequence_number,
+ const QuicConnectionId& connection_id, uint64_t sequence_number,
uint64_t retire_prior_to,
const StatelessResetToken& stateless_reset_token);
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager_test.cc
index 9d6b434ef31..6d208111a53 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager_test.cc
@@ -66,12 +66,16 @@ class QuicControlFrameManagerTest : public QuicTest {
EXPECT_FALSE(manager_->WillingToWrite());
EXPECT_CALL(*session_, WriteControlFrame(_, _)).WillOnce(Return(false));
- manager_->WriteOrBufferRstStream(kTestStreamId, QUIC_STREAM_CANCELLED, 0);
+ manager_->WriteOrBufferRstStream(
+ kTestStreamId,
+ QuicResetStreamError::FromInternal(QUIC_STREAM_CANCELLED), 0);
manager_->WriteOrBufferGoAway(QUIC_PEER_GOING_AWAY, kTestStreamId,
"Going away.");
manager_->WriteOrBufferWindowUpdate(kTestStreamId, 100);
manager_->WriteOrBufferBlocked(kTestStreamId);
- manager_->WriteOrBufferStopSending(kTestStopSendingCode, kTestStreamId);
+ manager_->WriteOrBufferStopSending(
+ QuicResetStreamError::FromInternal(kTestStopSendingCode),
+ kTestStreamId);
number_of_frames_ = 5u;
EXPECT_EQ(number_of_frames_,
QuicControlFrameManagerPeer::QueueSize(manager_.get()));
@@ -341,14 +345,18 @@ TEST_F(QuicControlFrameManagerTest, TooManyBufferedControlFrames) {
// Write 995 control frames.
EXPECT_CALL(*session_, WriteControlFrame(_, _)).WillOnce(Return(false));
for (size_t i = 0; i < 995; ++i) {
- manager_->WriteOrBufferRstStream(kTestStreamId, QUIC_STREAM_CANCELLED, 0);
+ manager_->WriteOrBufferRstStream(
+ kTestStreamId,
+ QuicResetStreamError::FromInternal(QUIC_STREAM_CANCELLED), 0);
}
// Verify write one more control frame causes connection close.
EXPECT_CALL(
*connection_,
CloseConnection(QUIC_TOO_MANY_BUFFERED_CONTROL_FRAMES, _,
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET));
- manager_->WriteOrBufferRstStream(kTestStreamId, QUIC_STREAM_CANCELLED, 0);
+ manager_->WriteOrBufferRstStream(
+ kTestStreamId, QuicResetStreamError::FromInternal(QUIC_STREAM_CANCELLED),
+ 0);
}
} // namespace
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 e92606669de..d9f10350553 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
@@ -65,6 +65,13 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientHandshaker
std::unique_ptr<ApplicationState> /*application_state*/) override {
QUICHE_NOTREACHED();
}
+ bool ExportKeyingMaterial(absl::string_view /*label*/,
+ absl::string_view /*context*/,
+ size_t /*result_len*/,
+ std::string* /*result*/) override {
+ QUICHE_NOTREACHED();
+ return false;
+ }
// 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 ed5da6cb544..120e5dae233 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
@@ -77,18 +77,20 @@ class DummyProofSource : public ProofSource {
QuicTransportVersion /*transport_version*/,
absl::string_view /*chlo_hash*/,
std::unique_ptr<Callback> callback) override {
- QuicReferenceCountedPointer<ProofSource::Chain> chain =
- GetCertChain(server_address, client_address, hostname);
+ bool cert_matched_sni;
+ QuicReferenceCountedPointer<ProofSource::Chain> chain = GetCertChain(
+ server_address, client_address, hostname, &cert_matched_sni);
QuicCryptoProof proof;
proof.signature = "Dummy signature";
proof.leaf_cert_scts = "Dummy timestamp";
+ proof.cert_matched_sni = cert_matched_sni;
callback->Run(true, chain, proof, /*details=*/nullptr);
}
QuicReferenceCountedPointer<Chain> GetCertChain(
const QuicSocketAddress& /*server_address*/,
const QuicSocketAddress& /*client_address*/,
- const std::string& /*hostname*/) override {
+ const std::string& /*hostname*/, bool* /*cert_matched_sni*/) override {
std::vector<std::string> certs;
certs.push_back("Dummy cert");
return QuicReferenceCountedPointer<ProofSource::Chain>(
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 78d2f10a563..fe6471ff2bc 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.cc
@@ -43,11 +43,14 @@ QuicCryptoClientStream::QuicCryptoClientStream(
server_id, this, session, std::move(verify_context), crypto_config,
proof_handler);
break;
- case PROTOCOL_TLS1_3:
- handshaker_ = std::make_unique<TlsClientHandshaker>(
+ case PROTOCOL_TLS1_3: {
+ auto handshaker = std::make_unique<TlsClientHandshaker>(
server_id, this, session, std::move(verify_context), crypto_config,
proof_handler, has_application_state);
+ tls_handshaker_ = handshaker.get();
+ handshaker_ = std::move(handshaker);
break;
+ }
case PROTOCOL_UNSUPPORTED:
QUIC_BUG(quic_bug_10296_1)
<< "Attempting to create QuicCryptoClientStream for unknown "
@@ -125,6 +128,13 @@ QuicCryptoClientStream::CreateCurrentOneRttEncrypter() {
return handshaker_->CreateCurrentOneRttEncrypter();
}
+bool QuicCryptoClientStream::ExportKeyingMaterial(absl::string_view label,
+ absl::string_view context,
+ size_t result_len,
+ std::string* result) {
+ return handshaker_->ExportKeyingMaterial(label, context, result_len, result);
+}
+
std::string QuicCryptoClientStream::chlo_hash() const {
return handshaker_->chlo_hash();
}
@@ -167,4 +177,8 @@ void QuicCryptoClientStream::SetServerApplicationStateForResumption(
std::move(application_state));
}
+SSL* QuicCryptoClientStream::GetSsl() const {
+ return tls_handshaker_ == nullptr ? nullptr : tls_handshaker_->ssl();
+}
+
} // 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 b3d3c2b2bc3..daea001302e 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
@@ -25,6 +25,8 @@ namespace test {
class QuicCryptoClientStreamPeer;
} // namespace test
+class TlsClientHandshaker;
+
class QUIC_EXPORT_PRIVATE QuicCryptoClientStreamBase : public QuicCryptoStream {
public:
explicit QuicCryptoClientStreamBase(QuicSession* session);
@@ -63,6 +65,14 @@ 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;
+
+ bool ExportKeyingMaterial(absl::string_view /*label*/,
+ absl::string_view /*context*/,
+ size_t /*result_len*/,
+ std::string* /*result*/) override {
+ QUICHE_NOTREACHED();
+ return false;
+ }
};
class QUIC_EXPORT_PRIVATE QuicCryptoClientStream
@@ -185,6 +195,13 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientStream
// Called when application state is received.
virtual void SetServerApplicationStateForResumption(
std::unique_ptr<ApplicationState> application_state) = 0;
+
+ // Called to obtain keying material export of length |result_len| with the
+ // given |label| and |context|. Returns false on failure.
+ virtual bool ExportKeyingMaterial(absl::string_view label,
+ absl::string_view context,
+ size_t result_len,
+ std::string* result) = 0;
};
// ProofHandler is an interface that handles callbacks from the crypto
@@ -250,7 +267,9 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientStream
std::unique_ptr<QuicDecrypter> AdvanceKeysAndCreateCurrentOneRttDecrypter()
override;
std::unique_ptr<QuicEncrypter> CreateCurrentOneRttEncrypter() override;
-
+ SSL* GetSsl() const override;
+ bool ExportKeyingMaterial(absl::string_view label, absl::string_view context,
+ size_t result_len, std::string* result) override;
std::string chlo_hash() const;
protected:
@@ -261,6 +280,10 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientStream
private:
friend class test::QuicCryptoClientStreamPeer;
std::unique_ptr<HandshakerInterface> handshaker_;
+ // Points to |handshaker_| if it uses TLS1.3. Otherwise, nullptr.
+ // TODO(danzh) change the type of |handshaker_| to TlsClientHandshaker after
+ // deprecating Google QUIC.
+ TlsClientHandshaker* tls_handshaker_{nullptr};
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.cc
index 9bd9c7bc2b9..de6cb75cfb6 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
@@ -352,6 +352,10 @@ bool QuicCryptoServerStream::ShouldSendExpectCTHeader() const {
return signed_config_->proof.send_expect_ct_header;
}
+bool QuicCryptoServerStream::DidCertMatchSni() const {
+ return signed_config_->proof.cert_matched_sni;
+}
+
const ProofSource::Details* QuicCryptoServerStream::ProofSourceDetails() const {
return proof_source_details_.get();
}
@@ -507,4 +511,6 @@ const QuicSocketAddress QuicCryptoServerStream::GetClientAddress() {
return session()->connection()->peer_address();
}
+SSL* QuicCryptoServerStream::GetSsl() const { return nullptr; }
+
} // namespace quic
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 911ca7e789f..bf6f3e53e72 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h
@@ -51,6 +51,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerStream
std::string GetAddressToken() const override;
bool ValidateAddressToken(absl::string_view token) const override;
bool ShouldSendExpectCTHeader() const override;
+ bool DidCertMatchSni() const override;
const ProofSource::Details* ProofSourceDetails() const override;
// From QuicCryptoStream
@@ -68,6 +69,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerStream
std::unique_ptr<QuicDecrypter> AdvanceKeysAndCreateCurrentOneRttDecrypter()
override;
std::unique_ptr<QuicEncrypter> CreateCurrentOneRttEncrypter() override;
+ SSL* GetSsl() const override;
// From QuicCryptoHandshaker
void OnHandshakeMessage(const CryptoHandshakeMessage& message) override;
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_base.h b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_base.h
index 3ff9c37fa1e..967d6d11fb8 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_base.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_base.h
@@ -85,11 +85,22 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerStreamBase : public QuicCryptoStream {
// configuration for the certificate used in the connection is accessible.
virtual bool ShouldSendExpectCTHeader() const = 0;
+ // Return true if a cert was picked that matched the SNI hostname.
+ virtual bool DidCertMatchSni() const = 0;
+
// Returns the Details from the latest call to ProofSource::GetProof or
// ProofSource::ComputeTlsSignature. Returns nullptr if no such call has been
// made. The Details are owned by the QuicCryptoServerStreamBase and the
// pointer is only valid while the owning object is still valid.
virtual const ProofSource::Details* ProofSourceDetails() const = 0;
+
+ bool ExportKeyingMaterial(absl::string_view /*label*/,
+ absl::string_view /*context*/,
+ size_t /*result_len*/,
+ std::string* /*result*/) override {
+ QUICHE_NOTREACHED();
+ return false;
+ }
};
// Creates an appropriate QuicCryptoServerStream for the provided parameters,
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 a14cef07f27..99fb2cd22e1 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
@@ -127,20 +127,6 @@ void QuicCryptoStream::OnDataAvailableInSequencer(
}
}
-bool QuicCryptoStream::ExportKeyingMaterial(absl::string_view label,
- absl::string_view context,
- size_t result_len,
- std::string* result) const {
- if (!one_rtt_keys_available()) {
- QUIC_DLOG(ERROR) << "ExportKeyingMaterial was called before forward-secure"
- << "encryption was established.";
- return false;
- }
- return CryptoUtils::ExportKeyingMaterial(
- crypto_negotiated_params().subkey_secret, label, context, result_len,
- result);
-}
-
void QuicCryptoStream::WriteCryptoData(EncryptionLevel level,
absl::string_view data) {
if (!QuicVersionUsesCryptoFrames(session()->transport_version())) {
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 2a86a723d3c..b42b2d9e525 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
@@ -63,11 +63,12 @@ class QUIC_EXPORT_PRIVATE QuicCryptoStream : public QuicStream {
// Performs key extraction to derive a new secret of |result_len| bytes
// dependent on |label|, |context|, and the stream's negotiated subkey secret.
// Returns false if the handshake has not been confirmed or the parameters are
- // invalid (e.g. |label| contains null bytes); returns true on success.
- bool ExportKeyingMaterial(absl::string_view label,
- absl::string_view context,
- size_t result_len,
- std::string* result) const;
+ // invalid (e.g. |label| contains null bytes); returns true on success. This
+ // method is only supported for IETF QUIC and MUST NOT be called in gQUIC as
+ // that'll trigger an assert in DEBUG build.
+ virtual bool ExportKeyingMaterial(absl::string_view label,
+ absl::string_view context,
+ size_t result_len, std::string* result) = 0;
// Writes |data| to the QuicStream at level |level|.
virtual void WriteCryptoData(EncryptionLevel level, absl::string_view data);
@@ -147,6 +148,11 @@ class QUIC_EXPORT_PRIVATE QuicCryptoStream : public QuicStream {
// decrypter returned by AdvanceKeysAndCreateCurrentOneRttDecrypter().
virtual std::unique_ptr<QuicEncrypter> CreateCurrentOneRttEncrypter() = 0;
+ // Return the SSL struct object created by BoringSSL if the stream is using
+ // TLS1.3. Otherwise, return nullptr.
+ // This method is used in Envoy.
+ virtual SSL* GetSsl() const = 0;
+
// Called to cancel retransmission of unencrypted crypto stream data.
void NeuterUnencryptedStreamData();
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 545fdd8180f..e1bbf3599a7 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
@@ -79,6 +79,13 @@ class MockQuicCryptoStream : public QuicCryptoStream,
std::unique_ptr<QuicEncrypter> CreateCurrentOneRttEncrypter() override {
return nullptr;
}
+ bool ExportKeyingMaterial(absl::string_view /*label*/,
+ absl::string_view /*context*/,
+ size_t /*result_len*/,
+ std::string* /*result*/) override {
+ return false;
+ }
+ SSL* GetSsl() const override { return nullptr; }
private:
QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params_;
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_datagram_queue.cc b/chromium/net/third_party/quiche/src/quic/core/quic_datagram_queue.cc
index e6f3e6f427a..ebd74836597 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_datagram_queue.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_datagram_queue.cc
@@ -9,7 +9,6 @@
#include "quic/core/quic_session.h"
#include "quic/core/quic_time.h"
#include "quic/core/quic_types.h"
-#include "quic/platform/api/quic_mem_slice_span.h"
namespace quic {
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 11f4bcd4b3d..ad172810bbf 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
@@ -40,7 +40,7 @@ namespace {
const QuicPacketLength kMinClientInitialPacketLength = 1200;
// An alarm that informs the QuicDispatcher to delete old sessions.
-class DeleteSessionsAlarm : public QuicAlarm::Delegate {
+class DeleteSessionsAlarm : public QuicAlarm::DelegateWithoutContext {
public:
explicit DeleteSessionsAlarm(QuicDispatcher* dispatcher)
: dispatcher_(dispatcher) {}
@@ -54,6 +54,24 @@ class DeleteSessionsAlarm : public QuicAlarm::Delegate {
QuicDispatcher* dispatcher_;
};
+// An alarm that informs the QuicDispatcher to clear
+// recent_stateless_reset_addresses_.
+class ClearStatelessResetAddressesAlarm
+ : public QuicAlarm::DelegateWithoutContext {
+ public:
+ explicit ClearStatelessResetAddressesAlarm(QuicDispatcher* dispatcher)
+ : dispatcher_(dispatcher) {}
+ ClearStatelessResetAddressesAlarm(const DeleteSessionsAlarm&) = delete;
+ ClearStatelessResetAddressesAlarm& operator=(const DeleteSessionsAlarm&) =
+ delete;
+
+ void OnAlarm() override { dispatcher_->ClearStatelessResetAddresses(); }
+
+ private:
+ // Not owned.
+ QuicDispatcher* dispatcher_;
+};
+
// Collects packets serialized by a QuicPacketCreator in order
// to be handed off to the time wait list manager.
class PacketCollector : public QuicPacketCreator::DelegateInterface,
@@ -159,7 +177,6 @@ class StatelessConnectionTerminator {
SerializeConnectionClosePacket(error_code, error_details);
time_wait_list_manager_->AddConnectionIdToTimeWait(
- server_connection_id_,
QuicTimeWaitListManager::SEND_TERMINATION_PACKETS,
TimeWaitConnectionInfo(ietf_quic, collector_.packets(),
std::move(active_connection_ids),
@@ -311,8 +328,7 @@ bool MaybeHandleLegacyVersionEncapsulation(
} // namespace
QuicDispatcher::QuicDispatcher(
- const QuicConfig* config,
- const QuicCryptoServerConfig* crypto_config,
+ const QuicConfig* config, const QuicCryptoServerConfig* crypto_config,
QuicVersionManager* version_manager,
std::unique_ptr<QuicConnectionHelperInterface> helper,
std::unique_ptr<QuicCryptoServerStreamBase::Helper> session_helper,
@@ -335,19 +351,22 @@ QuicDispatcher::QuicDispatcher(
allow_short_initial_server_connection_ids_(false),
expected_server_connection_id_length_(
expected_server_connection_id_length),
+ clear_stateless_reset_addresses_alarm_(alarm_factory_->CreateAlarm(
+ new ClearStatelessResetAddressesAlarm(this))),
should_update_expected_server_connection_id_length_(false) {
QUIC_BUG_IF(quic_bug_12724_1, GetSupportedVersions().empty())
<< "Trying to create dispatcher without any supported versions";
QUIC_DLOG(INFO) << "Created QuicDispatcher with versions: "
<< ParsedQuicVersionVectorToString(GetSupportedVersions());
- QUIC_RESTART_FLAG_COUNT(quic_alarm_add_permanent_cancel);
}
QuicDispatcher::~QuicDispatcher() {
- if (GetQuicRestartFlag(quic_alarm_add_permanent_cancel) &&
- delete_sessions_alarm_ != nullptr) {
+ if (delete_sessions_alarm_ != nullptr) {
delete_sessions_alarm_->PermanentCancel();
}
+ if (clear_stateless_reset_addresses_alarm_ != nullptr) {
+ clear_stateless_reset_addresses_alarm_->PermanentCancel();
+ }
reference_counted_session_map_.clear();
closed_ref_counted_session_list_.clear();
if (support_multiple_cid_per_connection_) {
@@ -480,12 +499,54 @@ QuicConnectionId QuicDispatcher::ReplaceLongServerConnectionId(
server_connection_id, expected_server_connection_id_length);
}
+namespace {
+inline bool IsSourceUdpPortBlocked(uint16_t port) {
+ // TODO(dschinazi) make this function constexpr when we remove flag
+ // protection.
+ if (!GetQuicReloadableFlag(quic_blocked_ports)) {
+ return port == 0;
+ }
+ QUIC_RELOADABLE_FLAG_COUNT(quic_blocked_ports);
+ // These UDP source ports have been observed in large scale denial of service
+ // attacks and are not expected to ever carry user traffic, they are therefore
+ // blocked as a safety measure. See draft-ietf-quic-applicability for details.
+ constexpr uint16_t blocked_ports[] = {
+ 0, // We cannot send to port 0 so drop that source port.
+ 17, // Quote of the Day, can loop with QUIC.
+ 19, // Chargen, can loop with QUIC.
+ 53, // DNS, vulnerable to reflection attacks.
+ 111, // Portmap.
+ 123, // NTP, vulnerable to reflection attacks.
+ 137, // NETBIOS Name Service,
+ 128, // NETBIOS Datagram Service
+ 161, // SNMP.
+ 389, // CLDAP.
+ 500, // IKE, can loop with QUIC.
+ 1900, // SSDP, vulnerable to reflection attacks.
+ 5353, // mDNS, vulnerable to reflection attacks.
+ 11211, // memcache, vulnerable to reflection attacks.
+ // This list MUST be sorted in increasing order.
+ };
+ constexpr size_t num_blocked_ports = ABSL_ARRAYSIZE(blocked_ports);
+ constexpr uint16_t highest_blocked_port =
+ blocked_ports[num_blocked_ports - 1];
+ if (QUICHE_PREDICT_TRUE(port > highest_blocked_port)) {
+ // Early-return to skip comparisons for the majority of traffic.
+ return false;
+ }
+ for (size_t i = 0; i < num_blocked_ports; i++) {
+ if (port == blocked_ports[i]) {
+ return true;
+ }
+ }
+ return false;
+}
+} // namespace
+
bool QuicDispatcher::MaybeDispatchPacket(
const ReceivedPacketInfo& packet_info) {
- // Port zero is only allowed for unidirectional UDP, so is disallowed by QUIC.
- // Given that we can't even send a reply rejecting the packet, just drop the
- // packet.
- if (packet_info.peer_address.port() == 0) {
+ if (IsSourceUdpPortBlocked(packet_info.peer_address.port())) {
+ // Silently drop the received packet.
return true;
}
@@ -512,19 +573,16 @@ bool QuicDispatcher::MaybeDispatchPacket(
return true;
}
- if (GetQuicReloadableFlag(quic_discard_packets_with_invalid_cid)) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_discard_packets_with_invalid_cid);
- if (packet_info.version_flag && packet_info.version.IsKnown() &&
- !QuicUtils::IsConnectionIdLengthValidForVersion(
- server_connection_id.length(),
- packet_info.version.transport_version)) {
- QUIC_DLOG(INFO) << "Packet with destination connection ID "
- << server_connection_id << " is invalid with version "
- << packet_info.version;
- // Drop the packet silently.
- QUIC_CODE_COUNT(quic_dropped_invalid_initial_connection_id);
- return true;
- }
+ if (packet_info.version_flag && packet_info.version.IsKnown() &&
+ !QuicUtils::IsConnectionIdLengthValidForVersion(
+ server_connection_id.length(),
+ packet_info.version.transport_version)) {
+ QUIC_DLOG(INFO) << "Packet with destination connection ID "
+ << server_connection_id << " is invalid with version "
+ << packet_info.version;
+ // Drop the packet silently.
+ QUIC_CODE_COUNT(quic_dropped_invalid_initial_connection_id);
+ return true;
}
// Packets with connection IDs for active connections are processed
@@ -879,7 +937,7 @@ void QuicDispatcher::CleanUpSession(QuicConnectionId server_connection_id,
QUIC_CODE_COUNT(quic_v44_add_to_time_wait_list_with_stateless_reset);
}
time_wait_list_manager_->AddConnectionIdToTimeWait(
- server_connection_id, action,
+ action,
TimeWaitConnectionInfo(
connection->version().HasIetfInvariantHeader(),
connection->termination_packets(),
@@ -944,6 +1002,10 @@ void QuicDispatcher::DeleteSessions() {
closed_ref_counted_session_list_.clear();
}
+void QuicDispatcher::ClearStatelessResetAddresses() {
+ recent_stateless_reset_addresses_.clear();
+}
+
void QuicDispatcher::OnCanWrite() {
// The socket is now writable.
writer_->SetWritable();
@@ -1098,9 +1160,8 @@ void QuicDispatcher::StatelesslyTerminateConnection(
<< ", error_code:" << error_code
<< ", error_details:" << error_details;
time_wait_list_manager_->AddConnectionIdToTimeWait(
- server_connection_id, action,
- TimeWaitConnectionInfo(format != GOOGLE_QUIC_PACKET, nullptr,
- {server_connection_id}));
+ action, TimeWaitConnectionInfo(format != GOOGLE_QUIC_PACKET, nullptr,
+ {server_connection_id}));
return;
}
@@ -1138,7 +1199,7 @@ void QuicDispatcher::StatelesslyTerminateConnection(
/*ietf_quic=*/format != GOOGLE_QUIC_PACKET, use_length_prefix,
/*versions=*/{}));
time_wait_list_manager()->AddConnectionIdToTimeWait(
- server_connection_id, QuicTimeWaitListManager::SEND_TERMINATION_PACKETS,
+ QuicTimeWaitListManager::SEND_TERMINATION_PACKETS,
TimeWaitConnectionInfo(/*ietf_quic=*/format != GOOGLE_QUIC_PACKET,
&termination_packets, {server_connection_id}));
}
@@ -1369,8 +1430,14 @@ bool QuicDispatcher::IsSupportedVersion(const ParsedQuicVersion version) {
void QuicDispatcher::MaybeResetPacketsWithNoVersion(
const ReceivedPacketInfo& packet_info) {
QUICHE_DCHECK(!packet_info.version_flag);
- if (GetQuicRestartFlag(quic_fix_stateless_reset2) &&
- packet_info.form != GOOGLE_QUIC_PACKET) {
+ // Do not send a stateless reset if a reset has been sent to this address
+ // recently.
+ if (recent_stateless_reset_addresses_.contains(packet_info.peer_address)) {
+ QUIC_CODE_COUNT(quic_donot_send_reset_repeatedly);
+ QUICHE_DCHECK(use_recent_reset_addresses_);
+ return;
+ }
+ if (packet_info.form != GOOGLE_QUIC_PACKET) {
// Drop IETF packets smaller than the minimal stateless reset length.
if (packet_info.packet.length() <=
QuicFramer::GetMinStatelessResetPacketLength()) {
@@ -1386,8 +1453,24 @@ void QuicDispatcher::MaybeResetPacketsWithNoVersion(
QUIC_CODE_COUNT(drop_too_small_packets);
return;
}
- // TODO(fayang): Consider rate limiting reset packets if reset packet size >
- // packet_length.
+ }
+ if (use_recent_reset_addresses_) {
+ QUIC_RESTART_FLAG_COUNT(quic_use_recent_reset_addresses);
+ // Do not send a stateless reset if there are too many stateless reset
+ // addresses.
+ if (recent_stateless_reset_addresses_.size() >=
+ GetQuicFlag(FLAGS_quic_max_recent_stateless_reset_addresses)) {
+ QUIC_CODE_COUNT(quic_too_many_recent_reset_addresses);
+ return;
+ }
+ if (recent_stateless_reset_addresses_.empty()) {
+ clear_stateless_reset_addresses_alarm_->Update(
+ helper()->GetClock()->ApproximateNow() +
+ QuicTime::Delta::FromMilliseconds(GetQuicFlag(
+ FLAGS_quic_recent_stateless_reset_addresses_lifetime_ms)),
+ QuicTime::Delta::Zero());
+ }
+ recent_stateless_reset_addresses_.emplace(packet_info.peer_address);
}
time_wait_list_manager()->SendPublicReset(
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 a6ba1a6e975..0073666fd62 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
@@ -131,6 +131,9 @@ class QUIC_NO_EXPORT QuicDispatcher
// Deletes all sessions on the closed session list and clears the list.
virtual void DeleteSessions();
+ // Clear recent_stateless_reset_addresses_.
+ void ClearStatelessResetAddresses();
+
using ConnectionIdMap = absl::
flat_hash_map<QuicConnectionId, QuicConnectionId, QuicConnectionIdHash>;
@@ -473,12 +476,21 @@ class QUIC_NO_EXPORT QuicDispatcher
// version does not allow variable length connection ID.
uint8_t expected_server_connection_id_length_;
+ // Records client addresses that have been recently reset.
+ absl::flat_hash_set<QuicSocketAddress, QuicSocketAddressHash>
+ recent_stateless_reset_addresses_;
+
+ // An alarm which clear recent_stateless_reset_addresses_.
+ std::unique_ptr<QuicAlarm> clear_stateless_reset_addresses_alarm_;
+
// If true, change expected_server_connection_id_length_ to be the received
// destination connection ID length of all IETF long headers.
bool should_update_expected_server_connection_id_length_;
+ const bool use_recent_reset_addresses_ =
+ GetQuicRestartFlag(quic_use_recent_reset_addresses);
+
const bool support_multiple_cid_per_connection_ =
- GetQuicRestartFlag(quic_time_wait_list_support_multiple_cid_v2) &&
GetQuicRestartFlag(
quic_dispatcher_support_multiple_cid_per_connection_v2);
};
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher_test.cc
index 3a98be3df90..218096230c6 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
@@ -121,15 +121,12 @@ class TestDispatcher : public QuicDispatcher {
public:
TestDispatcher(const QuicConfig* config,
const QuicCryptoServerConfig* crypto_config,
- QuicVersionManager* version_manager,
- QuicRandom* random)
- : QuicDispatcher(config,
- crypto_config,
- version_manager,
+ QuicVersionManager* version_manager, QuicRandom* random)
+ : QuicDispatcher(config, crypto_config, version_manager,
std::make_unique<MockQuicConnectionHelper>(),
std::unique_ptr<QuicCryptoServerStreamBase::Helper>(
new QuicSimpleCryptoServerStreamHelper()),
- std::make_unique<MockAlarmFactory>(),
+ std::make_unique<TestAlarmFactory>(),
kQuicDefaultConnectionIdLength),
random_(random) {}
@@ -500,6 +497,11 @@ class QuicDispatcherTestBase : public QuicTestWithParam<ParsedQuicVersion> {
const QuicConnectionId& server_connection_id,
const QuicConnectionId& client_connection_id);
+ TestAlarmFactory::TestAlarm* GetClearResetAddressesAlarm() {
+ return reinterpret_cast<TestAlarmFactory::TestAlarm*>(
+ QuicDispatcherPeer::GetClearResetAddressesAlarm(dispatcher_.get()));
+ }
+
ParsedQuicVersion version_;
MockQuicConnectionHelper mock_helper_;
MockAlarmFactory mock_alarm_factory_;
@@ -895,7 +897,7 @@ TEST_P(QuicDispatcherTestAllVersions, TimeWaitListManager) {
EXPECT_CALL(*time_wait_list_manager_,
ProcessPacket(_, _, connection_id, _, _, _))
.Times(1);
- EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _, _))
+ EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _))
.Times(0);
ProcessPacket(client_address, connection_id, true, "data");
}
@@ -911,7 +913,7 @@ TEST_P(QuicDispatcherTestAllVersions, NoVersionPacketToTimeWaitListManager) {
EXPECT_CALL(*time_wait_list_manager_,
ProcessPacket(_, _, connection_id, _, _, _))
.Times(0);
- EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _, _))
+ EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _))
.Times(0);
EXPECT_CALL(*time_wait_list_manager_, SendPublicReset(_, _, _, _, _, _))
.Times(1);
@@ -933,7 +935,7 @@ TEST_P(QuicDispatcherTestAllVersions,
EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _, _, _)).Times(0);
EXPECT_CALL(*time_wait_list_manager_, ProcessPacket(_, _, _, _, _, _))
.Times(0);
- EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _, _))
+ EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _))
.Times(0);
// Verify small packet is silently dropped.
EXPECT_CALL(*time_wait_list_manager_, SendPublicReset(_, _, _, _, _, _))
@@ -944,6 +946,120 @@ TEST_P(QuicDispatcherTestAllVersions,
dispatcher_->ProcessPacket(server_address_, client_address, packet2);
}
+TEST_P(QuicDispatcherTestOneVersion, DropPacketWithInvalidFlags) {
+ QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
+ CreateTimeWaitListManager();
+ uint8_t all_zero_packet[1200] = {};
+ QuicReceivedPacket packet(reinterpret_cast<char*>(all_zero_packet),
+ sizeof(all_zero_packet), QuicTime::Zero());
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _, _, _)).Times(0);
+ EXPECT_CALL(*time_wait_list_manager_, ProcessPacket(_, _, _, _, _, _))
+ .Times(0);
+ EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _))
+ .Times(0);
+ EXPECT_CALL(*time_wait_list_manager_, SendPublicReset(_, _, _, _, _, _))
+ .Times(0);
+ dispatcher_->ProcessPacket(server_address_, client_address, packet);
+}
+
+TEST_P(QuicDispatcherTestAllVersions, LimitResetsToSameClientAddress) {
+ CreateTimeWaitListManager();
+
+ QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
+ QuicSocketAddress client_address2(QuicIpAddress::Loopback4(), 2);
+ QuicSocketAddress client_address3(QuicIpAddress::Loopback6(), 1);
+ QuicConnectionId connection_id = TestConnectionId(1);
+
+ if (GetQuicRestartFlag(quic_use_recent_reset_addresses)) {
+ // Verify only one reset is sent to the address, although multiple packets
+ // are received.
+ EXPECT_CALL(*time_wait_list_manager_, SendPublicReset(_, _, _, _, _, _))
+ .Times(1);
+ } else {
+ EXPECT_CALL(*time_wait_list_manager_, SendPublicReset(_, _, _, _, _, _))
+ .Times(3);
+ }
+ ProcessPacket(client_address, connection_id, /*has_version_flag=*/false,
+ "data");
+ ProcessPacket(client_address, connection_id, /*has_version_flag=*/false,
+ "data2");
+ ProcessPacket(client_address, connection_id, /*has_version_flag=*/false,
+ "data3");
+
+ EXPECT_CALL(*time_wait_list_manager_, SendPublicReset(_, _, _, _, _, _))
+ .Times(2);
+ ProcessPacket(client_address2, connection_id, /*has_version_flag=*/false,
+ "data");
+ ProcessPacket(client_address3, connection_id, /*has_version_flag=*/false,
+ "data");
+}
+
+TEST_P(QuicDispatcherTestAllVersions,
+ StopSendingResetOnTooManyRecentAddresses) {
+ SetQuicFlag(FLAGS_quic_max_recent_stateless_reset_addresses, 2);
+ const size_t kTestLifeTimeMs = 10;
+ SetQuicFlag(FLAGS_quic_recent_stateless_reset_addresses_lifetime_ms,
+ kTestLifeTimeMs);
+ CreateTimeWaitListManager();
+
+ QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
+ QuicSocketAddress client_address2(QuicIpAddress::Loopback4(), 2);
+ QuicSocketAddress client_address3(QuicIpAddress::Loopback6(), 1);
+ QuicConnectionId connection_id = TestConnectionId(1);
+
+ EXPECT_CALL(*time_wait_list_manager_, SendPublicReset(_, _, _, _, _, _))
+ .Times(2);
+ EXPECT_FALSE(GetClearResetAddressesAlarm()->IsSet());
+ ProcessPacket(client_address, connection_id, /*has_version_flag=*/false,
+ "data");
+ const QuicTime expected_deadline =
+ mock_helper_.GetClock()->Now() +
+ QuicTime::Delta::FromMilliseconds(kTestLifeTimeMs);
+ if (GetQuicRestartFlag(quic_use_recent_reset_addresses)) {
+ ASSERT_TRUE(GetClearResetAddressesAlarm()->IsSet());
+ EXPECT_EQ(expected_deadline, GetClearResetAddressesAlarm()->deadline());
+ } else {
+ EXPECT_FALSE(GetClearResetAddressesAlarm()->IsSet());
+ }
+ // Received no version packet 2 after 5ms.
+ mock_helper_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
+ ProcessPacket(client_address2, connection_id, /*has_version_flag=*/false,
+ "data");
+ if (GetQuicRestartFlag(quic_use_recent_reset_addresses)) {
+ ASSERT_TRUE(GetClearResetAddressesAlarm()->IsSet());
+ // Verify deadline does not change.
+ EXPECT_EQ(expected_deadline, GetClearResetAddressesAlarm()->deadline());
+ } else {
+ EXPECT_FALSE(GetClearResetAddressesAlarm()->IsSet());
+ }
+ if (GetQuicRestartFlag(quic_use_recent_reset_addresses)) {
+ // Verify reset gets throttled since there are too many recent addresses.
+ EXPECT_CALL(*time_wait_list_manager_, SendPublicReset(_, _, _, _, _, _))
+ .Times(0);
+ } else {
+ EXPECT_CALL(*time_wait_list_manager_, SendPublicReset(_, _, _, _, _, _))
+ .Times(1);
+ }
+ ProcessPacket(client_address3, connection_id, /*has_version_flag=*/false,
+ "data");
+
+ mock_helper_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
+ if (GetQuicRestartFlag(quic_use_recent_reset_addresses)) {
+ GetClearResetAddressesAlarm()->Fire();
+ EXPECT_CALL(*time_wait_list_manager_, SendPublicReset(_, _, _, _, _, _))
+ .Times(2);
+ } else {
+ EXPECT_CALL(*time_wait_list_manager_, SendPublicReset(_, _, _, _, _, _))
+ .Times(3);
+ }
+ ProcessPacket(client_address, connection_id, /*has_version_flag=*/false,
+ "data");
+ ProcessPacket(client_address2, connection_id, /*has_version_flag=*/false,
+ "data");
+ ProcessPacket(client_address3, connection_id, /*has_version_flag=*/false,
+ "data");
+}
+
// Makes sure nine-byte connection IDs are replaced by 8-byte ones.
TEST_P(QuicDispatcherTestAllVersions, LongConnectionIdLengthReplaced) {
if (!version_.AllowsVariableLengthConnectionIds()) {
@@ -1080,12 +1196,49 @@ TEST_P(QuicDispatcherTestAllVersions, ProcessPacketWithZeroPort) {
.Times(0);
EXPECT_CALL(*time_wait_list_manager_, ProcessPacket(_, _, _, _, _, _))
.Times(0);
- EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _, _))
+ EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _))
.Times(0);
ProcessPacket(client_address, TestConnectionId(1), /*has_version_flag=*/true,
"data");
}
+TEST_P(QuicDispatcherTestAllVersions, ProcessPacketWithBlockedPort) {
+ SetQuicReloadableFlag(quic_blocked_ports, true);
+ CreateTimeWaitListManager();
+
+ QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 17);
+
+ // dispatcher_ should drop this packet.
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(TestConnectionId(1), _,
+ client_address, _, _, _))
+ .Times(0);
+ EXPECT_CALL(*time_wait_list_manager_, ProcessPacket(_, _, _, _, _, _))
+ .Times(0);
+ EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _))
+ .Times(0);
+ ProcessPacket(client_address, TestConnectionId(1), /*has_version_flag=*/true,
+ "data");
+}
+
+TEST_P(QuicDispatcherTestAllVersions, ProcessPacketWithNonBlockedPort) {
+ CreateTimeWaitListManager();
+
+ // Port 443 must not be blocked because it might be useful for proxies to send
+ // proxied traffic with source port 443 as that allows building a full QUIC
+ // proxy using a single UDP socket.
+ QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 443);
+
+ // dispatcher_ should not drop this packet.
+ EXPECT_CALL(*dispatcher_,
+ CreateQuicSession(TestConnectionId(1), _, client_address,
+ Eq(ExpectedAlpn()), _, _))
+ .WillOnce(Return(ByMove(CreateSession(
+ dispatcher_.get(), config_, TestConnectionId(1), client_address,
+ &mock_helper_, &mock_alarm_factory_, &crypto_config_,
+ QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_))));
+ ProcessFirstFlight(client_address, TestConnectionId(1));
+}
+
TEST_P(QuicDispatcherTestAllVersions,
DropPacketWithKnownVersionAndInvalidShortInitialConnectionId) {
if (!version_.AllowsVariableLengthConnectionIds()) {
@@ -1099,14 +1252,13 @@ TEST_P(QuicDispatcherTestAllVersions,
EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _, _, _)).Times(0);
EXPECT_CALL(*time_wait_list_manager_, ProcessPacket(_, _, _, _, _, _))
.Times(0);
- EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _, _))
+ EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _))
.Times(0);
ProcessFirstFlight(client_address, EmptyQuicConnectionId());
}
TEST_P(QuicDispatcherTestAllVersions,
DropPacketWithKnownVersionAndInvalidInitialConnectionId) {
- SetQuicReloadableFlag(quic_discard_packets_with_invalid_cid, true);
CreateTimeWaitListManager();
QuicSocketAddress server_address;
@@ -1116,7 +1268,7 @@ TEST_P(QuicDispatcherTestAllVersions,
EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _, _, _)).Times(0);
EXPECT_CALL(*time_wait_list_manager_, ProcessPacket(_, _, _, _, _, _))
.Times(0);
- EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _, _))
+ EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _))
.Times(0);
absl::string_view cid_str = "123456789abcdefg123456789abcdefg";
QuicConnectionId invalid_connection_id(cid_str.data(), cid_str.length());
@@ -1538,7 +1690,7 @@ TEST_P(QuicDispatcherTestAllVersions, DoNotProcessSmallPacket) {
EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _, _, _)).Times(0);
EXPECT_CALL(*time_wait_list_manager_, SendPacket(_, _, _)).Times(0);
- EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _, _))
+ EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _))
.Times(0);
ProcessPacket(client_address, TestConnectionId(1), /*has_version_flag=*/true,
version_, SerializeCHLO(), /*full_padding=*/false,
@@ -1691,7 +1843,7 @@ TEST_P(QuicDispatcherTestStrayPacketConnectionId,
EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _, _, _)).Times(0);
EXPECT_CALL(*time_wait_list_manager_, ProcessPacket(_, _, _, _, _, _))
.Times(0);
- EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _, _))
+ EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _))
.Times(0);
ProcessPacket(client_address, connection_id, true, "data",
@@ -2006,7 +2158,6 @@ class QuicDispatcherSupportMultipleConnectionIdPerConnectionTest
public:
QuicDispatcherSupportMultipleConnectionIdPerConnectionTest()
: QuicDispatcherTestBase(crypto_test_utils::ProofSourceForTesting()) {
- SetQuicRestartFlag(quic_time_wait_list_support_multiple_cid_v2, true);
SetQuicRestartFlag(quic_dispatcher_support_multiple_cid_per_connection_v2,
true);
dispatcher_ = std::make_unique<NiceMock<TestDispatcher>>(
@@ -2318,7 +2469,7 @@ TEST_P(BufferedPacketStoreTest,
// A bunch of non-CHLO should be buffered upon arrival.
size_t kNumConnections = kMaxConnectionsWithoutCHLO + 1;
for (size_t i = 1; i <= kNumConnections; ++i) {
- QuicSocketAddress client_address(QuicIpAddress::Loopback4(), i);
+ QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 20000 + i);
QuicConnectionId conn_id = TestConnectionId(i);
EXPECT_CALL(*dispatcher_,
ShouldCreateOrBufferPacketForConnection(
@@ -2336,7 +2487,7 @@ TEST_P(BufferedPacketStoreTest,
kNumConnections);
// Process CHLOs to create session for these connections.
for (size_t i = 1; i <= kNumConnections; ++i) {
- QuicSocketAddress client_address(QuicIpAddress::Loopback4(), i);
+ QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 20000 + i);
QuicConnectionId conn_id = TestConnectionId(i);
if (i == kNumConnections) {
EXPECT_CALL(*dispatcher_,
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_epoll_alarm_factory_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_epoll_alarm_factory_test.cc
index e2268dbb502..d815fae8f4d 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_epoll_alarm_factory_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_epoll_alarm_factory_test.cc
@@ -12,7 +12,7 @@ namespace quic {
namespace test {
namespace {
-class TestDelegate : public QuicAlarm::Delegate {
+class TestDelegate : public QuicAlarm::DelegateWithoutContext {
public:
TestDelegate() : fired_(false) {}
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 c3fcb887066..162cb04e4d0 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
@@ -275,6 +275,8 @@ const char* QuicErrorCodeToString(QuicErrorCode error) {
RETURN_STRING_LITERAL(QUIC_TLS_UNRECOGNIZED_NAME);
RETURN_STRING_LITERAL(QUIC_TLS_CERTIFICATE_REQUIRED);
+ RETURN_STRING_LITERAL(QUIC_INVALID_CHARACTER_IN_FIELD_VALUE);
+
RETURN_STRING_LITERAL(QUIC_LAST_ERROR);
// Intentionally have no default case, so we'll break the build
// if we add errors and don't put them here.
@@ -772,6 +774,8 @@ QuicErrorCodeToIetfMapping QuicErrorCodeToTransportErrorCode(
return {true, static_cast<uint64_t>(CONNECTION_ID_LIMIT_ERROR)};
case QUIC_TOO_MANY_CONNECTION_ID_WAITING_TO_RETIRE:
return {true, static_cast<uint64_t>(INTERNAL_ERROR)};
+ case QUIC_INVALID_CHARACTER_IN_FIELD_VALUE:
+ return {false, static_cast<uint64_t>(QuicHttp3ErrorCode::MESSAGE_ERROR)};
case QUIC_LAST_ERROR:
return {false, static_cast<uint64_t>(QUIC_LAST_ERROR)};
}
@@ -939,6 +943,19 @@ QuicRstStreamErrorCode IetfResetStreamErrorCodeToRstStreamErrorCode(
return QUIC_STREAM_UNKNOWN_APPLICATION_ERROR_CODE;
}
+// static
+QuicResetStreamError QuicResetStreamError::FromInternal(
+ QuicRstStreamErrorCode code) {
+ return QuicResetStreamError(
+ code, RstStreamErrorCodeToIetfResetStreamErrorCode(code));
+}
+
+// static
+QuicResetStreamError QuicResetStreamError::FromIetf(uint64_t code) {
+ return QuicResetStreamError(
+ IetfResetStreamErrorCodeToRstStreamErrorCode(code), 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 53a881014ce..860f107e137 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
@@ -599,8 +599,11 @@ enum QuicErrorCode {
QUIC_TLS_UNRECOGNIZED_NAME = 201,
QUIC_TLS_CERTIFICATE_REQUIRED = 202,
+ // An HTTP field value containing an invalid character has been received.
+ QUIC_INVALID_CHARACTER_IN_FIELD_VALUE = 206,
+
// No error. Used as bound while iterating.
- QUIC_LAST_ERROR = 206,
+ QUIC_LAST_ERROR = 207,
};
// 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
@@ -609,6 +612,45 @@ static_assert(static_cast<uint64_t>(QUIC_LAST_ERROR) <=
static_cast<uint64_t>(std::numeric_limits<uint32_t>::max()),
"QuicErrorCode exceeds four octets");
+// Represents a reason for resetting a stream in both gQUIC and IETF error code
+// space. Both error codes have to be present.
+class QUIC_EXPORT_PRIVATE QuicResetStreamError {
+ public:
+ // Constructs a QuicResetStreamError from QuicRstStreamErrorCode; the IETF
+ // error code is inferred.
+ static QuicResetStreamError FromInternal(QuicRstStreamErrorCode code);
+ // Constructs a QuicResetStreamError from an IETF error code; the internal
+ // error code is inferred.
+ static QuicResetStreamError FromIetf(uint64_t code);
+ // Constructs a QuicResetStreamError with no error.
+ static QuicResetStreamError NoError() {
+ return FromInternal(QUIC_STREAM_NO_ERROR);
+ }
+
+ QuicResetStreamError(QuicRstStreamErrorCode internal_code,
+ uint64_t ietf_application_code)
+ : internal_code_(internal_code),
+ ietf_application_code_(ietf_application_code) {}
+
+ QuicRstStreamErrorCode internal_code() const { return internal_code_; }
+ uint64_t ietf_application_code() const { return ietf_application_code_; }
+
+ bool operator==(const QuicResetStreamError& other) const {
+ return internal_code() == other.internal_code() &&
+ ietf_application_code() == other.ietf_application_code();
+ }
+
+ // Returns true if the object holds no error.
+ bool ok() const { return internal_code() == QUIC_STREAM_NO_ERROR; }
+
+ private:
+ // Error code used in gQUIC. Even when IETF QUIC is in use, this needs to be
+ // populated as we use those internally.
+ QuicRstStreamErrorCode internal_code_;
+ // Application error code used in IETF QUIC.
+ uint64_t ietf_application_code_;
+};
+
// Convert TLS alert code to QuicErrorCode.
QUIC_EXPORT_PRIVATE QuicErrorCode TlsAlertToQuicErrorCode(uint8_t desc);
@@ -645,8 +687,7 @@ QUIC_EXPORT_PRIVATE std::string QuicIetfTransportErrorCodeString(
QuicIetfTransportErrorCodes c);
QUIC_EXPORT_PRIVATE std::ostream& operator<<(
- std::ostream& os,
- const QuicIetfTransportErrorCodes& c);
+ 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.
@@ -678,6 +719,7 @@ enum class QuicHttp3ErrorCode {
REQUEST_REJECTED = 0x10B,
REQUEST_CANCELLED = 0x10C,
REQUEST_INCOMPLETE = 0x10D,
+ MESSAGE_ERROR = 0x10E,
CONNECT_ERROR = 0x10F,
VERSION_FALLBACK = 0x110,
};
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_flags_list.h b/chromium/net/third_party/quiche/src/quic/core/quic_flags_list.h
index 9bb54b26abd..4399efaccf5 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_flags_list.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_flags_list.h
@@ -6,8 +6,6 @@
#ifdef QUIC_FLAG
-QUIC_FLAG(FLAGS_quic_restart_flag_dont_fetch_quic_private_keys_from_leto, false)
-
QUIC_FLAG(FLAGS_quic_restart_flag_quic_offload_pacing_to_usps2, false)
// A testonly reloadable flag that will always default to false.
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_testonly_default_false, false)
@@ -17,38 +15,40 @@ QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_testonly_default_true, true)
QUIC_FLAG(FLAGS_quic_restart_flag_quic_testonly_default_false, false)
// A testonly restart flag that will always default to true.
QUIC_FLAG(FLAGS_quic_restart_flag_quic_testonly_default_true, true)
-// If true and a QUIC connection is traced, add ssl events to the trace.
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_trace_ssl_events, true)
-// If true, GFE will explicitly configure its signature algorithm preference.
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_tls_set_signature_algorithm_prefs, false)
+// If bytes in flight has dipped below 1.25*MaxBW in the last round, do not exit PROBE_UP due to excess queue buildup.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_bbr2_no_probe_up_exit_if_no_queue, true)
+// If true and connection option B201 is used, check if cwnd limited before aggregation epoch, instead of ack event, in PROBE_UP phase.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_bbr2_check_cwnd_limited_before_aggregation_epoch, true)
+// If true, QPACK decoder rejects CR, LF, and NULL in field (header) values, and causes the stream to be reset with H3_MESSAGE_ERROR.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_reject_invalid_chars_in_field_value, true)
// If true, QUIC will default enable MTU discovery at server, with a target of 1450 bytes.
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_enable_mtu_discovery_at_server, false)
+// If true, QuicAlarms that belong to a single QuicConnection will fire under the corresponding QuicConnectionContext.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_restore_connection_context_in_alarms, true)
// If true, QuicGsoBatchWriter will support release time if it is available and the process has the permission to do so.
QUIC_FLAG(FLAGS_quic_restart_flag_quic_support_release_time_for_gso, false)
-// If true, QuicIdleNetworkDetector::SetAlarm will become a noop if dectection has been stopped by QuicIdleNetworkDetector::StopDetection.
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_idle_network_detector_no_alarm_after_stopped, true)
-// If true, TlsServerHandshaker::DefaultProofSourceHandle::DefaultSignatureCallback will run at most once.
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_run_default_signature_callback_once, true)
// If true, abort async QPACK header decompression in QuicSpdyStream::Reset() and in QuicSpdyStream::OnStreamReset().
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_abort_qpack_on_stream_reset, true)
// If true, ack frequency frame can be sent from server to client.
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_can_send_ack_frequency, true)
// If true, add missing MaybeUpdateAckTimeout for ack-eliciting frames.
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_add_missing_update_ack_timeout, true)
-// If true, allow QuicAlarm to be permanently cancelled.
-QUIC_FLAG(FLAGS_quic_restart_flag_quic_alarm_add_permanent_cancel, false)
// If true, allow client to enable BBRv2 on server via connection option \'B2ON\'.
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_allow_client_enabled_bbr_v2, false)
-// If true, allow ticket open to be ignored in TlsServerHandshaker. Also fixes TlsServerHandshaker::ResumptionAttempted when handshake hints is used.
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_tls_allow_ignore_ticket_open, true)
+// If true, always starts a new ack aggregation epoch if a full round has passed since the start of the current epoch.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_bbr_start_new_aggregation_epoch_after_a_full_round, true)
+// If true, avoid calling reloadable flags in QuicVersionManager constructor by lazily initializing internal state.
+QUIC_FLAG(FLAGS_quic_restart_flag_quic_lazy_quic_version_manager, true)
+// If true, clear undecryptable packets on handshake complete.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_clear_undecryptable_packets_on_handshake_complete, true)
// If true, close read side but not write side in QuicSpdyStream::OnStreamReset().
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_fix_on_stream_reset, true)
// If true, default on PTO which unifies TLP + RTO loss recovery.
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_default_on_pto, false)
// If true, default-enable 5RTO blachole detection.
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_default_enable_5rto_blackhole_detection2, true)
-// If true, determine stateless reset packet length based on the received packet length.
-QUIC_FLAG(FLAGS_quic_restart_flag_quic_fix_stateless_reset2, true)
+// If true, delay block allocation in QuicStreamSequencerBuffer until there is actually new data available.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_delay_sequencer_buffer_allocation_until_new_data, false)
// If true, disable QUIC version Q043.
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_disable_version_q043, false)
// If true, disable QUIC version Q046.
@@ -60,7 +60,7 @@ QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_disable_version_rfcv1, false)
// If true, disable QUIC version h3-29.
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_disable_version_draft_29, false)
// If true, disable QUIC version h3-T051.
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_disable_version_t051, false)
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_disable_version_t051, true)
// If true, disable blackhole detection on server side.
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_disable_server_blackhole_detection, false)
// If true, discard INITIAL packet if the key has been dropped.
@@ -75,58 +75,68 @@ QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_donot_rearm_pto_on_application_data_du
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_drop_unsent_path_response, true)
// If true, enable server retransmittable on wire PING.
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_enable_server_on_wire_ping, true)
+// If true, ietf connection migration is no longer conditioned on connection option RVCM.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_remove_connection_migration_connection_option, true)
// If true, ignore peer_max_ack_delay during handshake.
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_ignore_peer_max_ack_delay_during_handshake, true)
-// If true, include non-default port in the origin field of the ACCEPT_CH frame in ALPS.
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_include_port_in_alps_origin, true)
// If true, include stream information in idle timeout connection close detail.
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_add_stream_info_to_idle_close_detail, true)
-// If true, increase the size of stream sequencer buffer block container on demand.
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_allocate_stream_sequencer_buffer_blocks_on_demand, false)
// If true, pass the received PATH_RESPONSE payload to path validator to move forward the path validation.
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_pass_path_response_to_validator, true)
-// If true, quic connection sends/recieives NewConnectionId & RetireConnectionId frames.
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_connection_support_multiple_cids_v4, true)
-// If true, quic dispatcher discards packets with invalid server connection ID.
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_discard_packets_with_invalid_cid, true)
// If true, quic dispatcher supports one connection to use multiple connection IDs.
QUIC_FLAG(FLAGS_quic_restart_flag_quic_dispatcher_support_multiple_cid_per_connection_v2, true)
-// If true, receiving server push stream will trigger QUIC connection close.
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_decline_server_push_stream, false)
+// If true, record addresses that server has sent reset to recently, and do not send reset if the address lives in the set.
+QUIC_FLAG(FLAGS_quic_restart_flag_quic_use_recent_reset_addresses, true)
+// If true, refactor how QUIC TLS server disables resumption. No behavior change.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_tls_disable_resumption_refactor, true)
// If true, require handshake confirmation for QUIC connections, functionally disabling 0-rtt handshakes.
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_require_handshake_confirmation, false)
// If true, reset per packet state before processing undecryptable packets.
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_reset_per_packet_state_for_undecryptable_packets, true)
+// If true, respect FLAGS_quic_time_wait_list_max_pending_packets as the upper bound of queued packets in time wait list.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_add_upperbound_for_queued_packets, true)
+// If true, restore connection context in various callbacks in TlsServerHandshaker.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_tls_restore_connection_context_in_callbacks, true)
// If true, send PATH_RESPONSE upon receiving PATH_CHALLENGE regardless of perspective. --gfe2_reloadable_flag_quic_start_peer_migration_earlier has to be true before turn on this flag.
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_send_path_response2, true)
// If true, set burst token to 2 in cwnd bootstrapping experiment.
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_conservative_bursts, false)
// If true, stop resetting ideal_next_packet_send_time_ in pacing sender.
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_donot_reset_ideal_next_packet_send_time, false)
-// If true, time_wait_list can support multiple connection IDs.
-QUIC_FLAG(FLAGS_quic_restart_flag_quic_time_wait_list_support_multiple_cid_v2, true)
-// If true, update ACK timeout for NEW_CONNECTION_ID and RETIRE_CONNECTION_ID frames.
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_ack_cid_frames, true)
-// If true, upon receiving path challenge, send path response and reverse path challenge in the same function.
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_group_path_response_and_challenge_sending_closer, true)
+// If true, suppress crypto data write in mid of packet processing.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_suppress_write_mid_packet_processing, true)
// If true, use BBRv2 as the default congestion controller. Takes precedence over --quic_default_to_bbr.
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_default_to_bbr_v2, false)
+// If true, use max(max_bw, send_rate) as the estimated bandwidth in QUIC\'s MaxAckHeightTracker.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_bbr_use_send_rate_in_max_ack_height_tracker, true)
// If true, use new connection ID in connection migration.
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_connection_migration_use_new_cid_v2, true)
// If true, uses conservative cwnd gain and pacing gain when cwnd gets bootstrapped.
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_conservative_cwnd_and_pacing_gains, false)
// If true, validate that peer owns the new address once the server detects peer migration or is probed from that address, and also apply anti-amplification limit while sending to that address.
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_server_reverse_validate_new_path3, true)
-// Queue packets to attempt decryption later until the handshake is complete.
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_queue_until_handshake_complete, true)
+// When receiving STOP_SENDING, send a RESET_STREAM with a matching error code.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_match_ietf_reset_code, false)
// When the STMP connection option is sent by the client, timestamps in the QUIC ACK frame are sent and processed.
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_send_timestamps, false)
+// When the flag is true, exit STARTUP after the same number of loss events as PROBE_UP.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_bbr2_startup_probe_up_loss_events, true)
+// When true, QuicDispatcher will silently drop incoming packets whose UDP source port is on the blocklist.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_blocked_ports, false)
// When true, defaults to BBR congestion control instead of Cubic.
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_default_to_bbr, false)
// When true, prevents QUIC\'s PacingSender from generating bursts when the congestion controller is CWND limited and not pacing limited.
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_fix_pacing_sender_bursts, false)
// When true, set the initial congestion control window from connection options in QuicSentPacketManager rather than TcpCubicSenderBytes.
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_unified_iw_options, false)
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_unified_iw_options, true)
+// When true, the B203 connection option causes the Bbr2Sender to ignore inflight_hi during PROBE_UP and increase it when the bytes delivered without loss are higher.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_bbr2_ignore_inflight_hi_in_probe_up, true)
+// When true, the B204 connection option enables extra acked in STARTUP, but also adds new logic to decrease it whenever max bandwidth increases.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_bbr2_startup_extra_acked, true)
+// When true, the BBQ0 connection option causes QUIC BBR2 to add bytes_acked to probe_up_acked if the connection hasn\'t been app-limited since inflight_hi was utilized.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_bbr2_add_bytes_acked_after_inflight_hi_limited, true)
+// When true, the BBR4 copt sets the extra_acked window to 20 RTTs and BBR5 sets it to 40 RTTs.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_bbr2_extra_acked_window, true)
#endif
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_framer.cc b/chromium/net/third_party/quiche/src/quic/core/quic_framer.cc
index 24b2be86484..4e0f639ae2d 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
@@ -412,6 +412,7 @@ QuicFramer::QuicFramer(const ParsedQuicVersionVector& supported_versions,
perspective_(perspective),
validate_flags_(true),
process_timestamps_(false),
+ receive_timestamps_exponent_(0),
creation_time_(creation_time),
last_timestamp_(QuicTime::Delta::Zero()),
support_key_update_for_connection_(false),
@@ -1300,81 +1301,45 @@ size_t QuicFramer::GetMinStatelessResetPacketLength() {
// static
std::unique_ptr<QuicEncryptedPacket> QuicFramer::BuildIetfStatelessResetPacket(
- QuicConnectionId /*connection_id*/,
- size_t received_packet_length,
+ QuicConnectionId /*connection_id*/, size_t received_packet_length,
StatelessResetToken stateless_reset_token) {
QUIC_DVLOG(1) << "Building IETF stateless reset packet.";
- if (GetQuicRestartFlag(quic_fix_stateless_reset2)) {
- if (received_packet_length <= GetMinStatelessResetPacketLength()) {
- QUICHE_DLOG(ERROR)
- << "Tried to build stateless reset packet with received packet "
- "length "
- << received_packet_length;
- return nullptr;
- }
- // To ensure stateless reset is indistinguishable from a valid packet,
- // include the max connection ID length.
- size_t len = std::min(received_packet_length - 1,
- GetMinStatelessResetPacketLength() + 1 +
- kQuicMaxConnectionIdWithLengthPrefixLength);
- std::unique_ptr<char[]> buffer(new char[len]);
- QuicDataWriter writer(len, buffer.get());
- // Append random bytes. This randomness only exists to prevent middleboxes
- // from comparing the entire packet to a known value. Therefore it has no
- // cryptographic use, and does not need a secure cryptographic pseudo-random
- // number generator. It's therefore safe to use WriteInsecureRandomBytes.
- if (!writer.WriteInsecureRandomBytes(QuicRandom::GetInstance(),
- len - kStatelessResetTokenLength)) {
- QUIC_BUG(362045737_2) << "Failed to append random bytes of length: "
- << len - kStatelessResetTokenLength;
- return nullptr;
- }
- // Change first 2 fixed bits to 01.
- buffer[0] &= ~FLAGS_LONG_HEADER;
- buffer[0] |= FLAGS_FIXED_BIT;
-
- // Append stateless reset token.
- if (!writer.WriteBytes(&stateless_reset_token,
- sizeof(stateless_reset_token))) {
- QUIC_BUG(362045737_3) << "Failed to write stateless reset token";
- return nullptr;
- }
- QUIC_RESTART_FLAG_COUNT(quic_fix_stateless_reset2);
- return std::make_unique<QuicEncryptedPacket>(buffer.release(), len,
- /*owns_buffer=*/true);
+ if (received_packet_length <= GetMinStatelessResetPacketLength()) {
+ QUICHE_DLOG(ERROR)
+ << "Tried to build stateless reset packet with received packet "
+ "length "
+ << received_packet_length;
+ return nullptr;
}
-
- size_t len = kPacketHeaderTypeSize + kMinRandomBytesLengthInStatelessReset +
- sizeof(stateless_reset_token);
+ // To ensure stateless reset is indistinguishable from a valid packet,
+ // include the max connection ID length.
+ size_t len = std::min(received_packet_length - 1,
+ GetMinStatelessResetPacketLength() + 1 +
+ kQuicMaxConnectionIdWithLengthPrefixLength);
std::unique_ptr<char[]> buffer(new char[len]);
QuicDataWriter writer(len, buffer.get());
-
- uint8_t type = 0;
- type |= FLAGS_FIXED_BIT;
- type |= FLAGS_SHORT_HEADER_RESERVED_1;
- type |= FLAGS_SHORT_HEADER_RESERVED_2;
- type |= PacketNumberLengthToOnWireValue(PACKET_1BYTE_PACKET_NUMBER);
-
- // Append type byte.
- if (!writer.WriteUInt8(type)) {
- return nullptr;
- }
-
// Append random bytes. This randomness only exists to prevent middleboxes
// from comparing the entire packet to a known value. Therefore it has no
// cryptographic use, and does not need a secure cryptographic pseudo-random
// number generator. It's therefore safe to use WriteInsecureRandomBytes.
if (!writer.WriteInsecureRandomBytes(QuicRandom::GetInstance(),
- kMinRandomBytesLengthInStatelessReset)) {
+ len - kStatelessResetTokenLength)) {
+ QUIC_BUG(362045737_2) << "Failed to append random bytes of length: "
+ << len - kStatelessResetTokenLength;
return nullptr;
}
+ // Change first 2 fixed bits to 01.
+ buffer[0] &= ~FLAGS_LONG_HEADER;
+ buffer[0] |= FLAGS_FIXED_BIT;
// Append stateless reset token.
if (!writer.WriteBytes(&stateless_reset_token,
sizeof(stateless_reset_token))) {
+ QUIC_BUG(362045737_3) << "Failed to write stateless reset token";
return nullptr;
}
- return std::make_unique<QuicEncryptedPacket>(buffer.release(), len, true);
+ return std::make_unique<QuicEncryptedPacket>(buffer.release(), len,
+ /*owns_buffer=*/true);
}
// static
@@ -3172,11 +3137,14 @@ bool QuicFramer::IsIetfFrameTypeExpectedForEncryptionLevel(
case ENCRYPTION_INITIAL:
case ENCRYPTION_HANDSHAKE:
return frame_type == IETF_CRYPTO || frame_type == IETF_ACK ||
+ frame_type == IETF_ACK_ECN ||
+ frame_type == IETF_ACK_RECEIVE_TIMESTAMPS ||
frame_type == IETF_PING || frame_type == IETF_PADDING ||
frame_type == IETF_CONNECTION_CLOSE;
case ENCRYPTION_ZERO_RTT:
- return !(frame_type == IETF_ACK || frame_type == IETF_CRYPTO ||
- frame_type == IETF_HANDSHAKE_DONE ||
+ return !(frame_type == IETF_ACK || frame_type == IETF_ACK_ECN ||
+ frame_type == IETF_ACK_RECEIVE_TIMESTAMPS ||
+ frame_type == IETF_CRYPTO || frame_type == IETF_HANDSHAKE_DONE ||
frame_type == IETF_NEW_TOKEN ||
frame_type == IETF_PATH_RESPONSE ||
frame_type == IETF_RETIRE_CONNECTION_ID);
@@ -3448,6 +3416,14 @@ bool QuicFramer::ProcessIetfFrameData(QuicDataReader* reader,
}
break;
}
+ case IETF_ACK_RECEIVE_TIMESTAMPS:
+ if (!process_timestamps_) {
+ set_detailed_error("Unsupported frame type.");
+ QUIC_DLOG(WARNING)
+ << ENDPOINT << "IETF_ACK_RECEIVE_TIMESTAMPS not supported";
+ return RaiseError(QUIC_INVALID_FRAME_DATA);
+ }
+ ABSL_FALLTHROUGH_INTENDED;
case IETF_ACK_ECN:
case IETF_ACK: {
QuicAckFrame frame;
@@ -4115,7 +4091,12 @@ bool QuicFramer::ProcessIetfAckFrame(QuicDataReader* reader,
ack_block_count--;
}
- if (frame_type == IETF_ACK_ECN) {
+ if (frame_type == IETF_ACK_RECEIVE_TIMESTAMPS) {
+ QUICHE_DCHECK(process_timestamps_);
+ if (!ProcessIetfTimestampsInAckFrame(ack_frame->largest_acked, reader)) {
+ return false;
+ }
+ } else if (frame_type == IETF_ACK_ECN) {
ack_frame->ecn_counters_populated = true;
if (!reader->ReadVarInt62(&ack_frame->ect_0_count)) {
set_detailed_error("Unable to read ack ect_0_count.");
@@ -4145,6 +4126,76 @@ bool QuicFramer::ProcessIetfAckFrame(QuicDataReader* reader,
return true;
}
+bool QuicFramer::ProcessIetfTimestampsInAckFrame(QuicPacketNumber largest_acked,
+ QuicDataReader* reader) {
+ uint64_t timestamp_range_count;
+ if (!reader->ReadVarInt62(&timestamp_range_count)) {
+ set_detailed_error("Unable to read receive timestamp range count.");
+ return false;
+ }
+ if (timestamp_range_count == 0) {
+ return true;
+ }
+
+ QuicPacketNumber packet_number = largest_acked;
+
+ // Iterate through all timestamp ranges, each of which represents a block of
+ // contiguous packets for which receive timestamps are being reported. Each
+ // range is of the form:
+ //
+ // Timestamp Range {
+ // Gap (i),
+ // Timestamp Delta Count (i),
+ // Timestamp Delta (i) ...,
+ // }
+ for (uint64_t i = 0; i < timestamp_range_count; i++) {
+ uint64_t gap;
+ if (!reader->ReadVarInt62(&gap)) {
+ set_detailed_error("Unable to read receive timestamp gap.");
+ return false;
+ }
+ if (packet_number.ToUint64() < gap) {
+ set_detailed_error("Receive timestamp gap too high.");
+ return false;
+ }
+ packet_number = packet_number - gap;
+ uint64_t timestamp_count;
+ if (!reader->ReadVarInt62(&timestamp_count)) {
+ set_detailed_error("Unable to read receive timestamp count.");
+ return false;
+ }
+ if (packet_number.ToUint64() < timestamp_count) {
+ set_detailed_error("Receive timestamp count too high.");
+ return false;
+ }
+ for (uint64_t j = 0; j < timestamp_count; j++) {
+ uint64_t timestamp_delta;
+ if (!reader->ReadVarInt62(&timestamp_delta)) {
+ set_detailed_error("Unable to read receive timestamp delta.");
+ return false;
+ }
+ // The first timestamp delta is relative to framer creation time; whereas
+ // subsequent deltas are relative to the previous delta in decreasing
+ // packet order.
+ timestamp_delta = timestamp_delta << receive_timestamps_exponent_;
+ if (i == 0 && j == 0) {
+ last_timestamp_ = CalculateTimestampFromWire(timestamp_delta);
+ } else {
+ last_timestamp_ = last_timestamp_ -
+ QuicTime::Delta::FromMicroseconds(timestamp_delta);
+ if (last_timestamp_ < QuicTime::Delta::Zero()) {
+ set_detailed_error("Receive timestamp delta too high.");
+ return false;
+ }
+ }
+ visitor_->OnAckTimestamp(packet_number - j,
+ creation_time_ + last_timestamp_);
+ }
+ packet_number = packet_number - (timestamp_count - 1);
+ }
+ return true;
+}
+
bool QuicFramer::ProcessStopWaitingFrame(QuicDataReader* reader,
const QuicPacketHeader& header,
QuicStopWaitingFrame* stop_waiting) {
@@ -6557,6 +6608,24 @@ QuicErrorCode QuicFramer::ParsePublicHeaderDispatcher(
return QUIC_INVALID_PACKET_HEADER;
}
const uint8_t first_byte = reader.PeekByte();
+ if ((first_byte & FLAGS_LONG_HEADER) == 0 &&
+ (first_byte & FLAGS_FIXED_BIT) == 0 &&
+ (first_byte & FLAGS_DEMULTIPLEXING_BIT) == 0) {
+ // All versions of Google QUIC up to and including Q043 set
+ // FLAGS_DEMULTIPLEXING_BIT to one on all client-to-server packets. Q044
+ // and Q045 were never default-enabled in production. All subsequent
+ // versions of Google QUIC (starting with Q046) require FLAGS_FIXED_BIT to
+ // be set to one on all packets. All versions of IETF QUIC (since
+ // draft-ietf-quic-transport-17 which was earlier than the first IETF QUIC
+ // version that was deployed in production by any implementation) also
+ // require FLAGS_FIXED_BIT to be set to one on all packets. If a packet
+ // has the FLAGS_LONG_HEADER bit set to one, it could be a first flight
+ // from an unknown future version that allows the other two bits to be set
+ // to zero. Based on this, packets that have all three of those bits set
+ // to zero are known to be invalid.
+ *detailed_error = "Invalid flags.";
+ return QUIC_INVALID_PACKET_HEADER;
+ }
const bool ietf_format = QuicUtils::IsIetfPacketHeader(first_byte);
uint8_t unused_first_byte;
QuicVariableLengthIntegerLength retry_token_length_length;
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 31cc756990b..a6820eaa9d6 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
@@ -313,6 +313,11 @@ class QUIC_EXPORT_PRIVATE QuicFramer {
process_timestamps_ = process_timestamps;
}
+ // Sets the exponent to use when writing/reading ACK receive timestamps.
+ void set_receive_timestamps_exponent(uint32_t exponent) {
+ receive_timestamps_exponent_ = exponent;
+ }
+
// Pass a UDP packet into the framer for parsing.
// Return true if the packet was processed successfully. |packet| must be a
// single, complete UDP packet (not a frame of a packet). This packet
@@ -854,6 +859,8 @@ class QUIC_EXPORT_PRIVATE QuicFramer {
bool ProcessIetfAckFrame(QuicDataReader* reader,
uint64_t frame_type,
QuicAckFrame* ack_frame);
+ bool ProcessIetfTimestampsInAckFrame(QuicPacketNumber largest_acked,
+ QuicDataReader* reader);
bool ProcessStopWaitingFrame(QuicDataReader* reader,
const QuicPacketHeader& header,
QuicStopWaitingFrame* stop_waiting);
@@ -1118,6 +1125,8 @@ class QUIC_EXPORT_PRIVATE QuicFramer {
DiversificationNonce last_nonce_;
// If true, send and process timestamps in the ACK frame.
bool process_timestamps_;
+ // The exponent to use when writing/reading ACK receive timestamps.
+ uint32_t receive_timestamps_exponent_;
// The creation time of the connection, used to calculate timestamps.
QuicTime creation_time_;
// The last timestamp received if process_timestamps_ is true.
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 f36bf5c78c7..f630867b083 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
@@ -37,6 +37,7 @@
#include "common/test_tools/quiche_test_utils.h"
using testing::_;
+using testing::ContainerEq;
using testing::Return;
namespace quic {
@@ -358,7 +359,9 @@ class TestQuicVisitor : public QuicFramerVisitorInterface {
ack_frames_.push_back(std::make_unique<QuicAckFrame>(ack_frame));
if (VersionHasIetfQuicFrames(transport_version_)) {
EXPECT_TRUE(IETF_ACK == framer_->current_received_frame_type() ||
- IETF_ACK_ECN == framer_->current_received_frame_type());
+ IETF_ACK_ECN == framer_->current_received_frame_type() ||
+ IETF_ACK_RECEIVE_TIMESTAMPS ==
+ framer_->current_received_frame_type());
} else {
EXPECT_EQ(0u, framer_->current_received_frame_type());
}
@@ -370,7 +373,9 @@ class TestQuicVisitor : public QuicFramerVisitorInterface {
ack_frames_[ack_frames_.size() - 1]->packets.AddRange(start, end);
if (VersionHasIetfQuicFrames(transport_version_)) {
EXPECT_TRUE(IETF_ACK == framer_->current_received_frame_type() ||
- IETF_ACK_ECN == framer_->current_received_frame_type());
+ IETF_ACK_ECN == framer_->current_received_frame_type() ||
+ IETF_ACK_RECEIVE_TIMESTAMPS ==
+ framer_->current_received_frame_type());
} else {
EXPECT_EQ(0u, framer_->current_received_frame_type());
}
@@ -381,7 +386,14 @@ class TestQuicVisitor : public QuicFramerVisitorInterface {
QuicTime timestamp) override {
ack_frames_[ack_frames_.size() - 1]->received_packet_times.push_back(
std::make_pair(packet_number, timestamp));
- EXPECT_EQ(0u, framer_->current_received_frame_type());
+ if (VersionHasIetfQuicFrames(transport_version_)) {
+ EXPECT_TRUE(IETF_ACK == framer_->current_received_frame_type() ||
+ IETF_ACK_ECN == framer_->current_received_frame_type() ||
+ IETF_ACK_RECEIVE_TIMESTAMPS ==
+ framer_->current_received_frame_type());
+ } else {
+ EXPECT_EQ(0u, framer_->current_received_frame_type());
+ }
return true;
}
@@ -896,6 +908,11 @@ class QuicFramerTest : public QuicTestWithParam<ParsedQuicVersion> {
((n - 1) * QuicUtils::StreamIdDelta(transport_version));
}
+ QuicTime CreationTimePlus(uint64_t offset_us) {
+ return framer_.creation_time() +
+ QuicTime::Delta::FromMicroseconds(offset_us);
+ }
+
test::TestEncrypter* encrypter_;
test::TestDecrypter* decrypter_;
ParsedQuicVersion version_;
@@ -1286,6 +1303,27 @@ TEST_P(QuicFramerTest, LongPacketHeaderWithBothConnectionIds) {
EXPECT_EQ(FramerTestConnectionIdPlusOne(), source_connection_id);
}
+TEST_P(QuicFramerTest, AllZeroPacketParsingFails) {
+ unsigned char packet[1200] = {};
+ QuicEncryptedPacket encrypted(AsChars(packet), ABSL_ARRAYSIZE(packet), false);
+ PacketHeaderFormat format = GOOGLE_QUIC_PACKET;
+ QuicLongHeaderType long_packet_type = INVALID_PACKET_TYPE;
+ bool version_flag = false;
+ QuicConnectionId destination_connection_id, source_connection_id;
+ QuicVersionLabel version_label = 0;
+ std::string detailed_error = "";
+ bool retry_token_present, use_length_prefix;
+ absl::string_view retry_token;
+ ParsedQuicVersion parsed_version = UnsupportedQuicVersion();
+ const QuicErrorCode error_code = QuicFramer::ParsePublicHeaderDispatcher(
+ encrypted, kQuicDefaultConnectionIdLength, &format, &long_packet_type,
+ &version_flag, &use_length_prefix, &version_label, &parsed_version,
+ &destination_connection_id, &source_connection_id, &retry_token_present,
+ &retry_token, &detailed_error);
+ EXPECT_EQ(error_code, QUIC_INVALID_PACKET_HEADER);
+ EXPECT_EQ(detailed_error, "Invalid flags.");
+}
+
TEST_P(QuicFramerTest, ParsePublicHeader) {
// clang-format off
unsigned char packet[] = {
@@ -2139,7 +2177,7 @@ TEST_P(QuicFramerTest, PaddingFrame) {
0x00, 0x00,
};
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -2171,8 +2209,8 @@ TEST_P(QuicFramerTest, PaddingFrame) {
unsigned char* p = packet;
size_t p_size = ABSL_ARRAYSIZE(packet);
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
- p = packet99;
- p_size = ABSL_ARRAYSIZE(packet99);
+ p = packet_ietf;
+ p_size = ABSL_ARRAYSIZE(packet_ietf);
} else if (framer_.version().HasIetfInvariantHeader()) {
p = packet46;
p_size = ABSL_ARRAYSIZE(packet46);
@@ -2260,7 +2298,7 @@ TEST_P(QuicFramerTest, StreamFrame) {
'r', 'l', 'd', '!'}},
};
- PacketFragments packet99 = {
+ PacketFragments packet_ietf = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -2293,7 +2331,7 @@ TEST_P(QuicFramerTest, StreamFrame) {
PacketFragments& fragments =
VersionHasIetfQuicFrames(framer_.transport_version())
- ? packet99
+ ? packet_ietf
: (framer_.version().HasIetfInvariantHeader() ? packet46 : packet);
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
@@ -2583,7 +2621,7 @@ TEST_P(QuicFramerTest, StreamFrame2ByteStreamId) {
'r', 'l', 'd', '!'}},
};
- PacketFragments packet99 = {
+ PacketFragments packet_ietf = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -2616,7 +2654,7 @@ TEST_P(QuicFramerTest, StreamFrame2ByteStreamId) {
PacketFragments& fragments =
VersionHasIetfQuicFrames(framer_.transport_version())
- ? packet99
+ ? packet_ietf
: (framer_.version().HasIetfInvariantHeader() ? packet46 : packet);
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
@@ -2702,7 +2740,7 @@ TEST_P(QuicFramerTest, StreamFrame1ByteStreamId) {
'r', 'l', 'd', '!'}},
};
- PacketFragments packet99 = {
+ PacketFragments packet_ietf = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -2735,7 +2773,7 @@ TEST_P(QuicFramerTest, StreamFrame1ByteStreamId) {
PacketFragments& fragments =
VersionHasIetfQuicFrames(framer_.transport_version())
- ? packet99
+ ? packet_ietf
: (framer_.version().HasIetfInvariantHeader() ? packet46 : packet);
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
@@ -2880,7 +2918,7 @@ TEST_P(QuicFramerTest, StreamFrameWithVersion) {
'r', 'l', 'd', '!'}},
};
- PacketFragments packet99 = {
+ PacketFragments packet_ietf = {
// public flags (long header with packet type ZERO_RTT_PROTECTED and
// 4-byte packet number)
{"",
@@ -2934,7 +2972,7 @@ TEST_P(QuicFramerTest, StreamFrameWithVersion) {
PacketFragments& fragments =
VersionHasIetfQuicFrames(framer_.transport_version())
- ? packet99
+ ? packet_ietf
: (framer_.version().HasLongHeaderLengths()
? packet49
: (framer_.version().HasIetfInvariantHeader() ? packet46
@@ -3129,7 +3167,7 @@ TEST_P(QuicFramerTest, AckFrameOneAckBlock) {
{0x00}}
};
- PacketFragments packet99 = {
+ PacketFragments packet_ietf = {
// type (short packet, 4 byte packet number)
{"",
{0x43}},
@@ -3167,7 +3205,7 @@ TEST_P(QuicFramerTest, AckFrameOneAckBlock) {
PacketFragments& fragments =
VersionHasIetfQuicFrames(framer_.transport_version())
- ? packet99
+ ? packet_ietf
: (framer_.version().HasIetfInvariantHeader() ? packet46 : packet);
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
@@ -3250,7 +3288,7 @@ TEST_P(QuicFramerTest, FirstAckFrameUnderflow) {
{0x00}}
};
- PacketFragments packet99 = {
+ PacketFragments packet_ietf = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -3280,7 +3318,7 @@ TEST_P(QuicFramerTest, FirstAckFrameUnderflow) {
PacketFragments& fragments =
VersionHasIetfQuicFrames(framer_.transport_version())
- ? packet99
+ ? packet_ietf
: (framer_.version().HasIetfInvariantHeader() ? packet46 : packet);
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
@@ -3300,7 +3338,7 @@ TEST_P(QuicFramerTest, ThirdAckBlockUnderflowGap) {
}
SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
// clang-format off
- PacketFragments packet99 = {
+ PacketFragments packet_ietf = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -3340,12 +3378,12 @@ TEST_P(QuicFramerTest, ThirdAckBlockUnderflowGap) {
// clang-format on
std::unique_ptr<QuicEncryptedPacket> encrypted(
- AssemblePacketFromFragments(packet99));
+ AssemblePacketFromFragments(packet_ietf));
EXPECT_FALSE(framer_.ProcessPacket(*encrypted));
EXPECT_EQ(
framer_.detailed_error(),
"Underflow with gap block length 30 previous ack block start is 30.");
- CheckFramingBoundaries(packet99, QUIC_INVALID_ACK_DATA);
+ CheckFramingBoundaries(packet_ietf, QUIC_INVALID_ACK_DATA);
}
// This test checks that the ack frame processor correctly identifies
@@ -3360,7 +3398,7 @@ TEST_P(QuicFramerTest, ThirdAckBlockUnderflowAck) {
}
SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
// clang-format off
- PacketFragments packet99 = {
+ PacketFragments packet_ietf = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -3398,11 +3436,11 @@ TEST_P(QuicFramerTest, ThirdAckBlockUnderflowAck) {
// clang-format on
std::unique_ptr<QuicEncryptedPacket> encrypted(
- AssemblePacketFromFragments(packet99));
+ AssemblePacketFromFragments(packet_ietf));
EXPECT_FALSE(framer_.ProcessPacket(*encrypted));
EXPECT_EQ(framer_.detailed_error(),
"Underflow with ack block length 31 latest ack block end is 25.");
- CheckFramingBoundaries(packet99, QUIC_INVALID_ACK_DATA);
+ CheckFramingBoundaries(packet_ietf, QUIC_INVALID_ACK_DATA);
}
// Tests a variety of ack block wrap scenarios. For example, if the
@@ -3418,7 +3456,7 @@ TEST_P(QuicFramerTest, AckBlockUnderflowGapWrap) {
}
SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
// clang-format off
- PacketFragments packet99 = {
+ PacketFragments packet_ietf = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -3452,11 +3490,11 @@ TEST_P(QuicFramerTest, AckBlockUnderflowGapWrap) {
// clang-format on
std::unique_ptr<QuicEncryptedPacket> encrypted(
- AssemblePacketFromFragments(packet99));
+ AssemblePacketFromFragments(packet_ietf));
EXPECT_FALSE(framer_.ProcessPacket(*encrypted));
EXPECT_EQ(framer_.detailed_error(),
"Underflow with gap block length 2 previous ack block start is 1.");
- CheckFramingBoundaries(packet99, QUIC_INVALID_ACK_DATA);
+ CheckFramingBoundaries(packet_ietf, QUIC_INVALID_ACK_DATA);
}
// As AckBlockUnderflowGapWrap, but in this test, it's the ack
@@ -3470,7 +3508,7 @@ TEST_P(QuicFramerTest, AckBlockUnderflowAckWrap) {
}
SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
// clang-format off
- PacketFragments packet99 = {
+ PacketFragments packet_ietf = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -3504,11 +3542,11 @@ TEST_P(QuicFramerTest, AckBlockUnderflowAckWrap) {
// clang-format on
std::unique_ptr<QuicEncryptedPacket> encrypted(
- AssemblePacketFromFragments(packet99));
+ AssemblePacketFromFragments(packet_ietf));
EXPECT_FALSE(framer_.ProcessPacket(*encrypted));
EXPECT_EQ(framer_.detailed_error(),
"Underflow with ack block length 10 latest ack block end is 1.");
- CheckFramingBoundaries(packet99, QUIC_INVALID_ACK_DATA);
+ CheckFramingBoundaries(packet_ietf, QUIC_INVALID_ACK_DATA);
}
// An ack block that acks the entire range, 1...0x3fffffffffffffff
@@ -3521,7 +3559,7 @@ TEST_P(QuicFramerTest, AckBlockAcksEverything) {
}
SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
// clang-format off
- PacketFragments packet99 = {
+ PacketFragments packet_ietf = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -3552,7 +3590,7 @@ TEST_P(QuicFramerTest, AckBlockAcksEverything) {
// clang-format on
std::unique_ptr<QuicEncryptedPacket> encrypted(
- AssemblePacketFromFragments(packet99));
+ AssemblePacketFromFragments(packet_ietf));
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
EXPECT_EQ(1u, visitor_.ack_frames_.size());
const QuicAckFrame& frame = *visitor_.ack_frames_[0];
@@ -3737,7 +3775,7 @@ TEST_P(QuicFramerTest, AckFrameOneAckBlockMaxLength) {
{0x00}}
};
- PacketFragments packet99 = {
+ PacketFragments packet_ietf = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -3767,7 +3805,7 @@ TEST_P(QuicFramerTest, AckFrameOneAckBlockMaxLength) {
PacketFragments& fragments =
VersionHasIetfQuicFrames(framer_.transport_version())
- ? packet99
+ ? packet_ietf
: (framer_.version().HasIetfInvariantHeader() ? packet46 : packet);
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
@@ -3929,7 +3967,7 @@ TEST_P(QuicFramerTest, AckFrameTwoTimeStampsMultipleAckBlocks) {
{ 0x32, 0x10 }},
};
- PacketFragments packet99 = {
+ PacketFragments packet_ietf = {
// type (short header, 4 byte packet number)
{"",
{ 0x43 }},
@@ -3940,9 +3978,9 @@ TEST_P(QuicFramerTest, AckFrameTwoTimeStampsMultipleAckBlocks) {
{"",
{ 0x12, 0x34, 0x56, 0x78 }},
- // frame type (IETF_ACK frame)
+ // frame type (IETF_ACK_RECEIVE_TIMESTAMPS frame)
{"",
- { 0x02 }},
+ { 0x22 }},
// largest acked
{"Unable to read largest acked.",
{ kVarInt62TwoBytes + 0x12, 0x34 }}, // = 4660
@@ -3983,12 +4021,24 @@ TEST_P(QuicFramerTest, AckFrameTwoTimeStampsMultipleAckBlocks) {
// ack block length.
{ "Unable to read ack block value.",
{ kVarInt62OneByte + 0x03 }}, // block is 3 packets.
+
+ // Receive Timestamps.
+ { "Unable to read receive timestamp range count.",
+ { kVarInt62OneByte + 0x01 }},
+ { "Unable to read receive timestamp gap.",
+ { kVarInt62OneByte + 0x01 }},
+ { "Unable to read receive timestamp count.",
+ { kVarInt62OneByte + 0x02 }},
+ { "Unable to read receive timestamp delta.",
+ { kVarInt62FourBytes + 0x36, 0x54, 0x32, 0x10 }},
+ { "Unable to read receive timestamp delta.",
+ { kVarInt62TwoBytes + 0x32, 0x10 }},
};
// clang-format on
PacketFragments& fragments =
VersionHasIetfQuicFrames(framer_.transport_version())
- ? packet99
+ ? packet_ietf
: (framer_.version().HasIetfInvariantHeader() ? packet46 : packet);
std::unique_ptr<QuicEncryptedPacket> encrypted(
@@ -4009,12 +4059,331 @@ TEST_P(QuicFramerTest, AckFrameTwoTimeStampsMultipleAckBlocks) {
EXPECT_EQ(kSmallLargestObserved, LargestAcked(frame));
ASSERT_EQ(4254u, frame.packets.NumPacketsSlow());
EXPECT_EQ(4u, frame.packets.NumIntervals());
- if (VersionHasIetfQuicFrames(framer_.transport_version())) {
- EXPECT_EQ(0u, frame.received_packet_times.size());
- } else {
- EXPECT_EQ(2u, frame.received_packet_times.size());
+ EXPECT_EQ(2u, frame.received_packet_times.size());
+}
+
+TEST_P(QuicFramerTest, AckFrameMultipleReceiveTimestampRanges) {
+ if (!VersionHasIetfQuicFrames(framer_.transport_version())) {
+ return;
}
- CheckFramingBoundaries(fragments, QUIC_INVALID_ACK_DATA);
+ SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
+ // clang-format off
+ PacketFragments packet_ietf = {
+ // type (short header, 4 byte packet number)
+ {"",
+ { 0x43 }},
+ // connection_id
+ {"",
+ { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 }},
+ // packet number
+ {"",
+ { 0x12, 0x34, 0x56, 0x78 }},
+
+ // frame type (IETF_ACK_RECEIVE_TIMESTAMPS frame)
+ {"",
+ { 0x22 }},
+ // largest acked
+ {"Unable to read largest acked.",
+ { kVarInt62TwoBytes + 0x12, 0x34 }}, // = 4660
+ // Zero delta time.
+ {"Unable to read ack delay time.",
+ { kVarInt62OneByte + 0x00 }},
+ // number of additional ack blocks
+ {"Unable to read ack block count.",
+ { kVarInt62OneByte + 0x00 }},
+ // first ack block length.
+ {"Unable to read first ack block length.",
+ { kVarInt62OneByte + 0x00 }}, // 1st block length = 1
+
+ // Receive Timestamps.
+ { "Unable to read receive timestamp range count.",
+ { kVarInt62OneByte + 0x03 }},
+
+ // Timestamp range 1 (three packets).
+ { "Unable to read receive timestamp gap.",
+ { kVarInt62OneByte + 0x02 }},
+ { "Unable to read receive timestamp count.",
+ { kVarInt62OneByte + 0x03 }},
+ { "Unable to read receive timestamp delta.",
+ { kVarInt62FourBytes + 0x29, 0xff, 0xff, 0xff}},
+ { "Unable to read receive timestamp delta.",
+ { kVarInt62TwoBytes + 0x11, 0x11 }},
+ { "Unable to read receive timestamp delta.",
+ { kVarInt62OneByte + 0x01}},
+
+ // Timestamp range 2 (one packet).
+ { "Unable to read receive timestamp gap.",
+ { kVarInt62OneByte + 0x07 }},
+ { "Unable to read receive timestamp count.",
+ { kVarInt62OneByte + 0x01 }},
+ { "Unable to read receive timestamp delta.",
+ { kVarInt62TwoBytes + 0x10, 0x00 }},
+
+ // Timestamp range 3 (two packets).
+ { "Unable to read receive timestamp gap.",
+ { kVarInt62OneByte + 0x0a }},
+ { "Unable to read receive timestamp count.",
+ { kVarInt62OneByte + 0x02 }},
+ { "Unable to read receive timestamp delta.",
+ { kVarInt62OneByte + 0x10 }},
+ { "Unable to read receive timestamp delta.",
+ { kVarInt62TwoBytes + 0x01, 0x00 }},
+ };
+ // clang-format on
+
+ std::unique_ptr<QuicEncryptedPacket> encrypted(
+ AssemblePacketFromFragments(packet_ietf));
+
+ framer_.set_process_timestamps(true);
+ EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
+ EXPECT_THAT(framer_.error(), IsQuicNoError());
+ ASSERT_TRUE(visitor_.header_.get());
+ const QuicAckFrame& frame = *visitor_.ack_frames_[0];
+
+ EXPECT_THAT(frame.received_packet_times,
+ ContainerEq(PacketTimeVector{
+ // Timestamp Range 1.
+ {LargestAcked(frame) - 2, CreationTimePlus(0x29ffffff)},
+ {LargestAcked(frame) - 3, CreationTimePlus(0x29ffeeee)},
+ {LargestAcked(frame) - 4, CreationTimePlus(0x29ffeeed)},
+ // Timestamp Range 2.
+ {LargestAcked(frame) - 11, CreationTimePlus(0x29ffdeed)},
+ // Timestamp Range 3.
+ {LargestAcked(frame) - 21, CreationTimePlus(0x29ffdedd)},
+ {LargestAcked(frame) - 22, CreationTimePlus(0x29ffdddd)},
+ }));
+}
+
+TEST_P(QuicFramerTest, AckFrameReceiveTimestampWithExponent) {
+ if (!VersionHasIetfQuicFrames(framer_.transport_version())) {
+ return;
+ }
+ SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
+ // clang-format off
+ PacketFragments packet_ietf = {
+ // type (short header, 4 byte packet number)
+ {"",
+ { 0x43 }},
+ // connection_id
+ {"",
+ { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 }},
+ // packet number
+ {"",
+ { 0x12, 0x34, 0x56, 0x78 }},
+
+ // frame type (IETF_ACK_RECEIVE_TIMESTAMPS frame)
+ {"",
+ { 0x22 }},
+ // largest acked
+ {"Unable to read largest acked.",
+ { kVarInt62TwoBytes + 0x12, 0x34 }}, // = 4660
+ // Zero delta time.
+ {"Unable to read ack delay time.",
+ { kVarInt62OneByte + 0x00 }},
+ // number of additional ack blocks
+ {"Unable to read ack block count.",
+ { kVarInt62OneByte + 0x00 }},
+ // first ack block length.
+ {"Unable to read first ack block length.",
+ { kVarInt62OneByte + 0x00 }}, // 1st block length = 1
+
+ // Receive Timestamps.
+ { "Unable to read receive timestamp range count.",
+ { kVarInt62OneByte + 0x01 }},
+ { "Unable to read receive timestamp gap.",
+ { kVarInt62OneByte + 0x00 }},
+ { "Unable to read receive timestamp count.",
+ { kVarInt62OneByte + 0x03 }},
+ { "Unable to read receive timestamp delta.",
+ { kVarInt62TwoBytes + 0x29, 0xff}},
+ { "Unable to read receive timestamp delta.",
+ { kVarInt62TwoBytes + 0x11, 0x11 }},
+ { "Unable to read receive timestamp delta.",
+ { kVarInt62OneByte + 0x01}},
+ };
+ // clang-format on
+
+ std::unique_ptr<QuicEncryptedPacket> encrypted(
+ AssemblePacketFromFragments(packet_ietf));
+
+ framer_.set_receive_timestamps_exponent(3);
+ framer_.set_process_timestamps(true);
+ EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
+ EXPECT_THAT(framer_.error(), IsQuicNoError());
+ ASSERT_TRUE(visitor_.header_.get());
+ const QuicAckFrame& frame = *visitor_.ack_frames_[0];
+
+ EXPECT_THAT(frame.received_packet_times,
+ ContainerEq(PacketTimeVector{
+ // Timestamp Range 1.
+ {LargestAcked(frame), CreationTimePlus(0x29ff << 3)},
+ {LargestAcked(frame) - 1, CreationTimePlus(0x18ee << 3)},
+ {LargestAcked(frame) - 2, CreationTimePlus(0x18ed << 3)},
+ }));
+}
+
+TEST_P(QuicFramerTest, AckFrameReceiveTimestampGapTooHigh) {
+ if (!VersionHasIetfQuicFrames(framer_.transport_version())) {
+ return;
+ }
+ SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
+ // clang-format off
+ PacketFragments packet_ietf = {
+ // type (short header, 4 byte packet number)
+ {"",
+ { 0x43 }},
+ // connection_id
+ {"",
+ { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 }},
+ // packet number
+ {"",
+ { 0x12, 0x34, 0x56, 0x78 }},
+
+ // frame type (IETF_ACK_RECEIVE_TIMESTAMPS frame)
+ {"",
+ { 0x22 }},
+ // largest acked
+ {"Unable to read largest acked.",
+ { kVarInt62TwoBytes + 0x12, 0x34 }}, // = 4660
+ // Zero delta time.
+ {"Unable to read ack delay time.",
+ { kVarInt62OneByte + 0x00 }},
+ // number of additional ack blocks
+ {"Unable to read ack block count.",
+ { kVarInt62OneByte + 0x00 }},
+ // first ack block length.
+ {"Unable to read first ack block length.",
+ { kVarInt62OneByte + 0x00 }}, // 1st block length = 1
+
+ // Receive Timestamps.
+ { "Unable to read receive timestamp range count.",
+ { kVarInt62OneByte + 0x01 }},
+ { "Unable to read receive timestamp gap.",
+ { kVarInt62FourBytes + 0x12, 0x34, 0x56, 0x79 }},
+ { "Unable to read receive timestamp count.",
+ { kVarInt62OneByte + 0x01 }},
+ { "Unable to read receive timestamp delta.",
+ { kVarInt62TwoBytes + 0x29, 0xff}},
+ };
+ // clang-format on
+
+ std::unique_ptr<QuicEncryptedPacket> encrypted(
+ AssemblePacketFromFragments(packet_ietf));
+
+ framer_.set_process_timestamps(true);
+ EXPECT_FALSE(framer_.ProcessPacket(*encrypted));
+ EXPECT_TRUE(absl::StartsWith(framer_.detailed_error(),
+ "Receive timestamp gap too high."));
+}
+
+TEST_P(QuicFramerTest, AckFrameReceiveTimestampCountTooHigh) {
+ if (!VersionHasIetfQuicFrames(framer_.transport_version())) {
+ return;
+ }
+ SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
+ // clang-format off
+ PacketFragments packet_ietf = {
+ // type (short header, 4 byte packet number)
+ {"",
+ { 0x43 }},
+ // connection_id
+ {"",
+ { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 }},
+ // packet number
+ {"",
+ { 0x12, 0x34, 0x56, 0x78 }},
+
+ // frame type (IETF_ACK_RECEIVE_TIMESTAMPS frame)
+ {"",
+ { 0x22 }},
+ // largest acked
+ {"Unable to read largest acked.",
+ { kVarInt62TwoBytes + 0x12, 0x34 }}, // = 4660
+ // Zero delta time.
+ {"Unable to read ack delay time.",
+ { kVarInt62OneByte + 0x00 }},
+ // number of additional ack blocks
+ {"Unable to read ack block count.",
+ { kVarInt62OneByte + 0x00 }},
+ // first ack block length.
+ {"Unable to read first ack block length.",
+ { kVarInt62OneByte + 0x00 }}, // 1st block length = 1
+
+ // Receive Timestamps.
+ { "Unable to read receive timestamp range count.",
+ { kVarInt62OneByte + 0x01 }},
+ { "Unable to read receive timestamp gap.",
+ { kVarInt62OneByte + 0x02 }},
+ { "Unable to read receive timestamp count.",
+ { kVarInt62OneByte + 0x02 }},
+ { "Unable to read receive timestamp delta.",
+ { kVarInt62OneByte + 0x0a}},
+ { "Unable to read receive timestamp delta.",
+ { kVarInt62OneByte + 0x0b}},
+ };
+ // clang-format on
+
+ std::unique_ptr<QuicEncryptedPacket> encrypted(
+ AssemblePacketFromFragments(packet_ietf));
+
+ framer_.set_process_timestamps(true);
+ EXPECT_FALSE(framer_.ProcessPacket(*encrypted));
+ EXPECT_TRUE(absl::StartsWith(framer_.detailed_error(),
+ "Receive timestamp delta too high."));
+}
+
+TEST_P(QuicFramerTest, AckFrameReceiveTimestampDeltaTooHigh) {
+ if (!VersionHasIetfQuicFrames(framer_.transport_version())) {
+ return;
+ }
+ SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
+ // clang-format off
+ PacketFragments packet_ietf = {
+ // type (short header, 4 byte packet number)
+ {"",
+ { 0x43 }},
+ // connection_id
+ {"",
+ { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 }},
+ // packet number
+ {"",
+ { 0x12, 0x34, 0x56, 0x78 }},
+
+ // frame type (IETF_ACK_RECEIVE_TIMESTAMPS frame)
+ {"",
+ { 0x22 }},
+ // largest acked
+ {"Unable to read largest acked.",
+ { kVarInt62TwoBytes + 0x12, 0x34 }}, // = 4660
+ // Zero delta time.
+ {"Unable to read ack delay time.",
+ { kVarInt62OneByte + 0x00 }},
+ // number of additional ack blocks
+ {"Unable to read ack block count.",
+ { kVarInt62OneByte + 0x00 }},
+ // first ack block length.
+ {"Unable to read first ack block length.",
+ { kVarInt62OneByte + 0x00 }}, // 1st block length = 1
+
+ // Receive Timestamps.
+ { "Unable to read receive timestamp range count.",
+ { kVarInt62OneByte + 0x01 }},
+ { "Unable to read receive timestamp gap.",
+ { kVarInt62OneByte + 0x02 }},
+ { "Unable to read receive timestamp count.",
+ { kVarInt62FourBytes + 0x12, 0x34, 0x56, 0x77 }},
+ { "Unable to read receive timestamp delta.",
+ { kVarInt62TwoBytes + 0x29, 0xff}},
+ };
+ // clang-format on
+
+ std::unique_ptr<QuicEncryptedPacket> encrypted(
+ AssemblePacketFromFragments(packet_ietf));
+
+ framer_.set_process_timestamps(true);
+ EXPECT_FALSE(framer_.ProcessPacket(*encrypted));
+ EXPECT_TRUE(absl::StartsWith(framer_.detailed_error(),
+ "Receive timestamp count too high."));
}
TEST_P(QuicFramerTest, AckFrameTimeStampDeltaTooHigh) {
@@ -4319,7 +4688,7 @@ TEST_P(QuicFramerTest, RstStreamFrame) {
{0x00, 0x00, 0x00, 0x06}}
};
- PacketFragments packet99 = {
+ PacketFragments packet_ietf = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -4347,7 +4716,7 @@ TEST_P(QuicFramerTest, RstStreamFrame) {
PacketFragments& fragments =
VersionHasIetfQuicFrames(framer_.transport_version())
- ? packet99
+ ? packet_ietf
: (framer_.version().HasIetfInvariantHeader() ? packet46 : packet);
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
@@ -4424,7 +4793,7 @@ TEST_P(QuicFramerTest, ConnectionCloseFrame) {
}
};
- PacketFragments packet99 = {
+ PacketFragments packet_ietf = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -4458,7 +4827,7 @@ TEST_P(QuicFramerTest, ConnectionCloseFrame) {
PacketFragments& fragments =
VersionHasIetfQuicFrames(framer_.transport_version())
- ? packet99
+ ? packet_ietf
: (framer_.version().HasIetfInvariantHeader() ? packet46 : packet);
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
@@ -4549,7 +4918,7 @@ TEST_P(QuicFramerTest, ConnectionCloseFrameWithUnknownErrorCode) {
}
};
- PacketFragments packet99 = {
+ PacketFragments packet_ietf = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -4583,7 +4952,7 @@ TEST_P(QuicFramerTest, ConnectionCloseFrameWithUnknownErrorCode) {
PacketFragments& fragments =
VersionHasIetfQuicFrames(framer_.transport_version())
- ? packet99
+ ? packet_ietf
: (framer_.version().HasIetfInvariantHeader() ? packet46 : packet);
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
@@ -4679,7 +5048,7 @@ TEST_P(QuicFramerTest, ConnectionCloseFrameWithExtractedInfoIgnoreGCuic) {
}
};
- PacketFragments packet99 = {
+ PacketFragments packet_ietf = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -4713,7 +5082,7 @@ TEST_P(QuicFramerTest, ConnectionCloseFrameWithExtractedInfoIgnoreGCuic) {
PacketFragments& fragments =
VersionHasIetfQuicFrames(framer_.transport_version())
- ? packet99
+ ? packet_ietf
: (framer_.version().HasIetfInvariantHeader() ? packet46 : packet);
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
@@ -4756,7 +5125,7 @@ TEST_P(QuicFramerTest, ApplicationCloseFrame) {
SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
// clang-format off
- PacketFragments packet99 = {
+ PacketFragments packet_ietf = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -4786,7 +5155,7 @@ TEST_P(QuicFramerTest, ApplicationCloseFrame) {
// clang-format on
std::unique_ptr<QuicEncryptedPacket> encrypted(
- AssemblePacketFromFragments(packet99));
+ AssemblePacketFromFragments(packet_ietf));
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
EXPECT_THAT(framer_.error(), IsQuicNoError());
@@ -4805,7 +5174,7 @@ TEST_P(QuicFramerTest, ApplicationCloseFrame) {
ASSERT_EQ(0u, visitor_.ack_frames_.size());
- CheckFramingBoundaries(packet99, QUIC_INVALID_CONNECTION_CLOSE_DATA);
+ CheckFramingBoundaries(packet_ietf, QUIC_INVALID_CONNECTION_CLOSE_DATA);
}
// Check that we can extract an error code from an application close.
@@ -4817,7 +5186,7 @@ TEST_P(QuicFramerTest, ApplicationCloseFrameExtract) {
SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
// clang-format off
- PacketFragments packet99 = {
+ PacketFragments packet_ietf = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -4848,7 +5217,7 @@ TEST_P(QuicFramerTest, ApplicationCloseFrameExtract) {
// clang-format on
std::unique_ptr<QuicEncryptedPacket> encrypted(
- AssemblePacketFromFragments(packet99));
+ AssemblePacketFromFragments(packet_ietf));
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
EXPECT_THAT(framer_.error(), IsQuicNoError());
@@ -4867,7 +5236,7 @@ TEST_P(QuicFramerTest, ApplicationCloseFrameExtract) {
ASSERT_EQ(0u, visitor_.ack_frames_.size());
- CheckFramingBoundaries(packet99, QUIC_INVALID_CONNECTION_CLOSE_DATA);
+ CheckFramingBoundaries(packet_ietf, QUIC_INVALID_CONNECTION_CLOSE_DATA);
}
TEST_P(QuicFramerTest, GoAwayFrame) {
@@ -5131,7 +5500,7 @@ TEST_P(QuicFramerTest, MaxDataFrame) {
}
SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
// clang-format off
- PacketFragments packet99 = {
+ PacketFragments packet_ietf = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -5152,7 +5521,7 @@ TEST_P(QuicFramerTest, MaxDataFrame) {
// clang-format on
std::unique_ptr<QuicEncryptedPacket> encrypted(
- AssemblePacketFromFragments(packet99));
+ AssemblePacketFromFragments(packet_ietf));
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
EXPECT_THAT(framer_.error(), IsQuicNoError());
@@ -5165,7 +5534,7 @@ TEST_P(QuicFramerTest, MaxDataFrame) {
visitor_.window_update_frame_.stream_id);
EXPECT_EQ(kStreamOffset, visitor_.window_update_frame_.max_data);
- CheckFramingBoundaries(packet99, QUIC_INVALID_MAX_DATA_FRAME_DATA);
+ CheckFramingBoundaries(packet_ietf, QUIC_INVALID_MAX_DATA_FRAME_DATA);
}
TEST_P(QuicFramerTest, MaxStreamDataFrame) {
@@ -5175,7 +5544,7 @@ TEST_P(QuicFramerTest, MaxStreamDataFrame) {
}
SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
// clang-format off
- PacketFragments packet99 = {
+ PacketFragments packet_ietf = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -5199,7 +5568,7 @@ TEST_P(QuicFramerTest, MaxStreamDataFrame) {
// clang-format on
std::unique_ptr<QuicEncryptedPacket> encrypted(
- AssemblePacketFromFragments(packet99));
+ AssemblePacketFromFragments(packet_ietf));
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
EXPECT_THAT(framer_.error(), IsQuicNoError());
@@ -5211,7 +5580,7 @@ TEST_P(QuicFramerTest, MaxStreamDataFrame) {
EXPECT_EQ(kStreamId, visitor_.window_update_frame_.stream_id);
EXPECT_EQ(kStreamOffset, visitor_.window_update_frame_.max_data);
- CheckFramingBoundaries(packet99, QUIC_INVALID_MAX_STREAM_DATA_FRAME_DATA);
+ CheckFramingBoundaries(packet_ietf, QUIC_INVALID_MAX_STREAM_DATA_FRAME_DATA);
}
TEST_P(QuicFramerTest, BlockedFrame) {
@@ -5253,7 +5622,7 @@ TEST_P(QuicFramerTest, BlockedFrame) {
{0x01, 0x02, 0x03, 0x04}},
};
- PacketFragments packet99 = {
+ PacketFragments packet_ietf = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -5277,7 +5646,7 @@ TEST_P(QuicFramerTest, BlockedFrame) {
PacketFragments& fragments =
VersionHasIetfQuicFrames(framer_.transport_version())
- ? packet99
+ ? packet_ietf
: (framer_.version().HasIetfInvariantHeader() ? packet46 : packet);
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
@@ -5330,7 +5699,7 @@ TEST_P(QuicFramerTest, PingFrame) {
0x07,
};
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -5345,11 +5714,11 @@ TEST_P(QuicFramerTest, PingFrame) {
QuicEncryptedPacket encrypted(
AsChars(VersionHasIetfQuicFrames(framer_.transport_version())
- ? packet99
+ ? packet_ietf
: (framer_.version().HasIetfInvariantHeader() ? packet46
: packet)),
VersionHasIetfQuicFrames(framer_.transport_version())
- ? ABSL_ARRAYSIZE(packet99)
+ ? ABSL_ARRAYSIZE(packet_ietf)
: (framer_.version().HasIetfInvariantHeader()
? ABSL_ARRAYSIZE(packet46)
: ABSL_ARRAYSIZE(packet)),
@@ -5476,7 +5845,7 @@ TEST_P(QuicFramerTest, MessageFrame) {
{{},
{'m', 'e', 's', 's', 'a', 'g', 'e', '2'}},
};
- PacketFragments packet99 = {
+ PacketFragments packet_ietf = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -5506,7 +5875,7 @@ TEST_P(QuicFramerTest, MessageFrame) {
std::unique_ptr<QuicEncryptedPacket> encrypted;
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
- encrypted = AssemblePacketFromFragments(packet99);
+ encrypted = AssemblePacketFromFragments(packet_ietf);
} else {
encrypted = AssemblePacketFromFragments(packet46);
}
@@ -5523,7 +5892,7 @@ TEST_P(QuicFramerTest, MessageFrame) {
EXPECT_EQ(8u, visitor_.message_frames_[1]->message_length);
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
- CheckFramingBoundaries(packet99, QUIC_INVALID_MESSAGE_DATA);
+ CheckFramingBoundaries(packet_ietf, QUIC_INVALID_MESSAGE_DATA);
} else {
CheckFramingBoundaries(packet46, QUIC_INVALID_MESSAGE_DATA);
}
@@ -6153,7 +6522,7 @@ TEST_P(QuicFramerTest, BuildPaddingFramePacket) {
0x00, 0x00, 0x00, 0x00
};
- unsigned char packet99[kMaxOutgoingPacketSize] = {
+ unsigned char packet_ietf[kMaxOutgoingPacketSize] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -6169,7 +6538,7 @@ TEST_P(QuicFramerTest, BuildPaddingFramePacket) {
unsigned char* p = packet;
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
- p = packet99;
+ p = packet_ietf;
} else if (framer_.version().HasIetfInvariantHeader()) {
p = packet46;
}
@@ -6258,7 +6627,7 @@ TEST_P(QuicFramerTest, BuildStreamFramePacketWithNewPaddingFrame) {
0x00, 0x00,
};
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -6292,8 +6661,8 @@ TEST_P(QuicFramerTest, BuildStreamFramePacketWithNewPaddingFrame) {
unsigned char* p = packet;
size_t p_size = ABSL_ARRAYSIZE(packet);
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
- p = packet99;
- p_size = ABSL_ARRAYSIZE(packet99);
+ p = packet_ietf;
+ p_size = ABSL_ARRAYSIZE(packet_ietf);
} else if (framer_.version().HasIetfInvariantHeader()) {
p = packet46;
p_size = ABSL_ARRAYSIZE(packet46);
@@ -6342,7 +6711,7 @@ TEST_P(QuicFramerTest, Build4ByteSequenceNumberPaddingFramePacket) {
0x00, 0x00, 0x00, 0x00
};
- unsigned char packet99[kMaxOutgoingPacketSize] = {
+ unsigned char packet_ietf[kMaxOutgoingPacketSize] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -6358,7 +6727,7 @@ TEST_P(QuicFramerTest, Build4ByteSequenceNumberPaddingFramePacket) {
unsigned char* p = packet;
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
- p = packet99;
+ p = packet_ietf;
} else if (framer_.version().HasIetfInvariantHeader()) {
p = packet46;
}
@@ -6417,7 +6786,7 @@ TEST_P(QuicFramerTest, Build2ByteSequenceNumberPaddingFramePacket) {
0x00, 0x00, 0x00, 0x00
};
- unsigned char packet99[kMaxOutgoingPacketSize] = {
+ unsigned char packet_ietf[kMaxOutgoingPacketSize] = {
// type (short header, 2 byte packet number)
0x41,
// connection_id
@@ -6433,7 +6802,7 @@ TEST_P(QuicFramerTest, Build2ByteSequenceNumberPaddingFramePacket) {
unsigned char* p = packet;
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
- p = packet99;
+ p = packet_ietf;
} else if (framer_.version().HasIetfInvariantHeader()) {
p = packet46;
}
@@ -6492,7 +6861,7 @@ TEST_P(QuicFramerTest, Build1ByteSequenceNumberPaddingFramePacket) {
0x00, 0x00, 0x00, 0x00
};
- unsigned char packet99[kMaxOutgoingPacketSize] = {
+ unsigned char packet_ietf[kMaxOutgoingPacketSize] = {
// type (short header, 1 byte packet number)
0x40,
// connection_id
@@ -6508,7 +6877,7 @@ TEST_P(QuicFramerTest, Build1ByteSequenceNumberPaddingFramePacket) {
unsigned char* p = packet;
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
- p = packet99;
+ p = packet_ietf;
} else if (framer_.version().HasIetfInvariantHeader()) {
p = packet46;
}
@@ -6588,7 +6957,7 @@ TEST_P(QuicFramerTest, BuildStreamFramePacket) {
'r', 'l', 'd', '!',
};
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -6616,8 +6985,8 @@ TEST_P(QuicFramerTest, BuildStreamFramePacket) {
unsigned char* p = packet;
size_t p_size = ABSL_ARRAYSIZE(packet);
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
- p = packet99;
- p_size = ABSL_ARRAYSIZE(packet99);
+ p = packet_ietf;
+ p_size = ABSL_ARRAYSIZE(packet_ietf);
} else if (framer_.version().HasIetfInvariantHeader()) {
p = packet46;
p_size = ABSL_ARRAYSIZE(packet46);
@@ -6712,7 +7081,7 @@ TEST_P(QuicFramerTest, BuildStreamFramePacketWithVersionFlag) {
'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!',
};
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// type (long header with packet type ZERO_RTT_PROTECTED)
0xD3,
// version tag
@@ -6746,8 +7115,8 @@ TEST_P(QuicFramerTest, BuildStreamFramePacketWithVersionFlag) {
unsigned char* p = packet;
size_t p_size = ABSL_ARRAYSIZE(packet);
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
- p = packet99;
- p_size = ABSL_ARRAYSIZE(packet99);
+ p = packet_ietf;
+ p_size = ABSL_ARRAYSIZE(packet_ietf);
} else if (framer_.version().HasLongHeaderLengths()) {
p = packet49;
p_size = ABSL_ARRAYSIZE(packet49);
@@ -6803,7 +7172,7 @@ TEST_P(QuicFramerTest, BuildCryptoFramePacket) {
'r', 'l', 'd', '!',
};
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -6828,8 +7197,8 @@ TEST_P(QuicFramerTest, BuildCryptoFramePacket) {
unsigned char* packet = packet48;
size_t packet_size = ABSL_ARRAYSIZE(packet48);
if (framer_.version().HasIetfQuicFrames()) {
- packet = packet99;
- packet_size = ABSL_ARRAYSIZE(packet99);
+ packet = packet_ietf;
+ packet_size = ABSL_ARRAYSIZE(packet_ietf);
}
std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
@@ -6874,7 +7243,7 @@ TEST_P(QuicFramerTest, CryptoFrame) {
'r', 'l', 'd', '!'}},
};
- PacketFragments packet99 = {
+ PacketFragments packet_ietf = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -6903,7 +7272,7 @@ TEST_P(QuicFramerTest, CryptoFrame) {
// clang-format on
PacketFragments& fragments =
- framer_.version().HasIetfQuicFrames() ? packet99 : packet48;
+ framer_.version().HasIetfQuicFrames() ? packet_ietf : packet48;
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
@@ -7078,7 +7447,7 @@ TEST_P(QuicFramerTest, BuildAckFramePacketOneAckBlock) {
0x00,
};
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -7101,8 +7470,8 @@ TEST_P(QuicFramerTest, BuildAckFramePacketOneAckBlock) {
unsigned char* p = packet;
size_t p_size = ABSL_ARRAYSIZE(packet);
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
- p = packet99;
- p_size = ABSL_ARRAYSIZE(packet99);
+ p = packet_ietf;
+ p_size = ABSL_ARRAYSIZE(packet_ietf);
} else if (framer_.version().HasIetfInvariantHeader()) {
p = packet46;
p_size = ABSL_ARRAYSIZE(packet46);
@@ -7171,7 +7540,7 @@ TEST_P(QuicFramerTest, BuildAckFramePacketOneAckBlockMaxLength) {
};
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -7194,8 +7563,8 @@ TEST_P(QuicFramerTest, BuildAckFramePacketOneAckBlockMaxLength) {
unsigned char* p = packet;
size_t p_size = ABSL_ARRAYSIZE(packet);
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
- p = packet99;
- p_size = ABSL_ARRAYSIZE(packet99);
+ p = packet_ietf;
+ p_size = ABSL_ARRAYSIZE(packet_ietf);
} else if (framer_.version().HasIetfInvariantHeader()) {
p = packet46;
p_size = ABSL_ARRAYSIZE(packet46);
@@ -7304,7 +7673,7 @@ TEST_P(QuicFramerTest, BuildAckFramePacketMultipleAckBlocks) {
0x00,
};
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -7342,8 +7711,8 @@ TEST_P(QuicFramerTest, BuildAckFramePacketMultipleAckBlocks) {
unsigned char* p = packet;
size_t p_size = ABSL_ARRAYSIZE(packet);
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
- p = packet99;
- p_size = ABSL_ARRAYSIZE(packet99);
+ p = packet_ietf;
+ p_size = ABSL_ARRAYSIZE(packet_ietf);
} else if (framer_.version().HasIetfInvariantHeader()) {
p = packet46;
p_size = ABSL_ARRAYSIZE(packet46);
@@ -7563,7 +7932,7 @@ TEST_P(QuicFramerTest, BuildAckFramePacketMaxAckBlocks) {
0x00,
};
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -7651,8 +8020,8 @@ TEST_P(QuicFramerTest, BuildAckFramePacketMaxAckBlocks) {
unsigned char* p = packet;
size_t p_size = ABSL_ARRAYSIZE(packet);
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
- p = packet99;
- p_size = ABSL_ARRAYSIZE(packet99);
+ p = packet_ietf;
+ p_size = ABSL_ARRAYSIZE(packet_ietf);
} else if (framer_.version().HasIetfInvariantHeader()) {
p = packet46;
p_size = ABSL_ARRAYSIZE(packet46);
@@ -7762,7 +8131,7 @@ TEST_P(QuicFramerTest, BuildRstFramePacketQuic) {
0x05, 0x06, 0x07, 0x08,
};
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// type (short packet, 4 byte packet number)
0x43,
// connection_id
@@ -7789,8 +8158,8 @@ TEST_P(QuicFramerTest, BuildRstFramePacketQuic) {
unsigned char* p = packet;
size_t p_size = ABSL_ARRAYSIZE(packet);
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
- p = packet99;
- p_size = ABSL_ARRAYSIZE(packet99);
+ p = packet_ietf;
+ p_size = ABSL_ARRAYSIZE(packet_ietf);
} else if (framer_.version().HasIetfInvariantHeader()) {
p = packet46;
p_size = ABSL_ARRAYSIZE(packet46);
@@ -7857,7 +8226,7 @@ TEST_P(QuicFramerTest, BuildCloseFramePacket) {
'n',
};
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -7884,8 +8253,8 @@ TEST_P(QuicFramerTest, BuildCloseFramePacket) {
unsigned char* p = packet;
size_t p_size = ABSL_ARRAYSIZE(packet);
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
- p = packet99;
- p_size = ABSL_ARRAYSIZE(packet99);
+ p = packet_ietf;
+ p_size = ABSL_ARRAYSIZE(packet_ietf);
} else if (framer_.version().HasIetfInvariantHeader()) {
p = packet46;
p_size = ABSL_ARRAYSIZE(packet46);
@@ -7961,7 +8330,7 @@ TEST_P(QuicFramerTest, BuildCloseFramePacketExtendedInfo) {
'n',
};
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -7990,8 +8359,8 @@ TEST_P(QuicFramerTest, BuildCloseFramePacketExtendedInfo) {
unsigned char* p = packet;
size_t p_size = ABSL_ARRAYSIZE(packet);
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
- p = packet99;
- p_size = ABSL_ARRAYSIZE(packet99);
+ p = packet_ietf;
+ p_size = ABSL_ARRAYSIZE(packet_ietf);
} else if (framer_.version().HasIetfInvariantHeader()) {
p = packet46;
p_size = ABSL_ARRAYSIZE(packet46);
@@ -8116,7 +8485,7 @@ TEST_P(QuicFramerTest, BuildTruncatedCloseFramePacket) {
'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
};
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -8171,8 +8540,8 @@ TEST_P(QuicFramerTest, BuildTruncatedCloseFramePacket) {
unsigned char* p = packet;
size_t p_size = ABSL_ARRAYSIZE(packet);
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
- p = packet99;
- p_size = ABSL_ARRAYSIZE(packet99);
+ p = packet_ietf;
+ p_size = ABSL_ARRAYSIZE(packet_ietf);
} else if (framer_.version().HasIetfInvariantHeader()) {
p = packet46;
p_size = ABSL_ARRAYSIZE(packet46);
@@ -8206,7 +8575,7 @@ TEST_P(QuicFramerTest, BuildApplicationCloseFramePacket) {
// clang-format off
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -8232,8 +8601,8 @@ TEST_P(QuicFramerTest, BuildApplicationCloseFramePacket) {
ASSERT_TRUE(data != nullptr);
quiche::test::CompareCharArraysWithHexError(
- "constructed packet", data->data(), data->length(), AsChars(packet99),
- ABSL_ARRAYSIZE(packet99));
+ "constructed packet", data->data(), data->length(), AsChars(packet_ietf),
+ ABSL_ARRAYSIZE(packet_ietf));
}
TEST_P(QuicFramerTest, BuildTruncatedApplicationCloseFramePacket) {
@@ -8259,7 +8628,7 @@ TEST_P(QuicFramerTest, BuildTruncatedApplicationCloseFramePacket) {
QuicFrames frames = {QuicFrame(&app_close_frame)};
// clang-format off
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -8313,8 +8682,8 @@ TEST_P(QuicFramerTest, BuildTruncatedApplicationCloseFramePacket) {
ASSERT_TRUE(data != nullptr);
quiche::test::CompareCharArraysWithHexError(
- "constructed packet", data->data(), data->length(), AsChars(packet99),
- ABSL_ARRAYSIZE(packet99));
+ "constructed packet", data->data(), data->length(), AsChars(packet_ietf),
+ ABSL_ARRAYSIZE(packet_ietf));
}
TEST_P(QuicFramerTest, BuildGoAwayPacket) {
@@ -8585,7 +8954,7 @@ TEST_P(QuicFramerTest, BuildWindowUpdatePacket) {
0x55, 0x66, 0x77, 0x88,
};
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -8609,8 +8978,8 @@ TEST_P(QuicFramerTest, BuildWindowUpdatePacket) {
unsigned char* p = packet;
size_t p_size = ABSL_ARRAYSIZE(packet);
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
- p = packet99;
- p_size = ABSL_ARRAYSIZE(packet99);
+ p = packet_ietf;
+ p_size = ABSL_ARRAYSIZE(packet_ietf);
} else if (framer_.version().HasIetfInvariantHeader()) {
p = packet46;
p_size = ABSL_ARRAYSIZE(packet46);
@@ -8639,7 +9008,7 @@ TEST_P(QuicFramerTest, BuildMaxStreamDataPacket) {
QuicFrames frames = {QuicFrame(&window_update_frame)};
// clang-format off
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -8661,8 +9030,8 @@ TEST_P(QuicFramerTest, BuildMaxStreamDataPacket) {
ASSERT_TRUE(data != nullptr);
quiche::test::CompareCharArraysWithHexError(
- "constructed packet", data->data(), data->length(), AsChars(packet99),
- ABSL_ARRAYSIZE(packet99));
+ "constructed packet", data->data(), data->length(), AsChars(packet_ietf),
+ ABSL_ARRAYSIZE(packet_ietf));
}
TEST_P(QuicFramerTest, BuildMaxDataPacket) {
@@ -8685,7 +9054,7 @@ TEST_P(QuicFramerTest, BuildMaxDataPacket) {
QuicFrames frames = {QuicFrame(&window_update_frame)};
// clang-format off
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -8705,8 +9074,8 @@ TEST_P(QuicFramerTest, BuildMaxDataPacket) {
ASSERT_TRUE(data != nullptr);
quiche::test::CompareCharArraysWithHexError(
- "constructed packet", data->data(), data->length(), AsChars(packet99),
- ABSL_ARRAYSIZE(packet99));
+ "constructed packet", data->data(), data->length(), AsChars(packet_ietf),
+ ABSL_ARRAYSIZE(packet_ietf));
}
TEST_P(QuicFramerTest, BuildBlockedPacket) {
@@ -8760,7 +9129,7 @@ TEST_P(QuicFramerTest, BuildBlockedPacket) {
0x01, 0x02, 0x03, 0x04,
};
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// type (short packet, 4 byte packet number)
0x43,
// connection_id
@@ -8781,8 +9150,8 @@ TEST_P(QuicFramerTest, BuildBlockedPacket) {
unsigned char* p = packet;
size_t p_size = ABSL_ARRAYSIZE(packet);
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
- p = packet99;
- p_size = ABSL_ARRAYSIZE(packet99);
+ p = packet_ietf;
+ p_size = ABSL_ARRAYSIZE(packet_ietf);
} else if (framer_.version().HasIetfInvariantHeader()) {
p = packet46;
p_size = ABSL_ARRAYSIZE(packet46);
@@ -8827,7 +9196,7 @@ TEST_P(QuicFramerTest, BuildPingPacket) {
0x07,
};
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -8842,7 +9211,7 @@ TEST_P(QuicFramerTest, BuildPingPacket) {
unsigned char* p = packet;
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
- p = packet99;
+ p = packet_ietf;
} else if (framer_.version().HasIetfInvariantHeader()) {
p = packet46;
}
@@ -8973,7 +9342,7 @@ TEST_P(QuicFramerTest, BuildMessagePacket) {
'm', 'e', 's', 's', 'a', 'g', 'e', '2'
};
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -8996,7 +9365,7 @@ TEST_P(QuicFramerTest, BuildMessagePacket) {
unsigned char* p = packet46;
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
- p = packet99;
+ p = packet_ietf;
}
std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
@@ -9043,7 +9412,7 @@ TEST_P(QuicFramerTest, BuildMtuDiscoveryPacket) {
0x07,
};
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -9061,7 +9430,7 @@ TEST_P(QuicFramerTest, BuildMtuDiscoveryPacket) {
unsigned char* p = packet;
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
- p = packet99;
+ p = packet_ietf;
} else if (framer_.version().HasIetfInvariantHeader()) {
p = packet46;
}
@@ -9238,8 +9607,7 @@ TEST_P(QuicFramerTest, BuildPublicResetPacketWithEndpointId) {
}
TEST_P(QuicFramerTest, BuildIetfStatelessResetPacket) {
- if (GetQuicRestartFlag(quic_fix_stateless_reset2)) {
- // clang-format off
+ // clang-format off
unsigned char packet[] = {
// 1st byte 01XX XXXX
0x40,
@@ -9249,76 +9617,45 @@ TEST_P(QuicFramerTest, BuildIetfStatelessResetPacket) {
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f
};
- // clang-format on
-
- // Build the minimal stateless reset packet.
- std::unique_ptr<QuicEncryptedPacket> data(
- framer_.BuildIetfStatelessResetPacket(
- FramerTestConnectionId(),
- QuicFramer::GetMinStatelessResetPacketLength() + 1,
- kTestStatelessResetToken));
- ASSERT_TRUE(data);
- EXPECT_EQ(QuicFramer::GetMinStatelessResetPacketLength(), data->length());
- // Verify the first 2 bits are 01.
- EXPECT_FALSE(data->data()[0] & FLAGS_LONG_HEADER);
- EXPECT_TRUE(data->data()[0] & FLAGS_FIXED_BIT);
- // Verify stateless reset token.
- quiche::test::CompareCharArraysWithHexError(
- "constructed packet",
- data->data() + data->length() - kStatelessResetTokenLength,
- kStatelessResetTokenLength,
- AsChars(packet) + ABSL_ARRAYSIZE(packet) - kStatelessResetTokenLength,
- kStatelessResetTokenLength);
-
- // Packets with length <= minimal stateless reset does not trigger stateless
- // reset.
- std::unique_ptr<QuicEncryptedPacket> data2(
- framer_.BuildIetfStatelessResetPacket(
- FramerTestConnectionId(),
- QuicFramer::GetMinStatelessResetPacketLength(),
- kTestStatelessResetToken));
- ASSERT_FALSE(data2);
-
- // Do not send stateless reset >= minimal stateless reset + 1 + max
- // connection ID length.
- std::unique_ptr<QuicEncryptedPacket> data3(
- framer_.BuildIetfStatelessResetPacket(FramerTestConnectionId(), 1000,
- kTestStatelessResetToken));
- ASSERT_TRUE(data3);
- EXPECT_EQ(QuicFramer::GetMinStatelessResetPacketLength() + 1 +
- kQuicMaxConnectionIdWithLengthPrefixLength,
- data3->length());
- return;
- }
- // clang-format off
- unsigned char packet[] = {
- // type (short header, 1 byte packet number)
- 0x70,
- // random packet number
- 0xFE,
- // stateless reset token
- 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
- 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
- };
// clang-format on
+ // Build the minimal stateless reset packet.
std::unique_ptr<QuicEncryptedPacket> data(
- framer_.BuildIetfStatelessResetPacket(FramerTestConnectionId(), 0,
- kTestStatelessResetToken));
- ASSERT_TRUE(data != nullptr);
- // Skip packet number byte which is random in stateless reset packet.
- quiche::test::CompareCharArraysWithHexError(
- "constructed packet", data->data(), 1, AsChars(packet), 1);
- const size_t random_bytes_length =
- data->length() - kPacketHeaderTypeSize - kStatelessResetTokenLength;
- EXPECT_EQ(kMinRandomBytesLengthInStatelessReset, random_bytes_length);
- // Verify stateless reset token is correct.
+ framer_.BuildIetfStatelessResetPacket(
+ FramerTestConnectionId(),
+ QuicFramer::GetMinStatelessResetPacketLength() + 1,
+ kTestStatelessResetToken));
+ ASSERT_TRUE(data);
+ EXPECT_EQ(QuicFramer::GetMinStatelessResetPacketLength(), data->length());
+ // Verify the first 2 bits are 01.
+ EXPECT_FALSE(data->data()[0] & FLAGS_LONG_HEADER);
+ EXPECT_TRUE(data->data()[0] & FLAGS_FIXED_BIT);
+ // Verify stateless reset token.
quiche::test::CompareCharArraysWithHexError(
"constructed packet",
data->data() + data->length() - kStatelessResetTokenLength,
kStatelessResetTokenLength,
AsChars(packet) + ABSL_ARRAYSIZE(packet) - kStatelessResetTokenLength,
kStatelessResetTokenLength);
+
+ // Packets with length <= minimal stateless reset does not trigger stateless
+ // reset.
+ std::unique_ptr<QuicEncryptedPacket> data2(
+ framer_.BuildIetfStatelessResetPacket(
+ FramerTestConnectionId(),
+ QuicFramer::GetMinStatelessResetPacketLength(),
+ kTestStatelessResetToken));
+ ASSERT_FALSE(data2);
+
+ // Do not send stateless reset >= minimal stateless reset + 1 + max
+ // connection ID length.
+ std::unique_ptr<QuicEncryptedPacket> data3(
+ framer_.BuildIetfStatelessResetPacket(FramerTestConnectionId(), 1000,
+ kTestStatelessResetToken));
+ ASSERT_TRUE(data3);
+ EXPECT_EQ(QuicFramer::GetMinStatelessResetPacketLength() + 1 +
+ kQuicMaxConnectionIdWithLengthPrefixLength,
+ data3->length());
}
TEST_P(QuicFramerTest, EncryptPacket) {
@@ -9758,7 +10095,7 @@ TEST_P(QuicFramerTest, StopPacketProcessing) {
0x9A, 0xBE,
};
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -9810,8 +10147,8 @@ TEST_P(QuicFramerTest, StopPacketProcessing) {
unsigned char* p = packet;
size_t p_size = ABSL_ARRAYSIZE(packet);
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
- p = packet99;
- p_size = ABSL_ARRAYSIZE(packet99);
+ p = packet_ietf;
+ p_size = ABSL_ARRAYSIZE(packet_ietf);
} else if (framer_.version().HasIetfInvariantHeader()) {
p = packet46;
p_size = ABSL_ARRAYSIZE(packet46);
@@ -9927,7 +10264,7 @@ TEST_P(QuicFramerTest, IetfBlockedFrame) {
SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
// clang-format off
- PacketFragments packet99 = {
+ PacketFragments packet_ietf = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -9947,7 +10284,7 @@ TEST_P(QuicFramerTest, IetfBlockedFrame) {
// clang-format on
std::unique_ptr<QuicEncryptedPacket> encrypted(
- AssemblePacketFromFragments(packet99));
+ AssemblePacketFromFragments(packet_ietf));
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
EXPECT_THAT(framer_.error(), IsQuicNoError());
@@ -9958,7 +10295,7 @@ TEST_P(QuicFramerTest, IetfBlockedFrame) {
EXPECT_EQ(kStreamOffset, visitor_.blocked_frame_.offset);
- CheckFramingBoundaries(packet99, QUIC_INVALID_BLOCKED_DATA);
+ CheckFramingBoundaries(packet_ietf, QUIC_INVALID_BLOCKED_DATA);
}
TEST_P(QuicFramerTest, BuildIetfBlockedPacket) {
@@ -9979,7 +10316,7 @@ TEST_P(QuicFramerTest, BuildIetfBlockedPacket) {
QuicFrames frames = {QuicFrame(&frame)};
// clang-format off
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -9998,8 +10335,8 @@ TEST_P(QuicFramerTest, BuildIetfBlockedPacket) {
ASSERT_TRUE(data != nullptr);
quiche::test::CompareCharArraysWithHexError(
- "constructed packet", data->data(), data->length(), AsChars(packet99),
- ABSL_ARRAYSIZE(packet99));
+ "constructed packet", data->data(), data->length(), AsChars(packet_ietf),
+ ABSL_ARRAYSIZE(packet_ietf));
}
TEST_P(QuicFramerTest, IetfStreamBlockedFrame) {
@@ -10010,7 +10347,7 @@ TEST_P(QuicFramerTest, IetfStreamBlockedFrame) {
SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
// clang-format off
- PacketFragments packet99 = {
+ PacketFragments packet_ietf = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -10032,7 +10369,7 @@ TEST_P(QuicFramerTest, IetfStreamBlockedFrame) {
// clang-format on
std::unique_ptr<QuicEncryptedPacket> encrypted(
- AssemblePacketFromFragments(packet99));
+ AssemblePacketFromFragments(packet_ietf));
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
EXPECT_THAT(framer_.error(), IsQuicNoError());
@@ -10044,7 +10381,7 @@ TEST_P(QuicFramerTest, IetfStreamBlockedFrame) {
EXPECT_EQ(kStreamId, visitor_.blocked_frame_.stream_id);
EXPECT_EQ(kStreamOffset, visitor_.blocked_frame_.offset);
- CheckFramingBoundaries(packet99, QUIC_INVALID_STREAM_BLOCKED_DATA);
+ CheckFramingBoundaries(packet_ietf, QUIC_INVALID_STREAM_BLOCKED_DATA);
}
TEST_P(QuicFramerTest, BuildIetfStreamBlockedPacket) {
@@ -10065,7 +10402,7 @@ TEST_P(QuicFramerTest, BuildIetfStreamBlockedPacket) {
QuicFrames frames = {QuicFrame(&frame)};
// clang-format off
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -10086,8 +10423,8 @@ TEST_P(QuicFramerTest, BuildIetfStreamBlockedPacket) {
ASSERT_TRUE(data != nullptr);
quiche::test::CompareCharArraysWithHexError(
- "constructed packet", data->data(), data->length(), AsChars(packet99),
- ABSL_ARRAYSIZE(packet99));
+ "constructed packet", data->data(), data->length(), AsChars(packet_ietf),
+ ABSL_ARRAYSIZE(packet_ietf));
}
TEST_P(QuicFramerTest, BiDiMaxStreamsFrame) {
@@ -10098,7 +10435,7 @@ TEST_P(QuicFramerTest, BiDiMaxStreamsFrame) {
SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
// clang-format off
- PacketFragments packet99 = {
+ PacketFragments packet_ietf = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -10118,7 +10455,7 @@ TEST_P(QuicFramerTest, BiDiMaxStreamsFrame) {
// clang-format on
std::unique_ptr<QuicEncryptedPacket> encrypted(
- AssemblePacketFromFragments(packet99));
+ AssemblePacketFromFragments(packet_ietf));
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
EXPECT_THAT(framer_.error(), IsQuicNoError());
@@ -10129,7 +10466,7 @@ TEST_P(QuicFramerTest, BiDiMaxStreamsFrame) {
EXPECT_EQ(3u, visitor_.max_streams_frame_.stream_count);
EXPECT_FALSE(visitor_.max_streams_frame_.unidirectional);
- CheckFramingBoundaries(packet99, QUIC_MAX_STREAMS_DATA);
+ CheckFramingBoundaries(packet_ietf, QUIC_MAX_STREAMS_DATA);
}
TEST_P(QuicFramerTest, UniDiMaxStreamsFrame) {
@@ -10140,7 +10477,7 @@ TEST_P(QuicFramerTest, UniDiMaxStreamsFrame) {
SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
// clang-format off
- PacketFragments packet99 = {
+ PacketFragments packet_ietf = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -10158,7 +10495,7 @@ TEST_P(QuicFramerTest, UniDiMaxStreamsFrame) {
// clang-format on
std::unique_ptr<QuicEncryptedPacket> encrypted(
- AssemblePacketFromFragments(packet99));
+ AssemblePacketFromFragments(packet_ietf));
QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
@@ -10170,7 +10507,7 @@ TEST_P(QuicFramerTest, UniDiMaxStreamsFrame) {
EXPECT_EQ(3u, visitor_.max_streams_frame_.stream_count);
EXPECT_TRUE(visitor_.max_streams_frame_.unidirectional);
- CheckFramingBoundaries(packet99, QUIC_MAX_STREAMS_DATA);
+ CheckFramingBoundaries(packet_ietf, QUIC_MAX_STREAMS_DATA);
}
TEST_P(QuicFramerTest, ServerUniDiMaxStreamsFrame) {
@@ -10181,7 +10518,7 @@ TEST_P(QuicFramerTest, ServerUniDiMaxStreamsFrame) {
SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
// clang-format off
- PacketFragments packet99 = {
+ PacketFragments packet_ietf = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -10201,7 +10538,7 @@ TEST_P(QuicFramerTest, ServerUniDiMaxStreamsFrame) {
// clang-format on
std::unique_ptr<QuicEncryptedPacket> encrypted(
- AssemblePacketFromFragments(packet99));
+ AssemblePacketFromFragments(packet_ietf));
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
EXPECT_THAT(framer_.error(), IsQuicNoError());
@@ -10212,7 +10549,7 @@ TEST_P(QuicFramerTest, ServerUniDiMaxStreamsFrame) {
EXPECT_EQ(3u, visitor_.max_streams_frame_.stream_count);
EXPECT_TRUE(visitor_.max_streams_frame_.unidirectional);
- CheckFramingBoundaries(packet99, QUIC_MAX_STREAMS_DATA);
+ CheckFramingBoundaries(packet_ietf, QUIC_MAX_STREAMS_DATA);
}
TEST_P(QuicFramerTest, ClientUniDiMaxStreamsFrame) {
@@ -10223,7 +10560,7 @@ TEST_P(QuicFramerTest, ClientUniDiMaxStreamsFrame) {
SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
// clang-format off
- PacketFragments packet99 = {
+ PacketFragments packet_ietf = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -10241,7 +10578,7 @@ TEST_P(QuicFramerTest, ClientUniDiMaxStreamsFrame) {
// clang-format on
std::unique_ptr<QuicEncryptedPacket> encrypted(
- AssemblePacketFromFragments(packet99));
+ AssemblePacketFromFragments(packet_ietf));
QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
@@ -10253,7 +10590,7 @@ TEST_P(QuicFramerTest, ClientUniDiMaxStreamsFrame) {
EXPECT_EQ(3u, visitor_.max_streams_frame_.stream_count);
EXPECT_TRUE(visitor_.max_streams_frame_.unidirectional);
- CheckFramingBoundaries(packet99, QUIC_MAX_STREAMS_DATA);
+ CheckFramingBoundaries(packet_ietf, QUIC_MAX_STREAMS_DATA);
}
// The following four tests ensure that the framer can deserialize a stream
@@ -10270,7 +10607,7 @@ TEST_P(QuicFramerTest, BiDiMaxStreamsFrameTooBig) {
SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
// clang-format off
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -10287,8 +10624,8 @@ TEST_P(QuicFramerTest, BiDiMaxStreamsFrameTooBig) {
};
// clang-format on
- QuicEncryptedPacket encrypted(AsChars(packet99), ABSL_ARRAYSIZE(packet99),
- false);
+ QuicEncryptedPacket encrypted(AsChars(packet_ietf),
+ ABSL_ARRAYSIZE(packet_ietf), false);
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
EXPECT_THAT(framer_.error(), IsQuicNoError());
ASSERT_TRUE(visitor_.header_.get());
@@ -10308,7 +10645,7 @@ TEST_P(QuicFramerTest, ClientBiDiMaxStreamsFrameTooBig) {
SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
// clang-format off
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// type (short header, 4 byte packet number)
0x43,
// Test runs in client mode, no connection id
@@ -10324,8 +10661,8 @@ TEST_P(QuicFramerTest, ClientBiDiMaxStreamsFrameTooBig) {
};
// clang-format on
- QuicEncryptedPacket encrypted(AsChars(packet99), ABSL_ARRAYSIZE(packet99),
- false);
+ QuicEncryptedPacket encrypted(AsChars(packet_ietf),
+ ABSL_ARRAYSIZE(packet_ietf), false);
QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
@@ -10347,7 +10684,7 @@ TEST_P(QuicFramerTest, ServerUniDiMaxStreamsFrameTooBig) {
SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
// clang-format off
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -10364,8 +10701,8 @@ TEST_P(QuicFramerTest, ServerUniDiMaxStreamsFrameTooBig) {
};
// clang-format on
- QuicEncryptedPacket encrypted(AsChars(packet99), ABSL_ARRAYSIZE(packet99),
- false);
+ QuicEncryptedPacket encrypted(AsChars(packet_ietf),
+ ABSL_ARRAYSIZE(packet_ietf), false);
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
EXPECT_THAT(framer_.error(), IsQuicNoError());
@@ -10386,7 +10723,7 @@ TEST_P(QuicFramerTest, ClientUniDiMaxStreamsFrameTooBig) {
SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
// clang-format off
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// type (short header, 4 byte packet number)
0x43,
// Test runs in client mode, no connection id
@@ -10402,8 +10739,8 @@ TEST_P(QuicFramerTest, ClientUniDiMaxStreamsFrameTooBig) {
};
// clang-format on
- QuicEncryptedPacket encrypted(AsChars(packet99), ABSL_ARRAYSIZE(packet99),
- false);
+ QuicEncryptedPacket encrypted(AsChars(packet_ietf),
+ ABSL_ARRAYSIZE(packet_ietf), false);
QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
@@ -10426,7 +10763,7 @@ TEST_P(QuicFramerTest, MaxStreamsFrameZeroCount) {
SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
// clang-format off
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -10440,8 +10777,8 @@ TEST_P(QuicFramerTest, MaxStreamsFrameZeroCount) {
};
// clang-format on
- QuicEncryptedPacket encrypted(AsChars(packet99), ABSL_ARRAYSIZE(packet99),
- false);
+ QuicEncryptedPacket encrypted(AsChars(packet_ietf),
+ ABSL_ARRAYSIZE(packet_ietf), false);
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
}
@@ -10453,7 +10790,7 @@ TEST_P(QuicFramerTest, ServerBiDiStreamsBlockedFrame) {
SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
// clang-format off
- PacketFragments packet99 = {
+ PacketFragments packet_ietf = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -10473,7 +10810,7 @@ TEST_P(QuicFramerTest, ServerBiDiStreamsBlockedFrame) {
// clang-format on
std::unique_ptr<QuicEncryptedPacket> encrypted(
- AssemblePacketFromFragments(packet99));
+ AssemblePacketFromFragments(packet_ietf));
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
EXPECT_THAT(framer_.error(), IsQuicNoError());
@@ -10485,7 +10822,7 @@ TEST_P(QuicFramerTest, ServerBiDiStreamsBlockedFrame) {
EXPECT_EQ(0u, visitor_.max_streams_frame_.stream_count);
EXPECT_TRUE(visitor_.max_streams_frame_.unidirectional);
- CheckFramingBoundaries(packet99, QUIC_MAX_STREAMS_DATA);
+ CheckFramingBoundaries(packet_ietf, QUIC_MAX_STREAMS_DATA);
}
TEST_P(QuicFramerTest, BiDiStreamsBlockedFrame) {
@@ -10496,7 +10833,7 @@ TEST_P(QuicFramerTest, BiDiStreamsBlockedFrame) {
SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
// clang-format off
- PacketFragments packet99 = {
+ PacketFragments packet_ietf = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -10517,7 +10854,7 @@ TEST_P(QuicFramerTest, BiDiStreamsBlockedFrame) {
// clang-format on
std::unique_ptr<QuicEncryptedPacket> encrypted(
- AssemblePacketFromFragments(packet99));
+ AssemblePacketFromFragments(packet_ietf));
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
EXPECT_THAT(framer_.error(), IsQuicNoError());
@@ -10529,7 +10866,7 @@ TEST_P(QuicFramerTest, BiDiStreamsBlockedFrame) {
EXPECT_EQ(3u, visitor_.streams_blocked_frame_.stream_count);
EXPECT_FALSE(visitor_.streams_blocked_frame_.unidirectional);
- CheckFramingBoundaries(packet99, QUIC_STREAMS_BLOCKED_DATA);
+ CheckFramingBoundaries(packet_ietf, QUIC_STREAMS_BLOCKED_DATA);
}
TEST_P(QuicFramerTest, UniDiStreamsBlockedFrame) {
@@ -10540,7 +10877,7 @@ TEST_P(QuicFramerTest, UniDiStreamsBlockedFrame) {
SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
// clang-format off
- PacketFragments packet99 = {
+ PacketFragments packet_ietf = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -10561,7 +10898,7 @@ TEST_P(QuicFramerTest, UniDiStreamsBlockedFrame) {
// clang-format on
std::unique_ptr<QuicEncryptedPacket> encrypted(
- AssemblePacketFromFragments(packet99));
+ AssemblePacketFromFragments(packet_ietf));
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
EXPECT_THAT(framer_.error(), IsQuicNoError());
@@ -10572,7 +10909,7 @@ TEST_P(QuicFramerTest, UniDiStreamsBlockedFrame) {
EXPECT_EQ(3u, visitor_.streams_blocked_frame_.stream_count);
EXPECT_TRUE(visitor_.streams_blocked_frame_.unidirectional);
- CheckFramingBoundaries(packet99, QUIC_STREAMS_BLOCKED_DATA);
+ CheckFramingBoundaries(packet_ietf, QUIC_STREAMS_BLOCKED_DATA);
}
TEST_P(QuicFramerTest, ClientUniDiStreamsBlockedFrame) {
@@ -10583,7 +10920,7 @@ TEST_P(QuicFramerTest, ClientUniDiStreamsBlockedFrame) {
SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
// clang-format off
- PacketFragments packet99 = {
+ PacketFragments packet_ietf = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -10602,7 +10939,7 @@ TEST_P(QuicFramerTest, ClientUniDiStreamsBlockedFrame) {
// clang-format on
std::unique_ptr<QuicEncryptedPacket> encrypted(
- AssemblePacketFromFragments(packet99));
+ AssemblePacketFromFragments(packet_ietf));
QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
@@ -10614,7 +10951,7 @@ TEST_P(QuicFramerTest, ClientUniDiStreamsBlockedFrame) {
EXPECT_EQ(3u, visitor_.streams_blocked_frame_.stream_count);
EXPECT_TRUE(visitor_.streams_blocked_frame_.unidirectional);
- CheckFramingBoundaries(packet99, QUIC_STREAMS_BLOCKED_DATA);
+ CheckFramingBoundaries(packet_ietf, QUIC_STREAMS_BLOCKED_DATA);
}
// Check that when we get a STREAMS_BLOCKED frame that specifies too large
@@ -10629,7 +10966,7 @@ TEST_P(QuicFramerTest, StreamsBlockedFrameTooBig) {
SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
// clang-format off
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// type (short header, 4 byte packet number)
0x43,
// Test runs in client mode, no connection id
@@ -10645,8 +10982,8 @@ TEST_P(QuicFramerTest, StreamsBlockedFrameTooBig) {
};
// clang-format on
- QuicEncryptedPacket encrypted(AsChars(packet99), ABSL_ARRAYSIZE(packet99),
- false);
+ QuicEncryptedPacket encrypted(AsChars(packet_ietf),
+ ABSL_ARRAYSIZE(packet_ietf), false);
QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
EXPECT_FALSE(framer_.ProcessPacket(encrypted));
@@ -10665,7 +11002,7 @@ TEST_P(QuicFramerTest, StreamsBlockedFrameZeroCount) {
SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
// clang-format off
- PacketFragments packet99 = {
+ PacketFragments packet_ietf = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -10686,7 +11023,7 @@ TEST_P(QuicFramerTest, StreamsBlockedFrameZeroCount) {
// clang-format on
std::unique_ptr<QuicEncryptedPacket> encrypted(
- AssemblePacketFromFragments(packet99));
+ AssemblePacketFromFragments(packet_ietf));
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
EXPECT_THAT(framer_.error(), IsQuicNoError());
@@ -10698,7 +11035,7 @@ TEST_P(QuicFramerTest, StreamsBlockedFrameZeroCount) {
EXPECT_EQ(0u, visitor_.streams_blocked_frame_.stream_count);
EXPECT_TRUE(visitor_.streams_blocked_frame_.unidirectional);
- CheckFramingBoundaries(packet99, QUIC_STREAMS_BLOCKED_DATA);
+ CheckFramingBoundaries(packet_ietf, QUIC_STREAMS_BLOCKED_DATA);
}
TEST_P(QuicFramerTest, BuildBiDiStreamsBlockedPacket) {
@@ -10720,7 +11057,7 @@ TEST_P(QuicFramerTest, BuildBiDiStreamsBlockedPacket) {
QuicFrames frames = {QuicFrame(frame)};
// clang-format off
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -10739,8 +11076,8 @@ TEST_P(QuicFramerTest, BuildBiDiStreamsBlockedPacket) {
ASSERT_TRUE(data != nullptr);
quiche::test::CompareCharArraysWithHexError(
- "constructed packet", data->data(), data->length(), AsChars(packet99),
- ABSL_ARRAYSIZE(packet99));
+ "constructed packet", data->data(), data->length(), AsChars(packet_ietf),
+ ABSL_ARRAYSIZE(packet_ietf));
}
TEST_P(QuicFramerTest, BuildUniStreamsBlockedPacket) {
@@ -10762,7 +11099,7 @@ TEST_P(QuicFramerTest, BuildUniStreamsBlockedPacket) {
QuicFrames frames = {QuicFrame(frame)};
// clang-format off
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -10781,8 +11118,8 @@ TEST_P(QuicFramerTest, BuildUniStreamsBlockedPacket) {
ASSERT_TRUE(data != nullptr);
quiche::test::CompareCharArraysWithHexError(
- "constructed packet", data->data(), data->length(), AsChars(packet99),
- ABSL_ARRAYSIZE(packet99));
+ "constructed packet", data->data(), data->length(), AsChars(packet_ietf),
+ ABSL_ARRAYSIZE(packet_ietf));
}
TEST_P(QuicFramerTest, BuildBiDiMaxStreamsPacket) {
@@ -10804,7 +11141,7 @@ TEST_P(QuicFramerTest, BuildBiDiMaxStreamsPacket) {
QuicFrames frames = {QuicFrame(frame)};
// clang-format off
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -10823,8 +11160,8 @@ TEST_P(QuicFramerTest, BuildBiDiMaxStreamsPacket) {
ASSERT_TRUE(data != nullptr);
quiche::test::CompareCharArraysWithHexError(
- "constructed packet", data->data(), data->length(), AsChars(packet99),
- ABSL_ARRAYSIZE(packet99));
+ "constructed packet", data->data(), data->length(), AsChars(packet_ietf),
+ ABSL_ARRAYSIZE(packet_ietf));
}
TEST_P(QuicFramerTest, BuildUniDiMaxStreamsPacket) {
@@ -10849,7 +11186,7 @@ TEST_P(QuicFramerTest, BuildUniDiMaxStreamsPacket) {
QuicFrames frames = {QuicFrame(frame)};
// clang-format off
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -10868,8 +11205,8 @@ TEST_P(QuicFramerTest, BuildUniDiMaxStreamsPacket) {
ASSERT_TRUE(data != nullptr);
quiche::test::CompareCharArraysWithHexError(
- "constructed packet", data->data(), data->length(), AsChars(packet99),
- ABSL_ARRAYSIZE(packet99));
+ "constructed packet", data->data(), data->length(), AsChars(packet_ietf),
+ ABSL_ARRAYSIZE(packet_ietf));
}
TEST_P(QuicFramerTest, NewConnectionIdFrame) {
@@ -10879,7 +11216,7 @@ TEST_P(QuicFramerTest, NewConnectionIdFrame) {
}
SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
// clang-format off
- PacketFragments packet99 = {
+ PacketFragments packet_ietf = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -10908,7 +11245,7 @@ TEST_P(QuicFramerTest, NewConnectionIdFrame) {
// clang-format on
std::unique_ptr<QuicEncryptedPacket> encrypted(
- AssemblePacketFromFragments(packet99));
+ AssemblePacketFromFragments(packet_ietf));
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
EXPECT_THAT(framer_.error(), IsQuicNoError());
@@ -10928,7 +11265,7 @@ TEST_P(QuicFramerTest, NewConnectionIdFrame) {
ASSERT_EQ(0u, visitor_.ack_frames_.size());
- CheckFramingBoundaries(packet99, QUIC_INVALID_NEW_CONNECTION_ID_DATA);
+ CheckFramingBoundaries(packet_ietf, QUIC_INVALID_NEW_CONNECTION_ID_DATA);
}
TEST_P(QuicFramerTest, NewConnectionIdFrameVariableLength) {
@@ -10938,7 +11275,7 @@ TEST_P(QuicFramerTest, NewConnectionIdFrameVariableLength) {
}
SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
// clang-format off
- PacketFragments packet99 = {
+ PacketFragments packet_ietf = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -10967,7 +11304,7 @@ TEST_P(QuicFramerTest, NewConnectionIdFrameVariableLength) {
// clang-format on
std::unique_ptr<QuicEncryptedPacket> encrypted(
- AssemblePacketFromFragments(packet99));
+ AssemblePacketFromFragments(packet_ietf));
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
EXPECT_THAT(framer_.error(), IsQuicNoError());
@@ -10987,7 +11324,7 @@ TEST_P(QuicFramerTest, NewConnectionIdFrameVariableLength) {
ASSERT_EQ(0u, visitor_.ack_frames_.size());
- CheckFramingBoundaries(packet99, QUIC_INVALID_NEW_CONNECTION_ID_DATA);
+ CheckFramingBoundaries(packet_ietf, QUIC_INVALID_NEW_CONNECTION_ID_DATA);
}
// Verifies that parsing a NEW_CONNECTION_ID frame with a length above the
@@ -10999,7 +11336,7 @@ TEST_P(QuicFramerTest, InvalidLongNewConnectionIdFrame) {
}
SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
// clang-format off
- PacketFragments packet99 = {
+ PacketFragments packet_ietf = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -11035,7 +11372,7 @@ TEST_P(QuicFramerTest, InvalidLongNewConnectionIdFrame) {
// clang-format on
std::unique_ptr<QuicEncryptedPacket> encrypted(
- AssemblePacketFromFragments(packet99));
+ AssemblePacketFromFragments(packet_ietf));
EXPECT_FALSE(framer_.ProcessPacket(*encrypted));
EXPECT_THAT(framer_.error(), IsError(QUIC_INVALID_NEW_CONNECTION_ID_DATA));
EXPECT_EQ("Invalid new connection ID length for version.",
@@ -11051,7 +11388,7 @@ TEST_P(QuicFramerTest, InvalidRetirePriorToNewConnectionIdFrame) {
}
SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
// clang-format off
- PacketFragments packet99 = {
+ PacketFragments packet_ietf = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -11080,7 +11417,7 @@ TEST_P(QuicFramerTest, InvalidRetirePriorToNewConnectionIdFrame) {
// clang-format on
std::unique_ptr<QuicEncryptedPacket> encrypted(
- AssemblePacketFromFragments(packet99));
+ AssemblePacketFromFragments(packet_ietf));
EXPECT_FALSE(framer_.ProcessPacket(*encrypted));
EXPECT_THAT(framer_.error(), IsError(QUIC_INVALID_NEW_CONNECTION_ID_DATA));
EXPECT_EQ("Retire_prior_to > sequence_number.", framer_.detailed_error());
@@ -11109,7 +11446,7 @@ TEST_P(QuicFramerTest, BuildNewConnectionIdFramePacket) {
QuicFrames frames = {QuicFrame(&frame)};
// clang-format off
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -11137,8 +11474,8 @@ TEST_P(QuicFramerTest, BuildNewConnectionIdFramePacket) {
ASSERT_TRUE(data != nullptr);
quiche::test::CompareCharArraysWithHexError(
- "constructed packet", data->data(), data->length(), AsChars(packet99),
- ABSL_ARRAYSIZE(packet99));
+ "constructed packet", data->data(), data->length(), AsChars(packet_ietf),
+ ABSL_ARRAYSIZE(packet_ietf));
}
TEST_P(QuicFramerTest, NewTokenFrame) {
@@ -11244,7 +11581,7 @@ TEST_P(QuicFramerTest, IetfStopSendingFrame) {
SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
// clang-format off
- PacketFragments packet99 = {
+ PacketFragments packet_ietf = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -11266,7 +11603,7 @@ TEST_P(QuicFramerTest, IetfStopSendingFrame) {
// clang-format on
std::unique_ptr<QuicEncryptedPacket> encrypted(
- AssemblePacketFromFragments(packet99));
+ AssemblePacketFromFragments(packet_ietf));
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
EXPECT_THAT(framer_.error(), IsQuicNoError());
@@ -11281,7 +11618,7 @@ TEST_P(QuicFramerTest, IetfStopSendingFrame) {
EXPECT_EQ(static_cast<uint64_t>(0x7654),
visitor_.stop_sending_frame_.ietf_error_code);
- CheckFramingBoundaries(packet99, QUIC_INVALID_STOP_SENDING_FRAME_DATA);
+ CheckFramingBoundaries(packet_ietf, QUIC_INVALID_STOP_SENDING_FRAME_DATA);
}
TEST_P(QuicFramerTest, BuildIetfStopSendingPacket) {
@@ -11304,7 +11641,7 @@ TEST_P(QuicFramerTest, BuildIetfStopSendingPacket) {
QuicFrames frames = {QuicFrame(&frame)};
// clang-format off
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -11325,8 +11662,8 @@ TEST_P(QuicFramerTest, BuildIetfStopSendingPacket) {
ASSERT_TRUE(data != nullptr);
quiche::test::CompareCharArraysWithHexError(
- "constructed packet", data->data(), data->length(), AsChars(packet99),
- ABSL_ARRAYSIZE(packet99));
+ "constructed packet", data->data(), data->length(), AsChars(packet_ietf),
+ ABSL_ARRAYSIZE(packet_ietf));
}
TEST_P(QuicFramerTest, IetfPathChallengeFrame) {
@@ -11337,7 +11674,7 @@ TEST_P(QuicFramerTest, IetfPathChallengeFrame) {
SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
// clang-format off
- PacketFragments packet99 = {
+ PacketFragments packet_ietf = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -11357,7 +11694,7 @@ TEST_P(QuicFramerTest, IetfPathChallengeFrame) {
// clang-format on
std::unique_ptr<QuicEncryptedPacket> encrypted(
- AssemblePacketFromFragments(packet99));
+ AssemblePacketFromFragments(packet_ietf));
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
EXPECT_THAT(framer_.error(), IsQuicNoError());
@@ -11369,7 +11706,7 @@ TEST_P(QuicFramerTest, IetfPathChallengeFrame) {
EXPECT_EQ(QuicPathFrameBuffer({{0, 1, 2, 3, 4, 5, 6, 7}}),
visitor_.path_challenge_frame_.data_buffer);
- CheckFramingBoundaries(packet99, QUIC_INVALID_PATH_CHALLENGE_DATA);
+ CheckFramingBoundaries(packet_ietf, QUIC_INVALID_PATH_CHALLENGE_DATA);
}
TEST_P(QuicFramerTest, BuildIetfPathChallengePacket) {
@@ -11389,7 +11726,7 @@ TEST_P(QuicFramerTest, BuildIetfPathChallengePacket) {
QuicFrames frames = {QuicFrame(&frame)};
// clang-format off
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -11408,8 +11745,8 @@ TEST_P(QuicFramerTest, BuildIetfPathChallengePacket) {
ASSERT_TRUE(data != nullptr);
quiche::test::CompareCharArraysWithHexError(
- "constructed packet", data->data(), data->length(), AsChars(packet99),
- ABSL_ARRAYSIZE(packet99));
+ "constructed packet", data->data(), data->length(), AsChars(packet_ietf),
+ ABSL_ARRAYSIZE(packet_ietf));
}
TEST_P(QuicFramerTest, IetfPathResponseFrame) {
@@ -11420,7 +11757,7 @@ TEST_P(QuicFramerTest, IetfPathResponseFrame) {
SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
// clang-format off
- PacketFragments packet99 = {
+ PacketFragments packet_ietf = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -11440,7 +11777,7 @@ TEST_P(QuicFramerTest, IetfPathResponseFrame) {
// clang-format on
std::unique_ptr<QuicEncryptedPacket> encrypted(
- AssemblePacketFromFragments(packet99));
+ AssemblePacketFromFragments(packet_ietf));
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
EXPECT_THAT(framer_.error(), IsQuicNoError());
@@ -11452,7 +11789,7 @@ TEST_P(QuicFramerTest, IetfPathResponseFrame) {
EXPECT_EQ(QuicPathFrameBuffer({{0, 1, 2, 3, 4, 5, 6, 7}}),
visitor_.path_response_frame_.data_buffer);
- CheckFramingBoundaries(packet99, QUIC_INVALID_PATH_RESPONSE_DATA);
+ CheckFramingBoundaries(packet_ietf, QUIC_INVALID_PATH_RESPONSE_DATA);
}
TEST_P(QuicFramerTest, BuildIetfPathResponsePacket) {
@@ -11472,7 +11809,7 @@ TEST_P(QuicFramerTest, BuildIetfPathResponsePacket) {
QuicFrames frames = {QuicFrame(&frame)};
// clang-format off
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -11491,8 +11828,8 @@ TEST_P(QuicFramerTest, BuildIetfPathResponsePacket) {
ASSERT_TRUE(data != nullptr);
quiche::test::CompareCharArraysWithHexError(
- "constructed packet", data->data(), data->length(), AsChars(packet99),
- ABSL_ARRAYSIZE(packet99));
+ "constructed packet", data->data(), data->length(), AsChars(packet_ietf),
+ ABSL_ARRAYSIZE(packet_ietf));
}
TEST_P(QuicFramerTest, GetRetransmittableControlFrameSize) {
@@ -12222,7 +12559,7 @@ TEST_P(QuicFramerTest, RetireConnectionIdFrame) {
}
SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
// clang-format off
- PacketFragments packet99 = {
+ PacketFragments packet_ietf = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -12242,7 +12579,7 @@ TEST_P(QuicFramerTest, RetireConnectionIdFrame) {
// clang-format on
std::unique_ptr<QuicEncryptedPacket> encrypted(
- AssemblePacketFromFragments(packet99));
+ AssemblePacketFromFragments(packet_ietf));
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
EXPECT_THAT(framer_.error(), IsQuicNoError());
@@ -12257,7 +12594,7 @@ TEST_P(QuicFramerTest, RetireConnectionIdFrame) {
ASSERT_EQ(0u, visitor_.ack_frames_.size());
- CheckFramingBoundaries(packet99, QUIC_INVALID_RETIRE_CONNECTION_ID_DATA);
+ CheckFramingBoundaries(packet_ietf, QUIC_INVALID_RETIRE_CONNECTION_ID_DATA);
}
TEST_P(QuicFramerTest, BuildRetireConnectionIdFramePacket) {
@@ -12278,7 +12615,7 @@ TEST_P(QuicFramerTest, BuildRetireConnectionIdFramePacket) {
QuicFrames frames = {QuicFrame(&frame)};
// clang-format off
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -12297,8 +12634,8 @@ TEST_P(QuicFramerTest, BuildRetireConnectionIdFramePacket) {
ASSERT_TRUE(data != nullptr);
quiche::test::CompareCharArraysWithHexError(
- "constructed packet", data->data(), data->length(), AsChars(packet99),
- ABSL_ARRAYSIZE(packet99));
+ "constructed packet", data->data(), data->length(), AsChars(packet_ietf),
+ ABSL_ARRAYSIZE(packet_ietf));
}
TEST_P(QuicFramerTest, AckFrameWithInvalidLargestObserved) {
@@ -12344,7 +12681,7 @@ TEST_P(QuicFramerTest, AckFrameWithInvalidLargestObserved) {
0x00
};
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -12368,8 +12705,8 @@ TEST_P(QuicFramerTest, AckFrameWithInvalidLargestObserved) {
unsigned char* p = packet;
size_t p_size = ABSL_ARRAYSIZE(packet);
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
- p = packet99;
- p_size = ABSL_ARRAYSIZE(packet99);
+ p = packet_ietf;
+ p_size = ABSL_ARRAYSIZE(packet_ietf);
} else if (framer_.version().HasIetfInvariantHeader()) {
p = packet46;
}
@@ -12422,7 +12759,7 @@ TEST_P(QuicFramerTest, FirstAckBlockJustUnderFlow) {
0x00
};
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -12446,8 +12783,8 @@ TEST_P(QuicFramerTest, FirstAckBlockJustUnderFlow) {
unsigned char* p = packet;
size_t p_size = ABSL_ARRAYSIZE(packet);
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
- p = packet99;
- p_size = ABSL_ARRAYSIZE(packet99);
+ p = packet_ietf;
+ p_size = ABSL_ARRAYSIZE(packet_ietf);
} else if (framer_.version().HasIetfInvariantHeader()) {
p = packet46;
p_size = ABSL_ARRAYSIZE(packet46);
@@ -12522,7 +12859,7 @@ TEST_P(QuicFramerTest, ThirdAckBlockJustUnderflow) {
0x00
};
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -12554,8 +12891,8 @@ TEST_P(QuicFramerTest, ThirdAckBlockJustUnderflow) {
unsigned char* p = packet;
size_t p_size = ABSL_ARRAYSIZE(packet);
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
- p = packet99;
- p_size = ABSL_ARRAYSIZE(packet99);
+ p = packet_ietf;
+ p_size = ABSL_ARRAYSIZE(packet_ietf);
} else if (framer_.version().HasIetfInvariantHeader()) {
p = packet46;
p_size = ABSL_ARRAYSIZE(packet46);
@@ -12636,7 +12973,7 @@ TEST_P(QuicFramerTest, CoalescedPacket) {
'O', '_', 'W', 'O',
'R', 'L', 'D', '?',
};
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// first coalesced packet
// public flags (long header with packet type ZERO_RTT_PROTECTED and
// 4-byte packet number)
@@ -12701,8 +13038,8 @@ TEST_P(QuicFramerTest, CoalescedPacket) {
unsigned char* p = packet;
size_t p_length = ABSL_ARRAYSIZE(packet);
if (framer_.version().HasIetfQuicFrames()) {
- p = packet99;
- p_length = ABSL_ARRAYSIZE(packet99);
+ p = packet_ietf;
+ p_length = ABSL_ARRAYSIZE(packet_ietf);
}
QuicEncryptedPacket encrypted(AsChars(p), p_length, false);
@@ -12778,7 +13115,7 @@ TEST_P(QuicFramerTest, CoalescedPacketWithUdpPadding) {
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
};
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// first coalesced packet
// public flags (long header with packet type ZERO_RTT_PROTECTED and
// 4-byte packet number)
@@ -12820,8 +13157,8 @@ TEST_P(QuicFramerTest, CoalescedPacketWithUdpPadding) {
unsigned char* p = packet;
size_t p_length = ABSL_ARRAYSIZE(packet);
if (framer_.version().HasIetfQuicFrames()) {
- p = packet99;
- p_length = ABSL_ARRAYSIZE(packet99);
+ p = packet_ietf;
+ p_length = ABSL_ARRAYSIZE(packet_ietf);
}
QuicEncryptedPacket encrypted(AsChars(p), p_length, false);
@@ -12906,7 +13243,7 @@ TEST_P(QuicFramerTest, CoalescedPacketWithDifferentVersion) {
'O', '_', 'W', 'O',
'R', 'L', 'D', '?',
};
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// first coalesced packet
// public flags (long header with packet type ZERO_RTT_PROTECTED and
// 4-byte packet number)
@@ -12971,8 +13308,8 @@ TEST_P(QuicFramerTest, CoalescedPacketWithDifferentVersion) {
unsigned char* p = packet;
size_t p_length = ABSL_ARRAYSIZE(packet);
if (framer_.version().HasIetfQuicFrames()) {
- p = packet99;
- p_length = ABSL_ARRAYSIZE(packet99);
+ p = packet_ietf;
+ p_length = ABSL_ARRAYSIZE(packet_ietf);
}
QuicEncryptedPacket encrypted(AsChars(p), p_length, false);
@@ -13278,7 +13615,7 @@ TEST_P(QuicFramerTest, UndecryptableCoalescedPacket) {
'O', '_', 'W', 'O',
'R', 'L', 'D', '?',
};
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// first coalesced packet
// public flags (long header with packet type HANDSHAKE and
// 4-byte packet number)
@@ -13344,8 +13681,8 @@ TEST_P(QuicFramerTest, UndecryptableCoalescedPacket) {
unsigned char* p = packet;
size_t p_length = ABSL_ARRAYSIZE(packet);
if (framer_.version().HasIetfQuicFrames()) {
- p = packet99;
- p_length = ABSL_ARRAYSIZE(packet99);
+ p = packet_ietf;
+ p_length = ABSL_ARRAYSIZE(packet_ietf);
}
QuicEncryptedPacket encrypted(AsChars(p), p_length, false);
@@ -13446,7 +13783,7 @@ TEST_P(QuicFramerTest, MismatchedCoalescedPacket) {
'O', '_', 'W', 'O',
'R', 'L', 'D', '?',
};
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// first coalesced packet
// public flags (long header with packet type ZERO_RTT_PROTECTED and
// 4-byte packet number)
@@ -13511,8 +13848,8 @@ TEST_P(QuicFramerTest, MismatchedCoalescedPacket) {
unsigned char* p = packet;
size_t p_length = ABSL_ARRAYSIZE(packet);
if (framer_.version().HasIetfQuicFrames()) {
- p = packet99;
- p_length = ABSL_ARRAYSIZE(packet99);
+ p = packet_ietf;
+ p_length = ABSL_ARRAYSIZE(packet_ietf);
}
QuicEncryptedPacket encrypted(AsChars(p), p_length, false);
@@ -13575,7 +13912,7 @@ TEST_P(QuicFramerTest, InvalidCoalescedPacket) {
0xD3,
// version would be here but we cut off the invalid coalesced header.
};
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// first coalesced packet
// public flags (long header with packet type ZERO_RTT_PROTECTED and
// 4-byte packet number)
@@ -13616,8 +13953,8 @@ TEST_P(QuicFramerTest, InvalidCoalescedPacket) {
unsigned char* p = packet;
size_t p_length = ABSL_ARRAYSIZE(packet);
if (framer_.version().HasIetfQuicFrames()) {
- p = packet99;
- p_length = ABSL_ARRAYSIZE(packet99);
+ p = packet_ietf;
+ p_length = ABSL_ARRAYSIZE(packet_ietf);
}
QuicEncryptedPacket encrypted(AsChars(p), p_length, false);
@@ -13809,7 +14146,7 @@ TEST_P(QuicFramerTest, MultiplePacketNumberSpaces) {
// padding frame
0x00,
};
- unsigned char long_header_packet99[] = {
+ unsigned char long_header_packet_ietf[] = {
// public flags (long header with packet type ZERO_RTT_PROTECTED and
// 4-byte packet number)
0xD3,
@@ -13844,8 +14181,8 @@ TEST_P(QuicFramerTest, MultiplePacketNumberSpaces) {
ABSL_ARRAYSIZE(long_header_packet), false)));
} else {
EXPECT_TRUE(framer_.ProcessPacket(
- QuicEncryptedPacket(AsChars(long_header_packet99),
- ABSL_ARRAYSIZE(long_header_packet99), false)));
+ QuicEncryptedPacket(AsChars(long_header_packet_ietf),
+ ABSL_ARRAYSIZE(long_header_packet_ietf), false)));
}
EXPECT_THAT(framer_.error(), IsQuicNoError());
@@ -14633,7 +14970,7 @@ TEST_P(QuicFramerTest, OverlyLargeAckDelay) {
}
SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
// clang-format off
- unsigned char packet99[] = {
+ unsigned char packet_ietf[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -14654,8 +14991,8 @@ TEST_P(QuicFramerTest, OverlyLargeAckDelay) {
};
// clang-format on
- framer_.ProcessPacket(
- QuicEncryptedPacket(AsChars(packet99), ABSL_ARRAYSIZE(packet99), false));
+ framer_.ProcessPacket(QuicEncryptedPacket(
+ AsChars(packet_ietf), ABSL_ARRAYSIZE(packet_ietf), false));
ASSERT_EQ(1u, visitor_.ack_frames_.size());
// Verify ack_delay_time is set correctly.
EXPECT_EQ(QuicTime::Delta::Infinite(),
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_idle_network_detector.cc b/chromium/net/third_party/quiche/src/quic/core/quic_idle_network_detector.cc
index ac6799ee46d..fceb1e7e9b0 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_idle_network_detector.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_idle_network_detector.cc
@@ -11,10 +11,11 @@ namespace quic {
namespace {
-class AlarmDelegate : public QuicAlarm::Delegate {
+class AlarmDelegate : public QuicAlarm::DelegateWithContext {
public:
- explicit AlarmDelegate(QuicIdleNetworkDetector* detector)
- : detector_(detector) {}
+ explicit AlarmDelegate(QuicIdleNetworkDetector* detector,
+ QuicConnectionContext* context)
+ : QuicAlarm::DelegateWithContext(context), detector_(detector) {}
AlarmDelegate(const AlarmDelegate&) = delete;
AlarmDelegate& operator=(const AlarmDelegate&) = delete;
@@ -28,20 +29,15 @@ class AlarmDelegate : public QuicAlarm::Delegate {
QuicIdleNetworkDetector::QuicIdleNetworkDetector(
Delegate* delegate, QuicTime now, QuicConnectionArena* arena,
- QuicAlarmFactory* alarm_factory)
+ QuicAlarmFactory* alarm_factory, QuicConnectionContext* context)
: delegate_(delegate),
start_time_(now),
handshake_timeout_(QuicTime::Delta::Infinite()),
time_of_last_received_packet_(now),
time_of_first_packet_sent_after_receiving_(QuicTime::Zero()),
idle_network_timeout_(QuicTime::Delta::Infinite()),
- alarm_(
- alarm_factory->CreateAlarm(arena->New<AlarmDelegate>(this), arena)) {
- if (no_alarm_after_stopped_) {
- QUIC_RELOADABLE_FLAG_COUNT_N(
- quic_idle_network_detector_no_alarm_after_stopped, 1, 2);
- }
-}
+ alarm_(alarm_factory->CreateAlarm(
+ arena->New<AlarmDelegate>(this, context), arena)) {}
void QuicIdleNetworkDetector::OnAlarm() {
if (handshake_timeout_.IsInfinite()) {
@@ -99,10 +95,7 @@ void QuicIdleNetworkDetector::OnPacketReceived(QuicTime now) {
}
void QuicIdleNetworkDetector::SetAlarm() {
- if (no_alarm_after_stopped_ && stopped_) {
- QUIC_RELOADABLE_FLAG_COUNT_N(
- quic_idle_network_detector_no_alarm_after_stopped, 2, 2);
-
+ if (stopped_) {
// TODO(wub): If this QUIC_BUG fires, it indicates a problem in the
// QuicConnection, which somehow called this function while disconnected.
// That problem needs to be fixed.
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_idle_network_detector.h b/chromium/net/third_party/quiche/src/quic/core/quic_idle_network_detector.h
index 1665104a186..2381c12cdc6 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_idle_network_detector.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_idle_network_detector.h
@@ -36,10 +36,10 @@ class QUIC_EXPORT_PRIVATE QuicIdleNetworkDetector {
virtual void OnIdleNetworkDetected() = 0;
};
- QuicIdleNetworkDetector(Delegate* delegate,
- QuicTime now,
+ QuicIdleNetworkDetector(Delegate* delegate, QuicTime now,
QuicConnectionArena* arena,
- QuicAlarmFactory* alarm_factory);
+ QuicAlarmFactory* alarm_factory,
+ QuicConnectionContext* context);
void OnAlarm();
@@ -111,9 +111,6 @@ class QUIC_EXPORT_PRIVATE QuicIdleNetworkDetector {
// Whether |StopDetection| has been called.
bool stopped_ = false;
-
- const bool no_alarm_after_stopped_ =
- GetQuicReloadableFlag(quic_idle_network_detector_no_alarm_after_stopped);
};
} // namespace quic
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 11d0cf76777..a6fd5d28ce7 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
@@ -32,7 +32,8 @@ class QuicIdleNetworkDetectorTest : public QuicTest {
QuicIdleNetworkDetectorTest() {
clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
detector_ = std::make_unique<QuicIdleNetworkDetector>(
- &delegate_, clock_.Now(), &arena_, &alarm_factory_);
+ &delegate_, clock_.Now(), &arena_, &alarm_factory_,
+ /*context=*/nullptr);
alarm_ = static_cast<MockAlarmFactory::TestAlarm*>(
QuicIdleNetworkDetectorTestPeer::GetAlarm(detector_.get()));
}
@@ -185,20 +186,12 @@ TEST_F(QuicIdleNetworkDetectorTest, ShorterIdleTimeoutOnSentPacket) {
TEST_F(QuicIdleNetworkDetectorTest, NoAlarmAfterStopped) {
detector_->StopDetection();
- if (GetQuicReloadableFlag(
- quic_idle_network_detector_no_alarm_after_stopped)) {
- EXPECT_QUIC_BUG(
- detector_->SetTimeouts(
- /*handshake_timeout=*/QuicTime::Delta::FromSeconds(30),
- /*idle_network_timeout=*/QuicTime::Delta::FromSeconds(20)),
- "SetAlarm called after stopped");
- EXPECT_FALSE(alarm_->IsSet());
- } else {
- detector_->SetTimeouts(
- /*handshake_timeout=*/QuicTime::Delta::FromSeconds(30),
- /*idle_network_timeout=*/QuicTime::Delta::FromSeconds(20));
- EXPECT_TRUE(alarm_->IsSet());
- }
+ EXPECT_QUIC_BUG(
+ detector_->SetTimeouts(
+ /*handshake_timeout=*/QuicTime::Delta::FromSeconds(30),
+ /*idle_network_timeout=*/QuicTime::Delta::FromSeconds(20)),
+ "SetAlarm called after stopped");
+ EXPECT_FALSE(alarm_->IsSet());
}
} // namespace
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_mtu_discovery.h b/chromium/net/third_party/quiche/src/quic/core/quic_mtu_discovery.h
index b16cc6aedca..dddd33de7dd 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_mtu_discovery.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_mtu_discovery.h
@@ -27,9 +27,9 @@ static_assert(kMtuDiscoveryAttempts + 8 < 8 * sizeof(QuicPacketNumber),
static_assert(kPacketsBetweenMtuProbesBase < (1 << 8),
"The initial number of packets between MTU probes is too high");
-// The incresed packet size targeted when doing path MTU discovery.
-const QuicByteCount kMtuDiscoveryTargetPacketSizeHigh = 1450;
-const QuicByteCount kMtuDiscoveryTargetPacketSizeLow = 1430;
+// The increased packet size targeted when doing path MTU discovery.
+const QuicByteCount kMtuDiscoveryTargetPacketSizeHigh = 1400;
+const QuicByteCount kMtuDiscoveryTargetPacketSizeLow = 1380;
static_assert(kMtuDiscoveryTargetPacketSizeLow <= kMaxOutgoingPacketSize,
"MTU discovery target is too large");
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_network_blackhole_detector.cc b/chromium/net/third_party/quiche/src/quic/core/quic_network_blackhole_detector.cc
index 4dca50832ac..2d9fc2d3a61 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_network_blackhole_detector.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_network_blackhole_detector.cc
@@ -10,10 +10,11 @@ namespace quic {
namespace {
-class AlarmDelegate : public QuicAlarm::Delegate {
+class AlarmDelegate : public QuicAlarm::DelegateWithContext {
public:
- explicit AlarmDelegate(QuicNetworkBlackholeDetector* detector)
- : detector_(detector) {}
+ explicit AlarmDelegate(QuicNetworkBlackholeDetector* detector,
+ QuicConnectionContext* context)
+ : QuicAlarm::DelegateWithContext(context), detector_(detector) {}
AlarmDelegate(const AlarmDelegate&) = delete;
AlarmDelegate& operator=(const AlarmDelegate&) = delete;
@@ -26,12 +27,11 @@ class AlarmDelegate : public QuicAlarm::Delegate {
} // namespace
QuicNetworkBlackholeDetector::QuicNetworkBlackholeDetector(
- Delegate* delegate,
- QuicConnectionArena* arena,
- QuicAlarmFactory* alarm_factory)
+ Delegate* delegate, QuicConnectionArena* arena,
+ QuicAlarmFactory* alarm_factory, QuicConnectionContext* context)
: delegate_(delegate),
- alarm_(
- alarm_factory->CreateAlarm(arena->New<AlarmDelegate>(this), arena)) {}
+ alarm_(alarm_factory->CreateAlarm(
+ arena->New<AlarmDelegate>(this, context), arena)) {}
void QuicNetworkBlackholeDetector::OnAlarm() {
QuicTime next_deadline = GetEarliestDeadline();
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_network_blackhole_detector.h b/chromium/net/third_party/quiche/src/quic/core/quic_network_blackhole_detector.h
index 82753f934a6..db52e8faa4f 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_network_blackhole_detector.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_network_blackhole_detector.h
@@ -40,9 +40,9 @@ class QUIC_EXPORT_PRIVATE QuicNetworkBlackholeDetector {
virtual void OnPathMtuReductionDetected() = 0;
};
- QuicNetworkBlackholeDetector(Delegate* delegate,
- QuicConnectionArena* arena,
- QuicAlarmFactory* alarm_factory);
+ QuicNetworkBlackholeDetector(Delegate* delegate, QuicConnectionArena* arena,
+ QuicAlarmFactory* alarm_factory,
+ QuicConnectionContext* context);
// Called to stop all detections. If |permanent|, the alarm will be cancelled
// permanently and future calls to RestartDetection will be no-op.
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 66bebfd455f..764ee9a1f5d 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
@@ -33,7 +33,7 @@ const size_t kBlackholeDelayInSeconds = 10;
class QuicNetworkBlackholeDetectorTest : public QuicTest {
public:
QuicNetworkBlackholeDetectorTest()
- : detector_(&delegate_, &arena_, &alarm_factory_),
+ : detector_(&delegate_, &arena_, &alarm_factory_, /*context=*/nullptr),
alarm_(static_cast<MockAlarmFactory::TestAlarm*>(
QuicNetworkBlackholeDetectorPeer::GetAlarm(&detector_))),
path_degrading_delay_(
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 53882ead440..02aae871e02 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
@@ -69,7 +69,7 @@ class QUIC_EXPORT_PRIVATE QuicOneBlockArena {
// QuicConnections currently use around 1KB of polymorphic types which would
// ordinarily be on the heap. Instead, store them inline in an arena.
-using QuicConnectionArena = QuicOneBlockArena<1056>;
+using QuicConnectionArena = QuicOneBlockArena<1152>;
} // namespace quic
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 94cf48a1d51..19168fb79ac 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
@@ -109,8 +109,7 @@ QuicPacketCreator::QuicPacketCreator(QuicConnectionId server_connection_id,
delegate) {}
QuicPacketCreator::QuicPacketCreator(QuicConnectionId server_connection_id,
- QuicFramer* framer,
- QuicRandom* random,
+ QuicFramer* framer, QuicRandom* random,
DelegateInterface* delegate)
: delegate_(delegate),
debug_delegate_(nullptr),
@@ -123,11 +122,7 @@ QuicPacketCreator::QuicPacketCreator(QuicConnectionId server_connection_id,
packet_size_(0),
server_connection_id_(server_connection_id),
client_connection_id_(EmptyQuicConnectionId()),
- packet_(QuicPacketNumber(),
- PACKET_1BYTE_PACKET_NUMBER,
- nullptr,
- 0,
- false,
+ packet_(QuicPacketNumber(), PACKET_1BYTE_PACKET_NUMBER, nullptr, 0, false,
false),
pending_padding_bytes_(0),
needs_full_padding_(false),
@@ -136,7 +131,9 @@ QuicPacketCreator::QuicPacketCreator(QuicConnectionId server_connection_id,
fully_pad_crypto_handshake_packets_(true),
latched_hard_max_packet_length_(0),
max_datagram_frame_size_(0),
- chaos_protection_enabled_(false) {
+ chaos_protection_enabled_(
+ GetQuicFlag(FLAGS_quic_enable_chaos_protection) &&
+ framer->perspective() == Perspective::IS_CLIENT) {
SetMaxPacketLength(kDefaultMaxPacketSize);
if (!framer_->version().UsesTls()) {
// QUIC+TLS negotiates the maximum datagram frame size via the
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 3dc1a4b184b..55385641426 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
@@ -1863,7 +1863,7 @@ TEST_P(QuicPacketCreatorTest, GetGuaranteedLargestMessagePayload) {
if (version.UsesTls()) {
creator_.SetMaxDatagramFrameSize(kMaxAcceptedDatagramFrameSize);
}
- QuicPacketLength expected_largest_payload = 1319;
+ QuicPacketLength expected_largest_payload = 1219;
if (version.HasLongHeaderLengths()) {
expected_largest_payload -= 2;
}
@@ -1914,7 +1914,7 @@ TEST_P(QuicPacketCreatorTest, GetCurrentLargestMessagePayload) {
if (version.UsesTls()) {
creator_.SetMaxDatagramFrameSize(kMaxAcceptedDatagramFrameSize);
}
- QuicPacketLength expected_largest_payload = 1319;
+ QuicPacketLength expected_largest_payload = 1219;
if (version.SendsVariableLengthPacketNumberInLongHeader()) {
expected_largest_payload += 3;
}
@@ -3249,7 +3249,7 @@ TEST_F(QuicPacketCreatorMultiplePacketsTest, PacketTransmissionType) {
// The first ConsumeData will fill the packet without flush.
creator_.SetTransmissionType(LOSS_RETRANSMISSION);
- size_t data_len = 1324;
+ size_t data_len = 1224;
CreateData(data_len);
QuicStreamId stream1_id = QuicUtils::GetFirstBidirectionalStreamId(
framer_.transport_version(), Perspective::IS_CLIENT);
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_path_validator.cc b/chromium/net/third_party/quiche/src/quic/core/quic_path_validator.cc
index bb83e9472f7..658dfefdce9 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_path_validator.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_path_validator.cc
@@ -10,10 +10,12 @@
namespace quic {
-class RetryAlarmDelegate : public QuicAlarm::Delegate {
+class RetryAlarmDelegate : public QuicAlarm::DelegateWithContext {
public:
- explicit RetryAlarmDelegate(QuicPathValidator* path_validator)
- : path_validator_(path_validator) {}
+ explicit RetryAlarmDelegate(QuicPathValidator* path_validator,
+ QuicConnectionContext* context)
+ : QuicAlarm::DelegateWithContext(context),
+ path_validator_(path_validator) {}
RetryAlarmDelegate(const RetryAlarmDelegate&) = delete;
RetryAlarmDelegate& operator=(const RetryAlarmDelegate&) = delete;
@@ -32,12 +34,12 @@ std::ostream& operator<<(std::ostream& os,
QuicPathValidator::QuicPathValidator(QuicAlarmFactory* alarm_factory,
QuicConnectionArena* arena,
SendDelegate* send_delegate,
- QuicRandom* random)
+ QuicRandom* random,
+ QuicConnectionContext* context)
: send_delegate_(send_delegate),
random_(random),
- retry_timer_(
- alarm_factory->CreateAlarm(arena->New<RetryAlarmDelegate>(this),
- arena)),
+ retry_timer_(alarm_factory->CreateAlarm(
+ arena->New<RetryAlarmDelegate>(this, context), arena)),
retry_count_(0u) {}
void QuicPathValidator::OnPathResponse(const QuicPathFrameBuffer& probing_data,
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_path_validator.h b/chromium/net/third_party/quiche/src/quic/core/quic_path_validator.h
index 9ea1554efa4..9fe2cef9884 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_path_validator.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_path_validator.h
@@ -13,6 +13,7 @@
#include "quic/core/quic_alarm_factory.h"
#include "quic/core/quic_arena_scoped_ptr.h"
#include "quic/core/quic_clock.h"
+#include "quic/core/quic_connection_context.h"
#include "quic/core/quic_one_block_arena.h"
#include "quic/core/quic_packet_writer.h"
#include "quic/core/quic_types.h"
@@ -107,10 +108,9 @@ class QUIC_EXPORT_PRIVATE QuicPathValidator {
std::unique_ptr<QuicPathValidationContext> context) = 0;
};
- QuicPathValidator(QuicAlarmFactory* alarm_factory,
- QuicConnectionArena* arena,
- SendDelegate* delegate,
- QuicRandom* random);
+ QuicPathValidator(QuicAlarmFactory* alarm_factory, QuicConnectionArena* arena,
+ SendDelegate* delegate, QuicRandom* random,
+ QuicConnectionContext* context);
// Send PATH_CHALLENGE and start the retry timer.
void StartPathValidation(std::unique_ptr<QuicPathValidationContext> context,
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_path_validator_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_path_validator_test.cc
index 1dfafc3b77a..28e12593e94 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_path_validator_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_path_validator_test.cc
@@ -48,11 +48,10 @@ class MockSendDelegate : public QuicPathValidator::SendDelegate {
class QuicPathValidatorTest : public QuicTest {
public:
QuicPathValidatorTest()
- : path_validator_(&alarm_factory_, &arena_, &send_delegate_, &random_),
- context_(new MockQuicPathValidationContext(self_address_,
- peer_address_,
- effective_peer_address_,
- &writer_)),
+ : path_validator_(&alarm_factory_, &arena_, &send_delegate_, &random_,
+ /*context=*/nullptr),
+ context_(new MockQuicPathValidationContext(
+ self_address_, peer_address_, effective_peer_address_, &writer_)),
result_delegate_(
new testing::StrictMock<MockQuicPathValidationResultDelegate>()) {
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_protocol_flags_list.h b/chromium/net/third_party/quiche/src/quic/core/quic_protocol_flags_list.h
index 56f83594b8f..3e327139a18 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_protocol_flags_list.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_protocol_flags_list.h
@@ -44,6 +44,26 @@ QUIC_PROTOCOL_FLAG(int64_t,
"Time period for which a given connection_id should live in "
"the time-wait state.")
+// This number is relatively conservative. For example, there are at most 1K
+// queued stateless resets, which consume 1K * 21B = 21KB.
+QUIC_PROTOCOL_FLAG(
+ uint64_t, quic_time_wait_list_max_pending_packets, 1024,
+ "Upper limit of pending packets in time wait list when writer is blocked.")
+
+// Stop sending a reset if the recorded number of addresses that server has
+// recently sent stateless reset to exceeds this limit.
+QUIC_PROTOCOL_FLAG(uint64_t, quic_max_recent_stateless_reset_addresses, 1024,
+ "Max number of recorded recent reset addresses.")
+
+// After this timeout, recent reset addresses will be cleared.
+// FLAGS_quic_max_recent_stateless_reset_addresses * (1000ms /
+// FLAGS_quic_recent_stateless_reset_addresses_lifetime_ms) is roughly the max
+// reset per second. For example, 1024 * (1000ms / 1000ms) = 1K reset per
+// second.
+QUIC_PROTOCOL_FLAG(
+ uint64_t, quic_recent_stateless_reset_addresses_lifetime_ms, 1000,
+ "Max time that a client address lives in recent reset addresses set.")
+
QUIC_PROTOCOL_FLAG(double,
quic_bbr_cwnd_gain,
2.0f,
@@ -77,6 +97,11 @@ QUIC_PROTOCOL_FLAG(
"Congestion window fraction that the pacing sender allows in bursts "
"during pacing.")
+QUIC_PROTOCOL_FLAG(
+ int32_t, quic_lumpy_pacing_min_bandwidth_kbps, 1200,
+ "The minimum estimated client bandwidth below which the pacing sender will "
+ "not allow bursts.")
+
QUIC_PROTOCOL_FLAG(int32_t,
quic_max_pace_time_into_future_ms,
10,
@@ -103,6 +128,10 @@ QUIC_PROTOCOL_FLAG(bool,
true,
"If true, use random greased settings and frames.")
+QUIC_PROTOCOL_FLAG(
+ bool, quic_enable_chaos_protection, true,
+ "If true, use chaos protection to randomize client initials.")
+
QUIC_PROTOCOL_FLAG(int64_t,
quic_max_tracked_packet_count,
10000,
@@ -256,4 +285,6 @@ QUIC_PROTOCOL_FLAG(
false,
"If true, always reject retry_token received in INITIAL packets")
+QUIC_PROTOCOL_FLAG(bool, quic_use_lower_server_response_mtu_for_test, false,
+ "If true, cap server response packet size at 1250.")
#endif
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_received_packet_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_received_packet_manager_test.cc
index da586c67a3d..9d6b6644421 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_received_packet_manager_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_received_packet_manager_test.cc
@@ -434,7 +434,6 @@ TEST_F(QuicReceivedPacketManagerTest,
EXPECT_FALSE(HasPendingAck());
QuicConfig config;
QuicTagVector connection_options;
- connection_options.push_back(kACKD);
// No limit on the number of packets received before sending an ack.
connection_options.push_back(kAKDU);
config.SetConnectionOptionsToSend(connection_options);
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 fd1190bde7b..d9d384f381f 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
@@ -257,18 +257,22 @@ void QuicSentPacketManager::SetFromConfig(const QuicConfig& config) {
// Initial window.
if (GetQuicReloadableFlag(quic_unified_iw_options)) {
if (config.HasClientRequestedIndependentOption(kIW03, perspective)) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_unified_iw_options, 1, 4);
initial_congestion_window_ = 3;
send_algorithm_->SetInitialCongestionWindowInPackets(3);
}
if (config.HasClientRequestedIndependentOption(kIW10, perspective)) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_unified_iw_options, 2, 4);
initial_congestion_window_ = 10;
send_algorithm_->SetInitialCongestionWindowInPackets(10);
}
if (config.HasClientRequestedIndependentOption(kIW20, perspective)) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_unified_iw_options, 3, 4);
initial_congestion_window_ = 20;
send_algorithm_->SetInitialCongestionWindowInPackets(20);
}
if (config.HasClientRequestedIndependentOption(kIW50, perspective)) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_unified_iw_options, 4, 4);
initial_congestion_window_ = 50;
send_algorithm_->SetInitialCongestionWindowInPackets(50);
}
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 aef3fc255a8..e2677377846 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
@@ -12,6 +12,7 @@
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "quic/core/frames/quic_ack_frequency_frame.h"
+#include "quic/core/frames/quic_window_update_frame.h"
#include "quic/core/quic_connection.h"
#include "quic/core/quic_connection_context.h"
#include "quic/core/quic_error_codes.h"
@@ -41,6 +42,12 @@ class ClosedStreamsCleanUpDelegate : public QuicAlarm::Delegate {
ClosedStreamsCleanUpDelegate& operator=(const ClosedStreamsCleanUpDelegate&) =
delete;
+ QuicConnectionContext* GetConnectionContext() override {
+ return (session_->connection() == nullptr)
+ ? nullptr
+ : session_->connection()->context();
+ }
+
void OnAlarm() override { session_->CleanUpClosedStreams(); }
private:
@@ -53,22 +60,14 @@ class ClosedStreamsCleanUpDelegate : public QuicAlarm::Delegate {
(perspective() == Perspective::IS_SERVER ? "Server: " : "Client: ")
QuicSession::QuicSession(
- QuicConnection* connection,
- Visitor* owner,
- const QuicConfig& config,
+ QuicConnection* connection, Visitor* owner, const QuicConfig& config,
const ParsedQuicVersionVector& supported_versions,
QuicStreamCount num_expected_unidirectional_static_streams)
- : QuicSession(connection,
- owner,
- config,
- supported_versions,
- num_expected_unidirectional_static_streams,
- nullptr) {}
+ : QuicSession(connection, owner, config, supported_versions,
+ num_expected_unidirectional_static_streams, nullptr) {}
QuicSession::QuicSession(
- QuicConnection* connection,
- Visitor* owner,
- const QuicConfig& config,
+ QuicConnection* connection, Visitor* owner, const QuicConfig& config,
const ParsedQuicVersionVector& supported_versions,
QuicStreamCount num_expected_unidirectional_static_streams,
std::unique_ptr<QuicDatagramQueue::Observer> datagram_observer)
@@ -77,14 +76,10 @@ QuicSession::QuicSession(
visitor_(owner),
write_blocked_streams_(connection->transport_version()),
config_(config),
- stream_id_manager_(perspective(),
- connection->transport_version(),
+ stream_id_manager_(perspective(), connection->transport_version(),
kDefaultMaxStreamsPerConnection,
config_.GetMaxBidirectionalStreamsToSend()),
- ietf_streamid_manager_(perspective(),
- connection->version(),
- this,
- 0,
+ ietf_streamid_manager_(perspective(), connection->version(), this, 0,
num_expected_unidirectional_static_streams,
config_.GetMaxBidirectionalStreamsToSend(),
config_.GetMaxUnidirectionalStreamsToSend() +
@@ -94,15 +89,13 @@ QuicSession::QuicSession(
num_static_streams_(0),
num_zombie_streams_(0),
flow_controller_(
- this,
- QuicUtils::GetInvalidStreamId(connection->transport_version()),
+ this, QuicUtils::GetInvalidStreamId(connection->transport_version()),
/*is_connection_flow_controller*/ true,
connection->version().AllowsLowFlowControlLimits()
? 0
: kMinimumFlowControlSendWindow,
config_.GetInitialSessionFlowControlWindowToSend(),
- kSessionReceiveWindowLimit,
- perspective() == Perspective::IS_SERVER,
+ kSessionReceiveWindowLimit, perspective() == Perspective::IS_SERVER,
nullptr),
currently_writing_stream_id_(0),
transport_goaway_sent_(false),
@@ -141,8 +134,8 @@ void QuicSession::Initialize() {
connection_->set_can_receive_ack_frequency_frame();
config_.SetMinAckDelayMs(kDefaultMinAckDelayTimeMs);
}
- if (config_.HasClientRequestedIndependentOption(kBPTE, perspective_)) {
- permutes_tls_extensions_ = true;
+ if (config_.HasClientRequestedIndependentOption(kNBPE, perspective_)) {
+ permutes_tls_extensions_ = false;
}
}
@@ -167,13 +160,13 @@ void QuicSession::Initialize() {
}
QuicSession::~QuicSession() {
- if (GetQuicRestartFlag(quic_alarm_add_permanent_cancel) &&
- closed_streams_clean_up_alarm_ != nullptr) {
+ if (closed_streams_clean_up_alarm_ != nullptr) {
closed_streams_clean_up_alarm_->PermanentCancel();
}
}
-void QuicSession::PendingStreamOnStreamFrame(const QuicStreamFrame& frame) {
+PendingStream* QuicSession::PendingStreamOnStreamFrame(
+ const QuicStreamFrame& frame) {
QUICHE_DCHECK(VersionUsesHttp3(transport_version()));
QuicStreamId stream_id = frame.stream_id;
@@ -184,27 +177,63 @@ void QuicSession::PendingStreamOnStreamFrame(const QuicStreamFrame& frame) {
QuicStreamOffset final_byte_offset = frame.offset + frame.data_length;
OnFinalByteOffsetReceived(stream_id, final_byte_offset);
}
- return;
+ return nullptr;
}
pending->OnStreamFrame(frame);
if (!connection()->connected()) {
- return;
+ return nullptr;
}
+ return pending;
+}
+
+void QuicSession::MaybeProcessPendingStream(PendingStream* pending) {
+ QUICHE_DCHECK(pending != nullptr);
+ QuicStreamId stream_id = pending->id();
+ absl::optional<QuicResetStreamError> stop_sending_error_code =
+ pending->GetStopSendingErrorCode();
QuicStream* stream = ProcessPendingStream(pending);
if (stream != nullptr) {
// The pending stream should now be in the scope of normal streams.
QUICHE_DCHECK(IsClosedStream(stream_id) || IsOpenStream(stream_id))
<< "Stream " << stream_id << " not created";
pending_stream_map_.erase(stream_id);
+ if (stop_sending_error_code) {
+ stream->OnStopSending(*stop_sending_error_code);
+ if (!connection()->connected()) {
+ return;
+ }
+ }
stream->OnStreamCreatedFromPendingStream();
return;
}
+ // At this point, none of the bytes has been successfully consumed by the
+ // application layer. We should close the pending stream even if it is
+ // bidirectionl as no application will be able to write in a bidirectional
+ // stream with zero byte as input.
if (pending->sequencer()->IsClosed()) {
ClosePendingStream(stream_id);
}
}
+void QuicSession::PendingStreamOnWindowUpdateFrame(
+ const QuicWindowUpdateFrame& frame) {
+ QUICHE_DCHECK(VersionUsesHttp3(transport_version()));
+ PendingStream* pending = GetOrCreatePendingStream(frame.stream_id);
+ if (pending) {
+ pending->OnWindowUpdateFrame(frame);
+ }
+}
+
+void QuicSession::PendingStreamOnStopSendingFrame(
+ const QuicStopSendingFrame& frame) {
+ QUICHE_DCHECK(VersionUsesHttp3(transport_version()));
+ PendingStream* pending = GetOrCreatePendingStream(frame.stream_id);
+ if (pending) {
+ pending->OnStopSending(frame.error());
+ }
+}
+
void QuicSession::OnStreamFrame(const QuicStreamFrame& frame) {
QuicStreamId stream_id = frame.stream_id;
if (stream_id == QuicUtils::GetInvalidStreamId(transport_version())) {
@@ -214,12 +243,11 @@ void QuicSession::OnStreamFrame(const QuicStreamFrame& frame) {
return;
}
- if (UsesPendingStreams() &&
- QuicUtils::GetStreamType(stream_id, perspective(),
- IsIncomingStream(stream_id),
- version()) == READ_UNIDIRECTIONAL &&
- stream_map_.find(stream_id) == stream_map_.end()) {
- PendingStreamOnStreamFrame(frame);
+ if (ShouldProcessFrameByPendingStream(STREAM_FRAME, stream_id)) {
+ PendingStream* pending = PendingStreamOnStreamFrame(frame);
+ if (pending != nullptr && ShouldProcessPendingStreamImmediately()) {
+ MaybeProcessPendingStream(pending);
+ }
return;
}
@@ -278,6 +306,10 @@ void QuicSession::OnStopSendingFrame(const QuicStopSendingFrame& frame) {
if (visitor_) {
visitor_->OnStopSendingReceived(frame);
}
+ if (ShouldProcessFrameByPendingStream(STOP_SENDING_FRAME, stream_id)) {
+ PendingStreamOnStopSendingFrame(frame);
+ return;
+ }
QuicStream* stream = GetOrCreateStream(stream_id);
if (!stream) {
@@ -285,7 +317,7 @@ void QuicSession::OnStopSendingFrame(const QuicStopSendingFrame& frame) {
return;
}
- stream->OnStopSending(frame.error_code);
+ stream->OnStopSending(frame.error());
}
void QuicSession::OnPacketDecrypted(EncryptionLevel level) {
@@ -325,11 +357,10 @@ void QuicSession::PendingStreamOnRstStream(const QuicRstStreamFrame& frame) {
}
pending->OnRstStreamFrame(frame);
- // Pending stream is currently read only. We can safely close the stream.
- QUICHE_DCHECK_EQ(
- READ_UNIDIRECTIONAL,
- QuicUtils::GetStreamType(pending->id(), perspective(),
- /*peer_initiated = */ true, version()));
+ // At this point, none of the bytes has been consumed by the application
+ // layer. It is safe to close the pending stream even if it is bidirectionl as
+ // no application will be able to write in a bidirectional stream with zero
+ // byte as input.
ClosePendingStream(stream_id);
}
@@ -356,11 +387,7 @@ void QuicSession::OnRstStream(const QuicRstStreamFrame& frame) {
visitor_->OnRstStreamReceived(frame);
}
- if (UsesPendingStreams() &&
- QuicUtils::GetStreamType(stream_id, perspective(),
- IsIncomingStream(stream_id),
- version()) == READ_UNIDIRECTIONAL &&
- stream_map_.find(stream_id) == stream_map_.end()) {
+ if (ShouldProcessFrameByPendingStream(RST_STREAM_FRAME, stream_id)) {
PendingStreamOnRstStream(frame);
return;
}
@@ -444,7 +471,7 @@ void QuicSession::OnConnectionClosed(const QuicConnectionCloseFrame& frame,
closed_streams_clean_up_alarm_->Cancel();
if (visitor_) {
- visitor_->OnConnectionClosed(connection_->connection_id(),
+ visitor_->OnConnectionClosed(connection_->GetOneActiveServerConnectionId(),
frame.quic_error_code, frame.error_details,
source);
}
@@ -483,9 +510,7 @@ void QuicSession::OnPathDegrading() {}
void QuicSession::OnForwardProgressMadeAfterPathDegrading() {}
-bool QuicSession::AllowSelfAddressChange() const {
- return false;
-}
+bool QuicSession::AllowSelfAddressChange() const { return false; }
void QuicSession::OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) {
// Stream may be closed by the time we receive a WINDOW_UPDATE, so we can't
@@ -513,6 +538,11 @@ void QuicSession::OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) {
return;
}
+ if (ShouldProcessFrameByPendingStream(WINDOW_UPDATE_FRAME, stream_id)) {
+ PendingStreamOnWindowUpdateFrame(frame);
+ return;
+ }
+
QuicStream* stream = GetOrCreateStream(stream_id);
if (stream != nullptr) {
stream->OnWindowUpdateFrame(frame);
@@ -808,8 +838,7 @@ QuicConsumedData QuicSession::WritevData(QuicStreamId id, size_t write_length,
return data;
}
-size_t QuicSession::SendCryptoData(EncryptionLevel level,
- size_t write_length,
+size_t QuicSession::SendCryptoData(EncryptionLevel level, size_t write_length,
QuicStreamOffset offset,
TransmissionType type) {
QUICHE_DCHECK(QuicVersionUsesCryptoFrames(transport_version()));
@@ -866,12 +895,12 @@ void QuicSession::ResetStream(QuicStreamId id, QuicRstStreamErrorCode error) {
}
QuicConnection::ScopedPacketFlusher flusher(connection());
- MaybeSendStopSendingFrame(id, error);
- MaybeSendRstStreamFrame(id, error, 0);
+ MaybeSendStopSendingFrame(id, QuicResetStreamError::FromInternal(error));
+ MaybeSendRstStreamFrame(id, QuicResetStreamError::FromInternal(error), 0);
}
void QuicSession::MaybeSendRstStreamFrame(QuicStreamId id,
- QuicRstStreamErrorCode error,
+ QuicResetStreamError error,
QuicStreamOffset bytes_written) {
if (!connection()->connected()) {
return;
@@ -882,11 +911,11 @@ void QuicSession::MaybeSendRstStreamFrame(QuicStreamId id,
control_frame_manager_.WriteOrBufferRstStream(id, error, bytes_written);
}
- connection_->OnStreamReset(id, error);
+ connection_->OnStreamReset(id, error.internal_code());
}
void QuicSession::MaybeSendStopSendingFrame(QuicStreamId id,
- QuicRstStreamErrorCode error) {
+ QuicResetStreamError error) {
if (!connection()->connected()) {
return;
}
@@ -956,8 +985,7 @@ void QuicSession::SendMaxStreams(QuicStreamCount stream_count,
}
void QuicSession::InsertLocallyClosedStreamsHighestOffset(
- const QuicStreamId id,
- QuicStreamOffset offset) {
+ const QuicStreamId id, QuicStreamOffset offset) {
locally_closed_streams_highest_offset_[id] = offset;
}
@@ -1045,9 +1073,14 @@ void QuicSession::ClosePendingStream(QuicStreamId stream_id) {
}
}
+bool QuicSession::ShouldProcessFrameByPendingStream(QuicFrameType type,
+ QuicStreamId id) const {
+ return UsesPendingStreamForFrame(type, id) &&
+ stream_map_.find(id) == stream_map_.end();
+}
+
void QuicSession::OnFinalByteOffsetReceived(
- QuicStreamId stream_id,
- QuicStreamOffset final_byte_offset) {
+ QuicStreamId stream_id, QuicStreamOffset final_byte_offset) {
auto it = locally_closed_streams_highest_offset_.find(stream_id);
if (it == locally_closed_streams_highest_offset_.end()) {
return;
@@ -1308,8 +1341,7 @@ void QuicSession::OnConfigNegotiated() {
}
absl::optional<std::string> QuicSession::OnAlpsData(
- const uint8_t* /*alps_data*/,
- size_t /*alps_length*/) {
+ const uint8_t* /*alps_data*/, size_t /*alps_length*/) {
return absl::nullopt;
}
@@ -1537,10 +1569,8 @@ void QuicSession::OnNewSessionFlowControlWindow(QuicStreamOffset new_window) {
}
bool QuicSession::OnNewDecryptionKeyAvailable(
- EncryptionLevel level,
- std::unique_ptr<QuicDecrypter> decrypter,
- bool set_alternative_decrypter,
- bool latch_once_used) {
+ EncryptionLevel level, std::unique_ptr<QuicDecrypter> decrypter,
+ bool set_alternative_decrypter, bool latch_once_used) {
if (connection_->version().handshake_protocol == PROTOCOL_TLS1_3 &&
!connection()->framer().HasEncrypterOfEncryptionLevel(
QuicUtils::GetEncryptionLevel(
@@ -1563,8 +1593,7 @@ bool QuicSession::OnNewDecryptionKeyAvailable(
}
void QuicSession::OnNewEncryptionKeyAvailable(
- EncryptionLevel level,
- std::unique_ptr<QuicEncrypter> encrypter) {
+ EncryptionLevel level, std::unique_ptr<QuicEncrypter> encrypter) {
connection()->SetEncrypter(level, std::move(encrypter));
if (connection_->version().handshake_protocol != PROTOCOL_TLS1_3) {
return;
@@ -1731,8 +1760,7 @@ bool QuicSession::FillTransportParameters(TransportParameters* params) {
}
QuicErrorCode QuicSession::ProcessTransportParameters(
- const TransportParameters& params,
- bool is_resumption,
+ const TransportParameters& params, bool is_resumption,
std::string* error_details) {
return config_.ProcessTransportParameters(params, is_resumption,
error_details);
@@ -1760,8 +1788,7 @@ void QuicSession::OnCryptoHandshakeMessageReceived(
const CryptoHandshakeMessage& /*message*/) {}
void QuicSession::RegisterStreamPriority(
- QuicStreamId id,
- bool is_static,
+ QuicStreamId id, bool is_static,
const spdy::SpdyStreamPrecedence& precedence) {
write_blocked_streams()->RegisterStream(id, is_static, precedence);
}
@@ -1771,14 +1798,11 @@ void QuicSession::UnregisterStreamPriority(QuicStreamId id, bool is_static) {
}
void QuicSession::UpdateStreamPriority(
- QuicStreamId id,
- const spdy::SpdyStreamPrecedence& new_precedence) {
+ QuicStreamId id, const spdy::SpdyStreamPrecedence& new_precedence) {
write_blocked_streams()->UpdateStreamPriority(id, new_precedence);
}
-QuicConfig* QuicSession::config() {
- return &config_;
-}
+QuicConfig* QuicSession::config() { return &config_; }
void QuicSession::ActivateStream(std::unique_ptr<QuicStream> stream) {
QuicStreamId stream_id = stream->id();
@@ -1989,8 +2013,7 @@ void QuicSession::DeleteConnection() {
}
bool QuicSession::MaybeSetStreamPriority(
- QuicStreamId stream_id,
- const spdy::SpdyStreamPrecedence& precedence) {
+ QuicStreamId stream_id, const spdy::SpdyStreamPrecedence& precedence) {
auto active_stream = stream_map_.find(stream_id);
if (active_stream != stream_map_.end()) {
active_stream->second->SetPriority(precedence);
@@ -2089,13 +2112,17 @@ void QuicSession::SendRetireConnectionId(uint64_t sequence_number) {
void QuicSession::OnServerConnectionIdIssued(
const QuicConnectionId& server_connection_id) {
- visitor_->OnNewConnectionIdSent(connection_->connection_id(),
- server_connection_id);
+ if (visitor_) {
+ visitor_->OnNewConnectionIdSent(
+ connection_->GetOneActiveServerConnectionId(), server_connection_id);
+ }
}
void QuicSession::OnServerConnectionIdRetired(
const QuicConnectionId& server_connection_id) {
- visitor_->OnConnectionIdRetired(server_connection_id);
+ if (visitor_) {
+ visitor_->OnConnectionIdRetired(server_connection_id);
+ }
}
bool QuicSession::IsConnectionFlowControlBlocked() const {
@@ -2468,9 +2495,7 @@ void QuicSession::OnMessageLost(QuicMessageId message_id) {
<< " is considered lost";
}
-void QuicSession::CleanUpClosedStreams() {
- closed_streams_.clear();
-}
+void QuicSession::CleanUpClosedStreams() { closed_streams_.clear(); }
QuicPacketLength QuicSession::GetCurrentLargestMessagePayload() const {
return connection_->GetCurrentLargestMessagePayload();
@@ -2579,6 +2604,21 @@ EncryptionLevel QuicSession::GetEncryptionLevelToSendApplicationData() const {
return connection_->framer().GetEncryptionLevelToSendApplicationData();
}
+void QuicSession::ProcessAllPendingStreams() {
+ std::vector<PendingStream*> pending_streams;
+ pending_streams.reserve(pending_stream_map_.size());
+ for (auto it = pending_stream_map_.cbegin(); it != pending_stream_map_.cend();
+ ++it) {
+ pending_streams.push_back(it->second.get());
+ }
+ for (auto* pending_stream : pending_streams) {
+ MaybeProcessPendingStream(pending_stream);
+ if (!connection()->connected()) {
+ return;
+ }
+ }
+}
+
void QuicSession::ValidatePath(
std::unique_ptr<QuicPathValidationContext> context,
std::unique_ptr<QuicPathValidator::ResultDelegate> result_delegate) {
@@ -2591,8 +2631,7 @@ bool QuicSession::HasPendingPathValidation() const {
bool QuicSession::MigratePath(const QuicSocketAddress& self_address,
const QuicSocketAddress& peer_address,
- QuicPacketWriter* writer,
- bool owns_writer) {
+ QuicPacketWriter* writer, bool owns_writer) {
return connection_->MigratePath(self_address, peer_address, writer,
owns_writer);
}
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 9eb7bd1614f..8789526e6d4 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
@@ -20,6 +20,8 @@
#include "absl/types/span.h"
#include "quic/core/crypto/tls_connection.h"
#include "quic/core/frames/quic_ack_frequency_frame.h"
+#include "quic/core/frames/quic_stop_sending_frame.h"
+#include "quic/core/frames/quic_window_update_frame.h"
#include "quic/core/handshaker_delegate_interface.h"
#include "quic/core/legacy_quic_stream_id_manager.h"
#include "quic/core/quic_connection.h"
@@ -97,13 +99,11 @@ class QUIC_EXPORT_PRIVATE QuicSession
};
// Does not take ownership of |connection| or |visitor|.
- QuicSession(QuicConnection* connection,
- Visitor* owner,
+ QuicSession(QuicConnection* connection, Visitor* owner,
const QuicConfig& config,
const ParsedQuicVersionVector& supported_versions,
QuicStreamCount num_expected_unidirectional_static_streams);
- QuicSession(QuicConnection* connection,
- Visitor* owner,
+ QuicSession(QuicConnection* connection, Visitor* owner,
const QuicConfig& config,
const ParsedQuicVersionVector& supported_versions,
QuicStreamCount num_expected_unidirectional_static_streams,
@@ -183,14 +183,12 @@ class QUIC_EXPORT_PRIVATE QuicSession
QuicStreamOffset offset,
QuicByteCount data_length,
QuicDataWriter* writer) override;
- bool WriteCryptoData(EncryptionLevel level,
- QuicStreamOffset offset,
+ bool WriteCryptoData(EncryptionLevel level, QuicStreamOffset offset,
QuicByteCount data_length,
QuicDataWriter* writer) override;
// SessionNotifierInterface methods:
- bool OnFrameAcked(const QuicFrame& frame,
- QuicTime::Delta ack_delay_time,
+ bool OnFrameAcked(const QuicFrame& frame, QuicTime::Delta ack_delay_time,
QuicTime receive_timestamp) override;
void OnStreamFrameRetransmitted(const QuicStreamFrame& frame) override;
void OnFrameLost(const QuicFrame& frame) override;
@@ -299,8 +297,7 @@ class QUIC_EXPORT_PRIVATE QuicSession
bool set_alternative_decrypter,
bool latch_once_used) override;
void OnNewEncryptionKeyAvailable(
- EncryptionLevel level,
- std::unique_ptr<QuicEncrypter> encrypter) override;
+ EncryptionLevel level, std::unique_ptr<QuicEncrypter> encrypter) override;
void SetDefaultEncryptionLevel(EncryptionLevel level) override;
void OnTlsHandshakeComplete() override;
void DiscardOldDecryptionKey(EncryptionLevel level) override;
@@ -323,8 +320,7 @@ class QUIC_EXPORT_PRIVATE QuicSession
std::string error_details) override;
// Sets priority in the write blocked list.
void RegisterStreamPriority(
- QuicStreamId id,
- bool is_static,
+ QuicStreamId id, bool is_static,
const spdy::SpdyStreamPrecedence& precedence) override;
// Clears priority from the write blocked list.
void UnregisterStreamPriority(QuicStreamId id, bool is_static) override;
@@ -343,8 +339,7 @@ class QUIC_EXPORT_PRIVATE QuicSession
TransmissionType type,
EncryptionLevel level) override;
- size_t SendCryptoData(EncryptionLevel level,
- size_t write_length,
+ size_t SendCryptoData(EncryptionLevel level, size_t write_length,
QuicStreamOffset offset,
TransmissionType type) override;
@@ -466,8 +461,7 @@ class QUIC_EXPORT_PRIVATE QuicSession
// Switch to the path described in |context| without validating the path.
bool MigratePath(const QuicSocketAddress& self_address,
const QuicSocketAddress& peer_address,
- QuicPacketWriter* writer,
- bool owns_writer);
+ QuicPacketWriter* writer, bool owns_writer);
// Returns the largest payload that will fit into a single MESSAGE frame.
// Because overhead can vary during a connection, this method should be
@@ -588,12 +582,12 @@ class QUIC_EXPORT_PRIVATE QuicSession
// Does actual work of sending RESET_STREAM, if the stream type allows.
// Also informs the connection so that pending stream frames can be flushed.
virtual void MaybeSendRstStreamFrame(QuicStreamId id,
- QuicRstStreamErrorCode error,
+ QuicResetStreamError error,
QuicStreamOffset bytes_written);
// Sends a STOP_SENDING frame if the stream type allows.
virtual void MaybeSendStopSendingFrame(QuicStreamId id,
- QuicRstStreamErrorCode error);
+ QuicResetStreamError error);
// Returns the encryption level to send application data.
EncryptionLevel GetEncryptionLevelToSendApplicationData() const;
@@ -623,6 +617,14 @@ class QUIC_EXPORT_PRIVATE QuicSession
virtual QuicSSLConfig GetSSLConfig() const { return QuicSSLConfig(); }
+ // Get latched flag value.
+ bool quic_tls_disable_resumption_refactor() const {
+ return quic_tls_disable_resumption_refactor_;
+ }
+
+ // Try converting all pending streams to normal streams.
+ void ProcessAllPendingStreams();
+
protected:
using StreamMap =
absl::flat_hash_map<QuicStreamId, std::unique_ptr<QuicStream>>;
@@ -675,11 +677,17 @@ class QUIC_EXPORT_PRIVATE QuicSession
virtual void OnFinalByteOffsetReceived(QuicStreamId id,
QuicStreamOffset final_byte_offset);
- // Returns true if incoming unidirectional streams should be buffered until
- // the first byte of the stream arrives.
- // If a subclass returns true here, it should make sure to implement
- // ProcessPendingStream().
- virtual bool UsesPendingStreams() const { return false; }
+ // Returns true if a frame with the given type and id can be prcoessed by a
+ // PendingStream. However, the frame will always be processed by a QuicStream
+ // if one exists with the given stream_id.
+ virtual bool UsesPendingStreamForFrame(QuicFrameType /*type*/,
+ QuicStreamId /*stream_id*/) const {
+ return false;
+ }
+
+ // Returns true if a pending stream should be converted to a real stream after
+ // a corresponding STREAM_FRAME is received.
+ virtual bool ShouldProcessPendingStreamImmediately() const { return true; }
spdy::SpdyPriority GetSpdyPriorityofStream(QuicStreamId stream_id) const {
return write_blocked_streams_.GetSpdyPriorityofStream(stream_id);
@@ -825,6 +833,7 @@ class QUIC_EXPORT_PRIVATE QuicSession
// closed.
QuicStream* GetStream(QuicStreamId id) const;
+ // Can return NULL, e.g., if the stream has been closed before.
PendingStream* GetOrCreatePendingStream(QuicStreamId stream_id);
// Let streams and control frame managers retransmit lost data, returns true
@@ -837,14 +846,30 @@ class QUIC_EXPORT_PRIVATE QuicSession
// Closes the pending stream |stream_id| before it has been created.
void ClosePendingStream(QuicStreamId stream_id);
- // Creates or gets pending stream, feeds it with |frame|, and processes the
- // pending stream.
- void PendingStreamOnStreamFrame(const QuicStreamFrame& frame);
+ // Whether the frame with given type and id should be feed to a pending
+ // stream.
+ bool ShouldProcessFrameByPendingStream(QuicFrameType type,
+ QuicStreamId id) const;
+
+ // Process the pending stream if possible.
+ void MaybeProcessPendingStream(PendingStream* pending);
+
+ // Creates or gets pending stream, feeds it with |frame|, and returns the
+ // pending stream. Can return NULL, e.g., if the stream ID is invalid.
+ PendingStream* PendingStreamOnStreamFrame(const QuicStreamFrame& frame);
// Creates or gets pending strea, feed it with |frame|, and closes the pending
// stream.
void PendingStreamOnRstStream(const QuicRstStreamFrame& frame);
+ // Creates or gets pending stream, feeds it with |frame|, and records the
+ // max_data in the pending stream.
+ void PendingStreamOnWindowUpdateFrame(const QuicWindowUpdateFrame& frame);
+
+ // Creates or gets pending stream, feeds it with |frame|, and records the
+ // ietf_error_code in the pending stream.
+ void PendingStreamOnStopSendingFrame(const QuicStopSendingFrame& frame);
+
// Keep track of highest received byte offset of locally closed streams, while
// waiting for a definitive final highest offset from the peer.
absl::flat_hash_map<QuicStreamId, QuicStreamOffset>
@@ -953,7 +978,10 @@ class QUIC_EXPORT_PRIVATE QuicSession
bool liveness_testing_in_progress_;
// Whether BoringSSL randomizes the order of TLS extensions.
- bool permutes_tls_extensions_ = false;
+ bool permutes_tls_extensions_ = true;
+
+ const bool quic_tls_disable_resumption_refactor_ =
+ GetQuicReloadableFlag(quic_tls_disable_resumption_refactor);
};
} // 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 84b9e2edc7a..b2f62749fce 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
@@ -23,13 +23,13 @@
#include "quic/core/quic_data_writer.h"
#include "quic/core/quic_packets.h"
#include "quic/core/quic_stream.h"
+#include "quic/core/quic_types.h"
#include "quic/core/quic_utils.h"
#include "quic/core/quic_versions.h"
#include "quic/platform/api/quic_expect_bug.h"
#include "quic/platform/api/quic_flags.h"
#include "quic/platform/api/quic_mem_slice_storage.h"
#include "quic/platform/api/quic_test.h"
-#include "quic/platform/api/quic_test_mem_slice_vector.h"
#include "quic/test_tools/mock_quic_session_visitor.h"
#include "quic/test_tools/quic_config_peer.h"
#include "quic/test_tools/quic_connection_peer.h"
@@ -168,6 +168,15 @@ class TestCryptoStream : public QuicCryptoStream, public QuicCryptoHandshaker {
void OnConnectionClosed(QuicErrorCode /*error*/,
ConnectionCloseSource /*source*/) override {}
+ bool ExportKeyingMaterial(absl::string_view /*label*/,
+ absl::string_view /*context*/,
+ size_t /*result_len*/,
+ std::string* /*result*/) override {
+ return false;
+ }
+
+ SSL* GetSsl() const override { return nullptr; }
+
private:
using QuicCryptoStream::session;
@@ -187,8 +196,8 @@ class TestStream : public QuicStream {
StreamType type)
: QuicStream(id, session, is_static, type) {}
- TestStream(PendingStream* pending, QuicSession* session, StreamType type)
- : QuicStream(pending, session, type, /*is_static=*/false) {}
+ TestStream(PendingStream* pending, QuicSession* session)
+ : QuicStream(pending, session, /*is_static=*/false) {}
using QuicStream::CloseWriteSide;
using QuicStream::WriteMemSlices;
@@ -279,11 +288,7 @@ class TestSession : public QuicSession {
}
TestStream* CreateIncomingStream(PendingStream* pending) override {
- QuicStreamId id = pending->id();
- TestStream* stream = new TestStream(
- pending, this,
- DetermineStreamType(id, connection()->version(), perspective(),
- /*is_incoming=*/true, BIDIRECTIONAL));
+ TestStream* stream = new TestStream(pending, this);
ActivateStream(absl::WrapUnique(stream));
++num_incoming_streams_created_;
return stream;
@@ -293,6 +298,9 @@ class TestSession : public QuicSession {
// test that the session handles pending streams correctly in terms of
// receiving stream frames.
QuicStream* ProcessPendingStream(PendingStream* pending) override {
+ if (pending->is_bidirectional()) {
+ return CreateIncomingStream(pending);
+ }
struct iovec iov;
if (pending->sequencer()->GetReadableRegion(&iov)) {
// Create TestStream once the first byte is received.
@@ -368,12 +376,45 @@ class TestSession : public QuicSession {
GetEncryptionLevelToSendApplicationData());
}
- bool UsesPendingStreams() const override { return uses_pending_streams_; }
+ bool UsesPendingStreamForFrame(QuicFrameType type,
+ QuicStreamId stream_id) const override {
+ if (!uses_pending_streams_) {
+ return false;
+ }
+ // Uses pending stream for STREAM/RST_STREAM frames with unidirectional read
+ // stream and uses pending stream for
+ // STREAM/RST_STREAM/STOP_SENDING/WINDOW_UPDATE frames with bidirectional
+ // stream.
+ bool is_incoming_stream = IsIncomingStream(stream_id);
+ StreamType stream_type = QuicUtils::GetStreamType(
+ stream_id, perspective(), is_incoming_stream, version());
+ switch (type) {
+ case STREAM_FRAME:
+ ABSL_FALLTHROUGH_INTENDED;
+ case RST_STREAM_FRAME:
+ return is_incoming_stream;
+ case STOP_SENDING_FRAME:
+ ABSL_FALLTHROUGH_INTENDED;
+ case WINDOW_UPDATE_FRAME:
+ return stream_type == BIDIRECTIONAL;
+ default:
+ return false;
+ }
+ }
+
+ bool ShouldProcessPendingStreamImmediately() const override {
+ return process_pending_stream_immediately_;
+ }
void set_uses_pending_streams(bool uses_pending_streams) {
uses_pending_streams_ = uses_pending_streams;
}
+ void set_process_pending_stream_immediately(
+ bool process_pending_stream_immediately) {
+ process_pending_stream_immediately_ = process_pending_stream_immediately;
+ }
+
int num_incoming_streams_created() const {
return num_incoming_streams_created_;
}
@@ -390,6 +431,7 @@ class TestSession : public QuicSession {
bool writev_consumes_all_data_;
bool uses_pending_streams_;
+ bool process_pending_stream_immediately_ = true;
QuicFrame save_frame_;
int num_incoming_streams_created_;
};
@@ -1784,6 +1826,7 @@ TEST_P(QuicSessionTestServer, PendingStreams) {
return;
}
session_.set_uses_pending_streams(true);
+ session_.set_process_pending_stream_immediately(true);
QuicStreamId stream_id = QuicUtils::GetFirstUnidirectionalStreamId(
transport_version(), Perspective::IS_CLIENT);
@@ -1798,11 +1841,50 @@ TEST_P(QuicSessionTestServer, PendingStreams) {
EXPECT_EQ(1, session_.num_incoming_streams_created());
}
+TEST_P(QuicSessionTestServer, BufferAllIncomingStreams) {
+ if (!VersionUsesHttp3(transport_version())) {
+ return;
+ }
+ session_.set_uses_pending_streams(true);
+ session_.set_process_pending_stream_immediately(false);
+
+ QuicStreamId stream_id = QuicUtils::GetFirstUnidirectionalStreamId(
+ transport_version(), Perspective::IS_CLIENT);
+ QuicStreamFrame data1(stream_id, true, 10, absl::string_view("HT"));
+ session_.OnStreamFrame(data1);
+ EXPECT_TRUE(QuicSessionPeer::GetPendingStream(&session_, stream_id));
+ EXPECT_EQ(0, session_.num_incoming_streams_created());
+ // Read unidirectional stream is still buffered when the first byte arrives.
+ QuicStreamFrame data2(stream_id, false, 0, absl::string_view("HT"));
+ session_.OnStreamFrame(data2);
+ EXPECT_TRUE(QuicSessionPeer::GetPendingStream(&session_, stream_id));
+ EXPECT_EQ(0, session_.num_incoming_streams_created());
+
+ // Bidirectional stream is buffered.
+ QuicStreamId bidirectional_stream_id =
+ QuicUtils::GetFirstBidirectionalStreamId(transport_version(),
+ Perspective::IS_CLIENT);
+ QuicStreamFrame data3(bidirectional_stream_id, false, 0,
+ absl::string_view("HT"));
+ session_.OnStreamFrame(data3);
+ EXPECT_TRUE(
+ QuicSessionPeer::GetPendingStream(&session_, bidirectional_stream_id));
+ EXPECT_EQ(0, session_.num_incoming_streams_created());
+
+ session_.ProcessAllPendingStreams();
+ // Both bidirectional and read-unidirectional streams are unbuffered.
+ EXPECT_FALSE(QuicSessionPeer::GetPendingStream(&session_, stream_id));
+ EXPECT_FALSE(
+ QuicSessionPeer::GetPendingStream(&session_, bidirectional_stream_id));
+ EXPECT_EQ(2, session_.num_incoming_streams_created());
+}
+
TEST_P(QuicSessionTestServer, RstPendingStreams) {
if (!VersionUsesHttp3(transport_version())) {
return;
}
session_.set_uses_pending_streams(true);
+ session_.set_process_pending_stream_immediately(false);
QuicStreamId stream_id = QuicUtils::GetFirstUnidirectionalStreamId(
transport_version(), Perspective::IS_CLIENT);
@@ -1824,6 +1906,27 @@ TEST_P(QuicSessionTestServer, RstPendingStreams) {
EXPECT_FALSE(QuicSessionPeer::GetPendingStream(&session_, stream_id));
EXPECT_EQ(0, session_.num_incoming_streams_created());
EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(&session_));
+
+ session_.ProcessAllPendingStreams();
+ // Bidirectional stream is buffered.
+ QuicStreamId bidirectional_stream_id =
+ QuicUtils::GetFirstBidirectionalStreamId(transport_version(),
+ Perspective::IS_CLIENT);
+ QuicStreamFrame data3(bidirectional_stream_id, false, 0,
+ absl::string_view("HT"));
+ session_.OnStreamFrame(data3);
+ EXPECT_TRUE(
+ QuicSessionPeer::GetPendingStream(&session_, bidirectional_stream_id));
+ EXPECT_EQ(0, session_.num_incoming_streams_created());
+
+ // Bidirectional pending stream is removed after RST_STREAM is received.
+ QuicRstStreamFrame rst2(kInvalidControlFrameId, bidirectional_stream_id,
+ QUIC_ERROR_PROCESSING_STREAM, 12);
+ session_.OnRstStream(rst2);
+ EXPECT_FALSE(
+ QuicSessionPeer::GetPendingStream(&session_, bidirectional_stream_id));
+ EXPECT_EQ(0, session_.num_incoming_streams_created());
+ EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(&session_));
}
TEST_P(QuicSessionTestServer, OnFinPendingStreams) {
@@ -1831,6 +1934,7 @@ TEST_P(QuicSessionTestServer, OnFinPendingStreams) {
return;
}
session_.set_uses_pending_streams(true);
+ session_.set_process_pending_stream_immediately(true);
QuicStreamId stream_id = QuicUtils::GetFirstUnidirectionalStreamId(
transport_version(), Perspective::IS_CLIENT);
@@ -1840,9 +1944,30 @@ TEST_P(QuicSessionTestServer, OnFinPendingStreams) {
EXPECT_FALSE(QuicSessionPeer::GetPendingStream(&session_, stream_id));
EXPECT_EQ(0, session_.num_incoming_streams_created());
EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(&session_));
+
+ session_.set_process_pending_stream_immediately(false);
+ // Bidirectional pending stream remains after Fin is received.
+ // Bidirectional stream is buffered.
+ QuicStreamId bidirectional_stream_id =
+ QuicUtils::GetFirstBidirectionalStreamId(transport_version(),
+ Perspective::IS_CLIENT);
+ QuicStreamFrame data2(bidirectional_stream_id, true, 0,
+ absl::string_view("HT"));
+ session_.OnStreamFrame(data2);
+ EXPECT_TRUE(
+ QuicSessionPeer::GetPendingStream(&session_, bidirectional_stream_id));
+ EXPECT_EQ(0, session_.num_incoming_streams_created());
+
+ session_.ProcessAllPendingStreams();
+ EXPECT_FALSE(
+ QuicSessionPeer::GetPendingStream(&session_, bidirectional_stream_id));
+ EXPECT_EQ(1, session_.num_incoming_streams_created());
+ QuicStream* bidirectional_stream =
+ QuicSessionPeer::GetStream(&session_, bidirectional_stream_id);
+ EXPECT_TRUE(bidirectional_stream->fin_received());
}
-TEST_P(QuicSessionTestServer, PendingStreamOnWindowUpdate) {
+TEST_P(QuicSessionTestServer, UnidirectionalPendingStreamOnWindowUpdate) {
if (!VersionUsesHttp3(transport_version())) {
return;
}
@@ -1864,6 +1989,80 @@ TEST_P(QuicSessionTestServer, PendingStreamOnWindowUpdate) {
session_.OnWindowUpdateFrame(window_update_frame);
}
+TEST_P(QuicSessionTestServer, BidirectionalPendingStreamOnWindowUpdate) {
+ if (!VersionUsesHttp3(transport_version())) {
+ return;
+ }
+
+ session_.set_uses_pending_streams(true);
+ session_.set_process_pending_stream_immediately(false);
+ QuicStreamId stream_id = QuicUtils::GetFirstBidirectionalStreamId(
+ transport_version(), Perspective::IS_CLIENT);
+ QuicStreamFrame data(stream_id, true, 10, absl::string_view("HT"));
+ session_.OnStreamFrame(data);
+ QuicWindowUpdateFrame window_update_frame(kInvalidControlFrameId, stream_id,
+ kDefaultFlowControlSendWindow * 2);
+ session_.OnWindowUpdateFrame(window_update_frame);
+ EXPECT_TRUE(QuicSessionPeer::GetPendingStream(&session_, stream_id));
+ EXPECT_EQ(0, session_.num_incoming_streams_created());
+
+ session_.ProcessAllPendingStreams();
+ EXPECT_FALSE(QuicSessionPeer::GetPendingStream(&session_, stream_id));
+ EXPECT_EQ(1, session_.num_incoming_streams_created());
+ QuicStream* bidirectional_stream =
+ QuicSessionPeer::GetStream(&session_, stream_id);
+ QuicByteCount send_window =
+ QuicStreamPeer::SendWindowSize(bidirectional_stream);
+ EXPECT_EQ(send_window, kDefaultFlowControlSendWindow * 2);
+}
+
+TEST_P(QuicSessionTestServer, UnidirectionalPendingStreamOnStopSending) {
+ if (!VersionUsesHttp3(transport_version())) {
+ return;
+ }
+
+ session_.set_uses_pending_streams(true);
+ QuicStreamId stream_id = QuicUtils::GetFirstUnidirectionalStreamId(
+ transport_version(), Perspective::IS_CLIENT);
+ QuicStreamFrame data1(stream_id, true, 10, absl::string_view("HT"));
+ session_.OnStreamFrame(data1);
+ EXPECT_TRUE(QuicSessionPeer::GetPendingStream(&session_, stream_id));
+ EXPECT_EQ(0, session_.num_incoming_streams_created());
+ QuicStopSendingFrame stop_sending_frame(kInvalidControlFrameId, stream_id,
+ QUIC_STREAM_CANCELLED);
+ EXPECT_CALL(
+ *connection_,
+ CloseConnection(QUIC_INVALID_STREAM_ID,
+ "Received STOP_SENDING for a read-only stream", _));
+ session_.OnStopSendingFrame(stop_sending_frame);
+}
+
+TEST_P(QuicSessionTestServer, BidirectionalPendingStreamOnStopSending) {
+ if (!VersionUsesHttp3(transport_version())) {
+ return;
+ }
+
+ session_.set_uses_pending_streams(true);
+ session_.set_process_pending_stream_immediately(false);
+ QuicStreamId stream_id = QuicUtils::GetFirstBidirectionalStreamId(
+ transport_version(), Perspective::IS_CLIENT);
+ QuicStreamFrame data(stream_id, true, 0, absl::string_view("HT"));
+ session_.OnStreamFrame(data);
+ QuicStopSendingFrame stop_sending_frame(kInvalidControlFrameId, stream_id,
+ QUIC_STREAM_CANCELLED);
+ session_.OnStopSendingFrame(stop_sending_frame);
+ EXPECT_TRUE(QuicSessionPeer::GetPendingStream(&session_, stream_id));
+ EXPECT_EQ(0, session_.num_incoming_streams_created());
+
+ EXPECT_CALL(*connection_, OnStreamReset(stream_id, _));
+ session_.ProcessAllPendingStreams();
+ EXPECT_FALSE(QuicSessionPeer::GetPendingStream(&session_, stream_id));
+ EXPECT_EQ(1, session_.num_incoming_streams_created());
+ QuicStream* bidirectional_stream =
+ QuicSessionPeer::GetStream(&session_, stream_id);
+ EXPECT_TRUE(bidirectional_stream->write_side_closed());
+}
+
TEST_P(QuicSessionTestServer, DrainingStreamsDoNotCountAsOpened) {
// Verify that a draining stream (which has received a FIN but not consumed
// it) does not count against the open quota (because it is closed from the
@@ -2571,12 +2770,11 @@ TEST_P(QuicSessionTestServer, WriteMemSlicesOnReadUnidirectionalStream) {
CloseConnection(
QUIC_TRY_TO_WRITE_DATA_ON_READ_UNIDIRECTIONAL_STREAM, _, _))
.Times(1);
- char data[1024];
- std::vector<std::pair<char*, size_t>> buffers;
- buffers.push_back(std::make_pair(data, ABSL_ARRAYSIZE(data)));
- buffers.push_back(std::make_pair(data, ABSL_ARRAYSIZE(data)));
- QuicTestMemSliceVector vector(buffers);
- stream4->WriteMemSlices(vector.span(), false);
+ std::string data(1024, 'a');
+ std::vector<QuicMemSlice> buffers;
+ buffers.push_back(MemSliceFromString(data));
+ buffers.push_back(MemSliceFromString(data));
+ stream4->WriteMemSlices(absl::MakeSpan(buffers), false);
}
// Test code that tests that an incoming stream frame with a new (not previously
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 cde50ef214d..f055bdf2e9f 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
@@ -15,11 +15,13 @@
#include "quic/core/quic_session.h"
#include "quic/core/quic_types.h"
#include "quic/core/quic_utils.h"
+#include "quic/core/quic_versions.h"
#include "quic/platform/api/quic_bug_tracker.h"
#include "quic/platform/api/quic_flag_utils.h"
#include "quic/platform/api/quic_flags.h"
#include "quic/platform/api/quic_logging.h"
#include "quic/platform/api/quic_mem_slice.h"
+#include "common/platform/api/quiche_logging.h"
using spdy::SpdyPriority;
@@ -118,9 +120,12 @@ PendingStream::PendingStream(QuicStreamId id, QuicSession* session)
stream_delegate_(session),
stream_bytes_read_(0),
fin_received_(false),
+ is_bidirectional_(QuicUtils::GetStreamType(id, session->perspective(),
+ /*peer_initiated = */ true,
+ session->version()) ==
+ BIDIRECTIONAL),
connection_flow_controller_(session->flow_controller()),
- flow_controller_(session,
- id,
+ flow_controller_(session, id,
/*is_connection_flow_controller*/ false,
GetReceivedFlowControlWindow(session, id),
GetInitialStreamFlowControlWindowToSend(session, id),
@@ -134,9 +139,7 @@ void PendingStream::OnDataAvailable() {
// QuicSession::ProcessPendingStream() can read it.
}
-void PendingStream::OnFinRead() {
- QUICHE_DCHECK(sequencer_.IsClosed());
-}
+void PendingStream::OnFinRead() { QUICHE_DCHECK(sequencer_.IsClosed()); }
void PendingStream::AddBytesConsumed(QuicByteCount bytes) {
// It will be called when the metadata of the stream is consumed.
@@ -144,7 +147,7 @@ void PendingStream::AddBytesConsumed(QuicByteCount bytes) {
connection_flow_controller_->AddBytesConsumed(bytes);
}
-void PendingStream::Reset(QuicRstStreamErrorCode /*error*/) {
+void PendingStream::ResetWithError(QuicResetStreamError /*error*/) {
// Currently PendingStream is only read-unidirectional. It shouldn't send
// Reset.
QUIC_NOTREACHED();
@@ -161,13 +164,9 @@ void PendingStream::OnUnrecoverableError(QuicErrorCode error,
stream_delegate_->OnStreamError(error, ietf_error, details);
}
-QuicStreamId PendingStream::id() const {
- return id_;
-}
+QuicStreamId PendingStream::id() const { return id_; }
-ParsedQuicVersion PendingStream::version() const {
- return version_;
-}
+ParsedQuicVersion PendingStream::version() const { return version_; }
void PendingStream::OnStreamFrame(const QuicStreamFrame& frame) {
QUICHE_DCHECK_EQ(frame.stream_id, id_);
@@ -252,6 +251,11 @@ void PendingStream::OnRstStreamFrame(const QuicRstStreamFrame& frame) {
}
}
+void PendingStream::OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) {
+ QUICHE_DCHECK(is_bidirectional_);
+ flow_controller_.UpdateSendWindowOffset(frame.max_data);
+}
+
bool PendingStream::MaybeIncreaseHighestReceivedOffset(
QuicStreamOffset new_offset) {
uint64_t increment =
@@ -268,6 +272,13 @@ bool PendingStream::MaybeIncreaseHighestReceivedOffset(
return true;
}
+void PendingStream::OnStopSending(
+ QuicResetStreamError stop_sending_error_code) {
+ if (!stop_sending_error_code_) {
+ stop_sending_error_code_ = stop_sending_error_code;
+ }
+}
+
void PendingStream::MarkConsumed(QuicByteCount num_bytes) {
sequencer_.MarkConsumed(num_bytes);
}
@@ -277,19 +288,17 @@ void PendingStream::StopReading() {
sequencer_.StopReading();
}
-QuicStream::QuicStream(PendingStream* pending,
- QuicSession* session,
- StreamType type,
+QuicStream::QuicStream(PendingStream* pending, QuicSession* session,
bool is_static)
- : QuicStream(pending->id_,
- session,
- std::move(pending->sequencer_),
+ : QuicStream(pending->id_, session, std::move(pending->sequencer_),
is_static,
- type,
- pending->stream_bytes_read_,
- pending->fin_received_,
+ QuicUtils::GetStreamType(pending->id_, session->perspective(),
+ /*peer_initiated = */ true,
+ session->version()),
+ pending->stream_bytes_read_, pending->fin_received_,
std::move(pending->flow_controller_),
pending->connection_flow_controller_) {
+ QUICHE_DCHECK(session->version().HasIetfQuicFrames());
sequencer_.set_stream(this);
}
@@ -317,26 +326,15 @@ absl::optional<QuicFlowController> FlowController(QuicStreamId id,
} // namespace
-QuicStream::QuicStream(QuicStreamId id,
- QuicSession* session,
- bool is_static,
+QuicStream::QuicStream(QuicStreamId id, QuicSession* session, bool is_static,
StreamType type)
- : QuicStream(id,
- session,
- QuicStreamSequencer(this),
- is_static,
- type,
- 0,
- false,
- FlowController(id, session, type),
+ : QuicStream(id, session, QuicStreamSequencer(this), is_static, type, 0,
+ false, FlowController(id, session, type),
session->flow_controller()) {}
-QuicStream::QuicStream(QuicStreamId id,
- QuicSession* session,
- QuicStreamSequencer sequencer,
- bool is_static,
- StreamType type,
- uint64_t stream_bytes_read,
+QuicStream::QuicStream(QuicStreamId id, QuicSession* session,
+ QuicStreamSequencer sequencer, bool is_static,
+ StreamType type, uint64_t stream_bytes_read,
bool fin_received,
absl::optional<QuicFlowController> flow_controller,
QuicFlowController* connection_flow_controller)
@@ -346,10 +344,11 @@ QuicStream::QuicStream(QuicStreamId id,
stream_delegate_(session),
precedence_(CalculateDefaultPriority(session)),
stream_bytes_read_(stream_bytes_read),
- stream_error_(QUIC_STREAM_NO_ERROR),
+ stream_error_(QuicResetStreamError::NoError()),
connection_error_(QUIC_NO_ERROR),
read_side_closed_(false),
write_side_closed_(false),
+ write_side_data_recvd_state_notified_(false),
fin_buffered_(false),
fin_sent_(false),
fin_outstanding_(false),
@@ -371,8 +370,7 @@ QuicStream::QuicStream(QuicStreamId id,
was_draining_(false),
type_(VersionHasIetfQuicFrames(session->transport_version()) &&
type != CRYPTO
- ? QuicUtils::GetStreamType(id_,
- session->perspective(),
+ ? QuicUtils::GetStreamType(id_, session->perspective(),
session->IsIncomingStream(id_),
session->version())
: type),
@@ -489,7 +487,7 @@ void QuicStream::OnStreamFrame(const QuicStreamFrame& frame) {
sequencer_.OnStreamFrame(frame);
}
-bool QuicStream::OnStopSending(QuicRstStreamErrorCode code) {
+bool QuicStream::OnStopSending(QuicResetStreamError error) {
// Do not reset the stream if all data has been sent and acknowledged.
if (write_side_closed() && !IsWaitingForAcks()) {
QUIC_DVLOG(1) << ENDPOINT
@@ -507,8 +505,14 @@ bool QuicStream::OnStopSending(QuicRstStreamErrorCode code) {
return false;
}
- stream_error_ = code;
- MaybeSendRstStream(code);
+ stream_error_ = error;
+ if (GetQuicReloadableFlag(quic_match_ietf_reset_code)) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_match_ietf_reset_code);
+ MaybeSendRstStream(error);
+ } else {
+ MaybeSendRstStream(
+ QuicResetStreamError::FromInternal(error.internal_code()));
+ }
return true;
}
@@ -553,7 +557,7 @@ void QuicStream::OnStreamReset(const QuicRstStreamFrame& frame) {
return;
}
- stream_error_ = frame.error_code;
+ stream_error_ = frame.error();
// Google QUIC closes both sides of the stream in response to a
// RESET_STREAM, IETF QUIC closes only the read side.
if (!VersionHasIetfQuicFrames(transport_version())) {
@@ -568,7 +572,8 @@ void QuicStream::OnConnectionClosed(QuicErrorCode error,
return;
}
if (error != QUIC_NO_ERROR) {
- stream_error_ = QUIC_STREAM_CONNECTION_ERROR;
+ stream_error_ =
+ QuicResetStreamError::FromInternal(QUIC_STREAM_CONNECTION_ERROR);
connection_error_ = error;
}
@@ -593,6 +598,10 @@ void QuicStream::SetFinSent() {
}
void QuicStream::Reset(QuicRstStreamErrorCode error) {
+ ResetWithError(QuicResetStreamError::FromInternal(error));
+}
+
+void QuicStream::ResetWithError(QuicResetStreamError error) {
stream_error_ = error;
QuicConnection::ScopedPacketFlusher flusher(session()->connection());
MaybeSendStopSending(error);
@@ -600,7 +609,24 @@ void QuicStream::Reset(QuicRstStreamErrorCode error) {
if (read_side_closed_ && write_side_closed_ && !IsWaitingForAcks()) {
session()->MaybeCloseZombieStream(id_);
- return;
+ }
+}
+
+void QuicStream::ResetWriteSide(QuicResetStreamError error) {
+ stream_error_ = error;
+ MaybeSendRstStream(error);
+
+ if (read_side_closed_ && write_side_closed_ && !IsWaitingForAcks()) {
+ session()->MaybeCloseZombieStream(id_);
+ }
+}
+
+void QuicStream::SendStopSending(QuicResetStreamError error) {
+ stream_error_ = error;
+ MaybeSendStopSending(error);
+
+ if (read_side_closed_ && write_side_closed_ && !IsWaitingForAcks()) {
+ session()->MaybeCloseZombieStream(id_);
}
}
@@ -628,8 +654,7 @@ void QuicStream::SetPriority(const spdy::SpdyStreamPrecedence& precedence) {
}
void QuicStream::WriteOrBufferData(
- absl::string_view data,
- bool fin,
+ absl::string_view data, bool fin,
QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) {
QUIC_BUG_IF(quic_bug_12570_4,
QuicUtils::IsCryptoStreamId(transport_version(), id_))
@@ -740,17 +765,12 @@ void QuicStream::MaybeSendBlocked() {
}
}
-QuicConsumedData QuicStream::WriteMemSlices(QuicMemSliceSpan span, bool fin) {
- return WriteMemSlicesInner(MemSliceSpanWrapper(span), fin);
+QuicConsumedData QuicStream::WriteMemSlice(QuicMemSlice span, bool fin) {
+ return WriteMemSlices(absl::MakeSpan(&span, 1), fin);
}
QuicConsumedData QuicStream::WriteMemSlices(absl::Span<QuicMemSlice> span,
bool fin) {
- return WriteMemSlicesInner(MemSliceSpanWrapper(span), fin);
-}
-
-QuicConsumedData QuicStream::WriteMemSlicesInner(MemSliceSpanWrapper span,
- bool fin) {
QuicConsumedData consumed_data(0, false);
if (span.empty() && !fin) {
QUIC_BUG(quic_bug_10586_6) << "span.empty() && !fin";
@@ -778,7 +798,7 @@ QuicConsumedData QuicStream::WriteMemSlicesInner(MemSliceSpanWrapper span,
if (!span.empty()) {
// Buffer all data if buffered data size is below limit.
QuicStreamOffset offset = send_buffer_.stream_offset();
- consumed_data.bytes_consumed = span.SaveTo(send_buffer_);
+ consumed_data.bytes_consumed = send_buffer_.SaveMemSliceSpan(span);
if (offset > send_buffer_.stream_offset() ||
kMaxStreamLength < send_buffer_.stream_offset()) {
QUIC_BUG(quic_bug_10586_8) << "Write too many data via stream " << id_;
@@ -841,12 +861,12 @@ void QuicStream::CloseWriteSide() {
}
}
-void QuicStream::MaybeSendStopSending(QuicRstStreamErrorCode error) {
+void QuicStream::MaybeSendStopSending(QuicResetStreamError error) {
if (stop_sending_sent_) {
return;
}
- if (!session()->version().UsesHttp3() && error != QUIC_STREAM_NO_ERROR) {
+ if (!session()->version().UsesHttp3() && !error.ok()) {
// In gQUIC, RST with error closes both read and write side.
return;
}
@@ -854,21 +874,21 @@ void QuicStream::MaybeSendStopSending(QuicRstStreamErrorCode error) {
if (session()->version().UsesHttp3()) {
session()->MaybeSendStopSendingFrame(id(), error);
} else {
- QUICHE_DCHECK_EQ(QUIC_STREAM_NO_ERROR, error);
- session()->MaybeSendRstStreamFrame(id(), QUIC_STREAM_NO_ERROR,
+ QUICHE_DCHECK_EQ(QUIC_STREAM_NO_ERROR, error.internal_code());
+ session()->MaybeSendRstStreamFrame(id(), QuicResetStreamError::NoError(),
stream_bytes_written());
}
stop_sending_sent_ = true;
CloseReadSide();
}
-void QuicStream::MaybeSendRstStream(QuicRstStreamErrorCode error) {
+void QuicStream::MaybeSendRstStream(QuicResetStreamError error) {
if (rst_sent_) {
return;
}
if (!session()->version().UsesHttp3()) {
- QUIC_BUG_IF(quic_bug_12570_5, error == QUIC_STREAM_NO_ERROR);
+ QUIC_BUG_IF(quic_bug_12570_5, error.ok());
stop_sending_sent_ = true;
CloseReadSide();
}
@@ -882,9 +902,7 @@ bool QuicStream::HasBufferedData() const {
return send_buffer_.stream_offset() > stream_bytes_written();
}
-ParsedQuicVersion QuicStream::version() const {
- return session_->version();
-}
+ParsedQuicVersion QuicStream::version() const { return session_->version(); }
QuicTransportVersion QuicStream::transport_version() const {
return session_->transport_version();
@@ -1065,8 +1083,7 @@ void QuicStream::AddRandomPaddingAfterFin() {
}
bool QuicStream::OnStreamFrameAcked(QuicStreamOffset offset,
- QuicByteCount data_length,
- bool fin_acked,
+ QuicByteCount data_length, bool fin_acked,
QuicTime::Delta /*ack_delay_time*/,
QuicTime /*receive_timestamp*/,
QuicByteCount* newly_acked_length) {
@@ -1090,6 +1107,11 @@ bool QuicStream::OnStreamFrameAcked(QuicStreamOffset offset,
fin_outstanding_ = false;
fin_lost_ = false;
}
+ if (!IsWaitingForAcks() && write_side_closed_ &&
+ !write_side_data_recvd_state_notified_) {
+ OnWriteSideInDataRecvdState();
+ write_side_data_recvd_state_notified_ = true;
+ }
if (!IsWaitingForAcks() && read_side_closed_ && write_side_closed_) {
session_->MaybeCloseZombieStream(id_);
}
@@ -1106,8 +1128,7 @@ void QuicStream::OnStreamFrameRetransmitted(QuicStreamOffset offset,
}
void QuicStream::OnStreamFrameLost(QuicStreamOffset offset,
- QuicByteCount data_length,
- bool fin_lost) {
+ QuicByteCount data_length, bool fin_lost) {
QUIC_DVLOG(1) << ENDPOINT << "stream " << id_ << " Losting "
<< "[" << offset << ", " << offset + data_length << "]"
<< " fin = " << fin_lost;
@@ -1120,8 +1141,7 @@ void QuicStream::OnStreamFrameLost(QuicStreamOffset offset,
}
bool QuicStream::RetransmitStreamData(QuicStreamOffset offset,
- QuicByteCount data_length,
- bool fin,
+ QuicByteCount data_length, bool fin,
TransmissionType type) {
QUICHE_DCHECK(type == PTO_RETRANSMISSION || type == RTO_RETRANSMISSION ||
type == TLP_RETRANSMISSION || type == PROBING_RETRANSMISSION);
@@ -1178,7 +1198,7 @@ bool QuicStream::RetransmitStreamData(QuicStreamOffset offset,
}
bool QuicStream::IsWaitingForAcks() const {
- return (!rst_sent_ || stream_error_ == QUIC_STREAM_NO_ERROR) &&
+ return (!rst_sent_ || stream_error_.ok()) &&
(send_buffer_.stream_bytes_outstanding() || fin_outstanding_);
}
@@ -1385,9 +1405,7 @@ bool QuicStream::HasDeadlinePassed() const {
return true;
}
-void QuicStream::OnDeadlinePassed() {
- Reset(QUIC_STREAM_TTL_EXPIRED);
-}
+void QuicStream::OnDeadlinePassed() { Reset(QUIC_STREAM_TTL_EXPIRED); }
bool QuicStream::IsFlowControlBlocked() const {
if (!flow_controller_.has_value()) {
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 6374d8ab6f6..dc129a28ee6 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
@@ -25,6 +25,8 @@
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
#include "absl/types/span.h"
+#include "quic/core/frames/quic_rst_stream_frame.h"
+#include "quic/core/quic_error_codes.h"
#include "quic/core/quic_flow_controller.h"
#include "quic/core/quic_packets.h"
#include "quic/core/quic_stream_send_buffer.h"
@@ -34,7 +36,6 @@
#include "quic/core/stream_delegate_interface.h"
#include "quic/platform/api/quic_export.h"
#include "quic/platform/api/quic_mem_slice.h"
-#include "quic/platform/api/quic_mem_slice_span.h"
#include "quic/platform/api/quic_reference_counted.h"
#include "spdy/core/spdy_protocol.h"
@@ -60,7 +61,7 @@ class QUIC_EXPORT_PRIVATE PendingStream
void OnDataAvailable() override;
void OnFinRead() override;
void AddBytesConsumed(QuicByteCount bytes) override;
- void Reset(QuicRstStreamErrorCode error) override;
+ void ResetWithError(QuicResetStreamError error) override;
void OnUnrecoverableError(QuicErrorCode error,
const std::string& details) override;
void OnUnrecoverableError(QuicErrorCode error,
@@ -73,10 +74,21 @@ class QUIC_EXPORT_PRIVATE PendingStream
// If the data violates flow control, the connection will be closed.
void OnStreamFrame(const QuicStreamFrame& frame);
+ bool is_bidirectional() const { return is_bidirectional_; }
+
// Stores the final byte offset from |frame|.
// If the final offset violates flow control, the connection will be closed.
void OnRstStreamFrame(const QuicRstStreamFrame& frame);
+ void OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame);
+
+ void OnStopSending(QuicResetStreamError stop_sending_error_code);
+
+ // The error code received from QuicStopSendingFrame (if any).
+ const absl::optional<QuicResetStreamError>& GetStopSendingErrorCode() const {
+ return stop_sending_error_code_;
+ }
+
// Returns the number of bytes read on this stream.
uint64_t stream_bytes_read() { return stream_bytes_read_; }
@@ -109,12 +121,17 @@ class QUIC_EXPORT_PRIVATE PendingStream
// True if a frame containing a fin has been received.
bool fin_received_;
+ // True if this pending stream is backing a bidirectional stream.
+ bool is_bidirectional_;
+
// Connection-level flow controller. Owned by the session.
QuicFlowController* connection_flow_controller_;
// Stream-level flow controller.
QuicFlowController flow_controller_;
// Stores the buffered frames.
QuicStreamSequencer sequencer_;
+ // The error code received from QuicStopSendingFrame (if any).
+ absl::optional<QuicResetStreamError> stop_sending_error_code_;
};
class QUIC_EXPORT_PRIVATE QuicStream
@@ -136,14 +153,9 @@ class QUIC_EXPORT_PRIVATE QuicStream
// |type| indicates whether the stream is bidirectional, read unidirectional
// or write unidirectional.
// TODO(fayang): Remove |type| when IETF stream ID numbering fully kicks in.
- QuicStream(QuicStreamId id,
- QuicSession* session,
- bool is_static,
+ QuicStream(QuicStreamId id, QuicSession* session, bool is_static,
StreamType type);
- QuicStream(PendingStream* pending,
- QuicSession* session,
- StreamType type,
- bool is_static);
+ QuicStream(PendingStream* pending, QuicSession* session, bool is_static);
QuicStream(const QuicStream&) = delete;
QuicStream& operator=(const QuicStream&) = delete;
@@ -162,7 +174,16 @@ class QUIC_EXPORT_PRIVATE QuicStream
// Called by the subclass or the sequencer to reset the stream from this
// end.
- void Reset(QuicRstStreamErrorCode error) override;
+ void ResetWithError(QuicResetStreamError error) override;
+ // Convenience wrapper for the method above.
+ // TODO(b/200606367): switch all calls to using QuicResetStreamError
+ // interface.
+ void Reset(QuicRstStreamErrorCode error);
+
+ // Reset() sends both RESET_STREAM and STOP_SENDING; the two methods below
+ // allow to send only one of those.
+ void ResetWriteSide(QuicResetStreamError error);
+ void SendStopSending(QuicResetStreamError error);
// Called by the subclass or the sequencer to close the entire connection from
// this end.
@@ -210,7 +231,9 @@ class QUIC_EXPORT_PRIVATE QuicStream
// Number of bytes available to read.
QuicByteCount ReadableBytes() const;
- QuicRstStreamErrorCode stream_error() const { return stream_error_; }
+ QuicRstStreamErrorCode stream_error() const {
+ return stream_error_.internal_code();
+ }
QuicErrorCode connection_error() const { return connection_error_; }
bool reading_stopped() const {
@@ -292,31 +315,26 @@ class QUIC_EXPORT_PRIVATE QuicStream
// session, write_side_closed() becomes true, otherwise fin_buffered_ becomes
// true.
void WriteOrBufferData(
- absl::string_view data,
- bool fin,
+ absl::string_view data, bool fin,
QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener);
// Sends |data| to connection with specified |level|.
void WriteOrBufferDataAtLevel(
- absl::string_view data,
- bool fin,
- EncryptionLevel level,
+ absl::string_view data, bool fin, EncryptionLevel level,
QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener);
// Adds random padding after the fin is consumed for this stream.
void AddRandomPaddingAfterFin();
// Write |data_length| of data starts at |offset| from send buffer.
- bool WriteStreamData(QuicStreamOffset offset,
- QuicByteCount data_length,
+ bool WriteStreamData(QuicStreamOffset offset, QuicByteCount data_length,
QuicDataWriter* writer);
// Called when data [offset, offset + data_length) is acked. |fin_acked|
// indicates whether the fin is acked. Returns true and updates
// |newly_acked_length| if any new stream data (including fin) gets acked.
virtual bool OnStreamFrameAcked(QuicStreamOffset offset,
- QuicByteCount data_length,
- bool fin_acked,
+ QuicByteCount data_length, bool fin_acked,
QuicTime::Delta ack_delay_time,
QuicTime receive_timestamp,
QuicByteCount* newly_acked_length);
@@ -330,15 +348,13 @@ class QUIC_EXPORT_PRIVATE QuicStream
// Called when data [offset, offset + data_length) is considered as lost.
// |fin_lost| indicates whether the fin is considered as lost.
virtual void OnStreamFrameLost(QuicStreamOffset offset,
- QuicByteCount data_length,
- bool fin_lost);
+ QuicByteCount data_length, bool fin_lost);
// Called to retransmit outstanding portion in data [offset, offset +
// data_length) and |fin| with Transmission |type|.
// Returns true if all data gets retransmitted.
virtual bool RetransmitStreamData(QuicStreamOffset offset,
- QuicByteCount data_length,
- bool fin,
+ QuicByteCount data_length, bool fin,
TransmissionType type);
// Sets deadline of this stream to be now + |ttl|, returns true if the setting
@@ -349,9 +365,8 @@ class QUIC_EXPORT_PRIVATE QuicStream
// the wire. This method has all-or-nothing semantics: if the write buffer is
// not full, all of the memslices in |span| are moved into it; otherwise,
// nothing happens.
- // TODO(vasilvv): deprecate and remove QuicMemSliceSpan version.
- QuicConsumedData WriteMemSlices(QuicMemSliceSpan span, bool fin);
QuicConsumedData WriteMemSlices(absl::Span<QuicMemSlice> span, bool fin);
+ QuicConsumedData WriteMemSlice(QuicMemSlice span, bool fin);
// Returns true if any stream data is lost (including fin) and needs to be
// retransmitted.
@@ -361,14 +376,13 @@ class QUIC_EXPORT_PRIVATE QuicStream
// outstanding or fin is outstanding (if |fin| is true). Returns false
// otherwise.
bool IsStreamFrameOutstanding(QuicStreamOffset offset,
- QuicByteCount data_length,
- bool fin) const;
+ QuicByteCount data_length, bool fin) const;
StreamType type() const { return type_; }
// Handle received StopSending frame. Returns true if the processing finishes
// gracefully.
- virtual bool OnStopSending(QuicRstStreamErrorCode code);
+ virtual bool OnStopSending(QuicResetStreamError error);
// Returns true if the stream is static.
bool is_static() const { return is_static_; }
@@ -393,8 +407,7 @@ class QUIC_EXPORT_PRIVATE QuicStream
// Called when data of [offset, offset + data_length] is buffered in send
// buffer.
virtual void OnDataBuffered(
- QuicStreamOffset /*offset*/,
- QuicByteCount /*data_length*/,
+ QuicStreamOffset /*offset*/, QuicByteCount /*data_length*/,
const QuicReferenceCountedPointer<QuicAckListenerInterface>&
/*ack_listener*/) {}
@@ -431,10 +444,18 @@ class QUIC_EXPORT_PRIVATE QuicStream
void SetFinSent();
// Send STOP_SENDING if it hasn't been sent yet.
- void MaybeSendStopSending(QuicRstStreamErrorCode error);
+ void MaybeSendStopSending(QuicResetStreamError error);
// Send RESET_STREAM if it hasn't been sent yet.
- void MaybeSendRstStream(QuicRstStreamErrorCode error);
+ void MaybeSendRstStream(QuicResetStreamError error);
+
+ // Convenience warppers for two methods above.
+ void MaybeSendRstStream(QuicRstStreamErrorCode error) {
+ MaybeSendRstStream(QuicResetStreamError::FromInternal(error));
+ }
+ void MaybeSendStopSending(QuicRstStreamErrorCode error) {
+ MaybeSendStopSending(QuicResetStreamError::FromInternal(error));
+ }
// Close the write side of the socket. Further writes will fail.
// Can be called by the subclass or internally.
@@ -442,7 +463,7 @@ class QUIC_EXPORT_PRIVATE QuicStream
virtual void CloseWriteSide();
void set_rst_received(bool rst_received) { rst_received_ = rst_received; }
- void set_stream_error(QuicRstStreamErrorCode error) { stream_error_ = error; }
+ void set_stream_error(QuicResetStreamError error) { stream_error_ = error; }
StreamDelegateInterface* stream_delegate() { return stream_delegate_; }
@@ -462,6 +483,11 @@ class QUIC_EXPORT_PRIVATE QuicStream
QuicStreamSendBuffer& send_buffer() { return send_buffer_; }
+ // Called when the write side of the stream is closed, and all of the outgoing
+ // data has been acknowledged. This corresponds to the "Data Recvd" state of
+ // RFC 9000.
+ virtual void OnWriteSideInDataRecvdState() {}
+
// Return the current flow control send window in bytes.
absl::optional<QuicByteCount> GetSendWindow() const;
absl::optional<QuicByteCount> GetReceiveWindow() const;
@@ -470,33 +496,9 @@ class QUIC_EXPORT_PRIVATE QuicStream
friend class test::QuicStreamPeer;
friend class QuicStreamUtils;
- // Wraps around either QuicMemSliceSpan or absl::Span<QuicMemSlice>.
- // TODO(vasilvv): delete this after QuicMemSliceSpan is gone.
- class QUIC_EXPORT_PRIVATE MemSliceSpanWrapper {
- public:
- explicit MemSliceSpanWrapper(QuicMemSliceSpan span) : old_(span) {}
- explicit MemSliceSpanWrapper(absl::Span<QuicMemSlice> span) : new_(span) {}
-
- bool empty() { return old_.has_value() ? old_->empty() : new_.empty(); }
- QuicByteCount SaveTo(QuicStreamSendBuffer& send_buffer) {
- if (old_.has_value()) {
- return send_buffer.SaveMemSliceSpan(*old_);
- }
- return send_buffer.SaveMemSliceSpan(new_);
- }
-
- private:
- absl::optional<QuicMemSliceSpan> old_;
- absl::Span<QuicMemSlice> new_;
- };
-
- QuicStream(QuicStreamId id,
- QuicSession* session,
- QuicStreamSequencer sequencer,
- bool is_static,
- StreamType type,
- uint64_t stream_bytes_read,
- bool fin_received,
+ QuicStream(QuicStreamId id, QuicSession* session,
+ QuicStreamSequencer sequencer, bool is_static, StreamType type,
+ uint64_t stream_bytes_read, bool fin_received,
absl::optional<QuicFlowController> flow_controller,
QuicFlowController* connection_flow_controller);
@@ -518,8 +520,6 @@ class QUIC_EXPORT_PRIVATE QuicStream
// Returns true if deadline_ has passed.
bool HasDeadlinePassed() const;
- QuicConsumedData WriteMemSlicesInner(MemSliceSpanWrapper span, bool fin);
-
QuicStreamSequencer sequencer_;
QuicStreamId id_;
// Pointer to the owning QuicSession object.
@@ -534,7 +534,7 @@ class QUIC_EXPORT_PRIVATE QuicStream
// Stream error code received from a RstStreamFrame or error code sent by the
// visitor or sequencer in the RstStreamFrame.
- QuicRstStreamErrorCode stream_error_;
+ QuicResetStreamError stream_error_;
// Connection error code due to which the stream was closed. |stream_error_|
// is set to |QUIC_STREAM_CONNECTION_ERROR| when this happens and consumers
// should check |connection_error_|.
@@ -545,6 +545,9 @@ class QUIC_EXPORT_PRIVATE QuicStream
// True if the write side is closed, and further writes should fail.
bool write_side_closed_;
+ // True if OnWriteSideInDataRecvdState() has already been called.
+ bool write_side_data_recvd_state_notified_;
+
// True if the subclass has written a FIN with WriteOrBufferData, but it was
// buffered in queued_data_ rather than being sent to the session.
bool fin_buffered_;
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream_send_buffer.cc b/chromium/net/third_party/quiche/src/quic/core/quic_stream_send_buffer.cc
index 1e32e544cd1..b2ac6bfc7c4 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_stream_send_buffer.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream_send_buffer.cc
@@ -92,11 +92,6 @@ void QuicStreamSendBuffer::SaveMemSlice(QuicMemSlice slice) {
stream_offset_ += length;
}
-QuicByteCount QuicStreamSendBuffer::SaveMemSliceSpan(QuicMemSliceSpan span) {
- return span.ConsumeAll(
- [&](QuicMemSlice slice) { SaveMemSlice(std::move(slice)); });
-}
-
QuicByteCount QuicStreamSendBuffer::SaveMemSliceSpan(
absl::Span<QuicMemSlice> span) {
QuicByteCount total = 0;
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream_send_buffer.h b/chromium/net/third_party/quiche/src/quic/core/quic_stream_send_buffer.h
index f91e4760870..bf50217cefd 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_stream_send_buffer.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream_send_buffer.h
@@ -12,7 +12,6 @@
#include "quic/core/quic_types.h"
#include "quic/platform/api/quic_iovec.h"
#include "quic/platform/api/quic_mem_slice.h"
-#include "quic/platform/api/quic_mem_slice_span.h"
#include "common/quiche_circular_deque.h"
namespace quic {
@@ -80,7 +79,6 @@ class QUIC_EXPORT_PRIVATE QuicStreamSendBuffer {
void SaveMemSlice(QuicMemSlice slice);
// Save all slices in |span| to send buffer. Return total bytes saved.
- QuicByteCount SaveMemSliceSpan(QuicMemSliceSpan span);
QuicByteCount SaveMemSliceSpan(absl::Span<QuicMemSlice> span);
// Called when |bytes_consumed| bytes has been consumed by the stream.
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream_send_buffer_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_stream_send_buffer_test.cc
index e1a2358acba..9aaec4d2c6a 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_stream_send_buffer_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream_send_buffer_test.cc
@@ -13,7 +13,6 @@
#include "quic/platform/api/quic_expect_bug.h"
#include "quic/platform/api/quic_flags.h"
#include "quic/platform/api/quic_test.h"
-#include "quic/platform/api/quic_test_mem_slice_vector.h"
#include "quic/test_tools/quic_stream_send_buffer_peer.h"
#include "quic/test_tools/quic_test_utils.h"
@@ -321,14 +320,13 @@ TEST_F(QuicStreamSendBufferTest, SaveMemSliceSpan) {
SimpleBufferAllocator allocator;
QuicStreamSendBuffer send_buffer(&allocator);
- char data[1024];
- std::vector<std::pair<char*, size_t>> buffers;
+ std::string data(1024, 'a');
+ std::vector<QuicMemSlice> buffers;
for (size_t i = 0; i < 10; ++i) {
- buffers.push_back(std::make_pair(data, 1024));
+ buffers.push_back(MemSliceFromString(data));
}
- QuicTestMemSliceVector vector(buffers);
- EXPECT_EQ(10 * 1024u, send_buffer.SaveMemSliceSpan(vector.span()));
+ EXPECT_EQ(10 * 1024u, send_buffer.SaveMemSliceSpan(absl::MakeSpan(buffers)));
EXPECT_EQ(10u, send_buffer.size());
}
@@ -336,15 +334,13 @@ TEST_F(QuicStreamSendBufferTest, SaveEmptyMemSliceSpan) {
SimpleBufferAllocator allocator;
QuicStreamSendBuffer send_buffer(&allocator);
- char data[1024];
- std::vector<std::pair<char*, size_t>> buffers;
+ std::string data(1024, 'a');
+ std::vector<QuicMemSlice> buffers;
for (size_t i = 0; i < 10; ++i) {
- buffers.push_back(std::make_pair(data, 1024));
+ buffers.push_back(MemSliceFromString(data));
}
- buffers.push_back(std::make_pair(nullptr, 0));
- QuicTestMemSliceVector vector(buffers);
- EXPECT_EQ(10 * 1024u, send_buffer.SaveMemSliceSpan(vector.span()));
+ EXPECT_EQ(10 * 1024u, send_buffer.SaveMemSliceSpan(absl::MakeSpan(buffers)));
// Verify the empty slice does not get saved.
EXPECT_EQ(10u, send_buffer.size());
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer.cc b/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer.cc
index 88a51bd5e08..1dbe5df9310 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer.cc
@@ -236,7 +236,8 @@ void QuicStreamSequencer::MarkConsumed(size_t num_bytes_consumed) {
<< "Invalid argument to MarkConsumed."
<< " expect to consume: " << num_bytes_consumed
<< ", but not enough bytes available. " << DebugString();
- stream_->Reset(QUIC_ERROR_PROCESSING_STREAM);
+ stream_->ResetWithError(
+ QuicResetStreamError::FromInternal(QUIC_ERROR_PROCESSING_STREAM));
return;
}
stream_->AddBytesConsumed(num_bytes_consumed);
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 b7ea49dac05..fe96f253dad 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
@@ -37,7 +37,7 @@ class QUIC_EXPORT_PRIVATE QuicStreamSequencer {
virtual void AddBytesConsumed(QuicByteCount bytes) = 0;
// Called when an error has occurred which should result in the stream
// being reset.
- virtual void Reset(QuicRstStreamErrorCode error) = 0;
+ virtual void ResetWithError(QuicResetStreamError error) = 0;
// Called when an error has occurred which should result in the connection
// being closed.
virtual void OnUnrecoverableError(QuicErrorCode error,
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_buffer.cc b/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_buffer.cc
index 871b832b168..78c55c7523d 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_buffer.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_buffer.cc
@@ -46,9 +46,7 @@ QuicStreamSequencerBuffer::QuicStreamSequencerBuffer(size_t max_capacity_bytes)
current_blocks_count_(0u),
total_bytes_read_(0),
blocks_(nullptr) {
- if (allocate_blocks_on_demand_) {
- QUICHE_DCHECK_GE(max_blocks_count_, kInitialBlockCount);
- }
+ QUICHE_DCHECK_GE(max_blocks_count_, kInitialBlockCount);
Clear();
}
@@ -58,9 +56,7 @@ QuicStreamSequencerBuffer::~QuicStreamSequencerBuffer() {
void QuicStreamSequencerBuffer::Clear() {
if (blocks_ != nullptr) {
- size_t blocks_to_clear =
- allocate_blocks_on_demand_ ? current_blocks_count_ : max_blocks_count_;
- for (size_t i = 0; i < blocks_to_clear; ++i) {
+ for (size_t i = 0; i < current_blocks_count_; ++i) {
if (blocks_[i] != nullptr) {
RetireBlock(i);
}
@@ -129,9 +125,7 @@ QuicErrorCode QuicStreamSequencerBuffer::OnStreamData(
*error_details = "Received data beyond available range.";
return QUIC_INTERNAL_ERROR;
}
- if (allocate_blocks_on_demand_) {
- QUIC_RELOADABLE_FLAG_COUNT(
- quic_allocate_stream_sequencer_buffer_blocks_on_demand);
+ if (!delay_allocation_until_new_data_) {
MaybeAddMoreBlocks(starting_offset + size);
}
@@ -148,6 +142,11 @@ QuicErrorCode QuicStreamSequencerBuffer::OnStreamData(
*error_details = "Too many data intervals received for this stream.";
return QUIC_TOO_MANY_STREAM_DATA_INTERVALS;
}
+ if (delay_allocation_until_new_data_) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(
+ quic_delay_sequencer_buffer_allocation_until_new_data, 1, 2);
+ MaybeAddMoreBlocks(starting_offset + size);
+ }
size_t bytes_copy = 0;
if (!CopyStreamData(starting_offset, data, &bytes_copy, error_details)) {
@@ -171,6 +170,11 @@ QuicErrorCode QuicStreamSequencerBuffer::OnStreamData(
*error_details = "Too many data intervals received for this stream.";
return QUIC_TOO_MANY_STREAM_DATA_INTERVALS;
}
+ if (delay_allocation_until_new_data_) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(
+ quic_delay_sequencer_buffer_allocation_until_new_data, 2, 2);
+ MaybeAddMoreBlocks(starting_offset + size);
+ }
for (const auto& interval : newly_received) {
const QuicStreamOffset copy_offset = interval.min();
const QuicByteCount copy_length = interval.max() - interval.min();
@@ -202,8 +206,7 @@ bool QuicStreamSequencerBuffer::CopyStreamData(QuicStreamOffset offset,
while (source_remaining > 0) {
const size_t write_block_num = GetBlockIndex(offset);
const size_t write_block_offset = GetInBlockOffset(offset);
- size_t current_blocks_count =
- allocate_blocks_on_demand_ ? current_blocks_count_ : max_blocks_count_;
+ size_t current_blocks_count = current_blocks_count_;
QUICHE_DCHECK_GT(current_blocks_count, write_block_num);
size_t block_capacity = GetBlockCapacity(write_block_num);
@@ -215,15 +218,6 @@ bool QuicStreamSequencerBuffer::CopyStreamData(QuicStreamOffset offset,
bytes_avail = total_bytes_read_ + max_buffer_capacity_bytes_ - offset;
}
- if (!allocate_blocks_on_demand_) {
- if (blocks_ == nullptr) {
- blocks_.reset(new BufferBlock*[max_blocks_count_]());
- for (size_t i = 0; i < max_blocks_count_; ++i) {
- blocks_[i] = nullptr;
- }
- }
- }
-
if (write_block_num >= current_blocks_count) {
*error_details = absl::StrCat(
"QuicStreamSequencerBuffer error: OnStreamData() exceed array bounds."
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 05d41b8149c..83ce01bd366 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
@@ -229,10 +229,6 @@ class QUIC_EXPORT_PRIVATE QuicStreamSequencerBuffer {
// Number of bytes read out of buffer.
QuicStreamOffset total_bytes_read_;
- // Whether size of blocks_ grows on demand.
- bool allocate_blocks_on_demand_ = GetQuicReloadableFlag(
- quic_allocate_stream_sequencer_buffer_blocks_on_demand);
-
// An ordered, variable-length list of blocks, with the length limited
// such that the number of blocks never exceeds max_blocks_count_.
// Each list entry can hold up to kBlockSizeBytes bytes.
@@ -243,6 +239,9 @@ class QUIC_EXPORT_PRIVATE QuicStreamSequencerBuffer {
// Currently received data.
QuicIntervalSet<QuicStreamOffset> bytes_received_;
+
+ bool delay_allocation_until_new_data_ = GetQuicReloadableFlag(
+ quic_delay_sequencer_buffer_allocation_until_new_data);
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_buffer_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_buffer_test.cc
index dc21a097441..212c25f7366 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_buffer_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_buffer_test.cc
@@ -1091,8 +1091,6 @@ TEST_F(QuicStreamSequencerBufferRandomIOTest, RandomWriteAndConsumeInPlace) {
}
TEST_F(QuicStreamSequencerBufferTest, GrowBlockSizeOnDemand) {
- SetQuicReloadableFlag(quic_allocate_stream_sequencer_buffer_blocks_on_demand,
- true);
max_capacity_bytes_ = 1024 * kBlockSizeBytes;
std::string source_of_one_block(kBlockSizeBytes, 'a');
Initialize();
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 b097bc5bc93..0a15e96d3c4 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
@@ -43,7 +43,7 @@ class MockStream : public QuicStreamSequencer::StreamInterface {
QuicIetfTransportErrorCodes ietf_error,
const std::string& details),
(override));
- MOCK_METHOD(void, Reset, (QuicRstStreamErrorCode error), (override));
+ MOCK_METHOD(void, ResetWithError, (QuicResetStreamError error), (override));
MOCK_METHOD(void, AddBytesConsumed, (QuicByteCount bytes), (override));
QuicStreamId id() const override { return 1; }
@@ -566,7 +566,8 @@ TEST_F(QuicStreamSequencerTest, MarkConsumedError) {
// Now, attempt to mark consumed more data than was readable and expect the
// stream to be closed.
- EXPECT_CALL(stream_, Reset(QUIC_ERROR_PROCESSING_STREAM));
+ EXPECT_CALL(stream_, ResetWithError(QuicResetStreamError::FromInternal(
+ QUIC_ERROR_PROCESSING_STREAM)));
EXPECT_QUIC_BUG(sequencer_->MarkConsumed(4),
"Invalid argument to MarkConsumed."
" expect to consume: 4, but not enough bytes available.");
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 e69b657177d..9d48b1fa295 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
@@ -26,7 +26,6 @@
#include "quic/platform/api/quic_logging.h"
#include "quic/platform/api/quic_mem_slice_storage.h"
#include "quic/platform/api/quic_test.h"
-#include "quic/platform/api/quic_test_mem_slice_vector.h"
#include "quic/test_tools/quic_config_peer.h"
#include "quic/test_tools/quic_connection_peer.h"
#include "quic/test_tools/quic_flow_controller_peer.h"
@@ -59,16 +58,15 @@ class TestStream : public QuicStream {
sequencer()->set_level_triggered(true);
}
- TestStream(PendingStream* pending,
- QuicSession* session,
- StreamType type,
- bool is_static)
- : QuicStream(pending, session, type, is_static) {}
+ TestStream(PendingStream* pending, QuicSession* session, bool is_static)
+ : QuicStream(pending, session, is_static) {}
MOCK_METHOD(void, OnDataAvailable, (), (override));
MOCK_METHOD(void, OnCanWriteNewData, (), (override));
+ MOCK_METHOD(void, OnWriteSideInDataRecvdState, (), (override));
+
using QuicStream::CanWriteNewData;
using QuicStream::CanWriteNewDataAfterData;
using QuicStream::CloseWriteSide;
@@ -88,11 +86,11 @@ class QuicStreamTest : public QuicTestWithParam<ParsedQuicVersion> {
: zero_(QuicTime::Delta::Zero()),
supported_versions_(AllSupportedVersions()) {}
- void Initialize() {
+ void Initialize(Perspective perspective = Perspective::IS_SERVER) {
ParsedQuicVersionVector version_vector;
version_vector.push_back(GetParam());
connection_ = new StrictMock<MockQuicConnection>(
- &helper_, &alarm_factory_, Perspective::IS_SERVER, version_vector);
+ &helper_, &alarm_factory_, perspective, version_vector);
connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
session_ = std::make_unique<StrictMock<MockQuicSession>>(connection_);
session_->Initialize();
@@ -133,12 +131,9 @@ class QuicStreamTest : public QuicTestWithParam<ParsedQuicVersion> {
}
QuicConsumedData CloseStreamOnWriteError(
- QuicStreamId id,
- QuicByteCount /*write_length*/,
- QuicStreamOffset /*offset*/,
- StreamSendingState /*state*/,
- TransmissionType /*type*/,
- absl::optional<EncryptionLevel> /*level*/) {
+ QuicStreamId id, QuicByteCount /*write_length*/,
+ QuicStreamOffset /*offset*/, StreamSendingState /*state*/,
+ TransmissionType /*type*/, absl::optional<EncryptionLevel> /*level*/) {
session_->ResetStream(id, QUIC_STREAM_CANCELLED);
return QuicConsumedData(1, false);
}
@@ -167,33 +162,59 @@ class QuicStreamTest : public QuicTestWithParam<ParsedQuicVersion> {
QuicStreamId kTestStreamId =
GetNthClientInitiatedBidirectionalStreamId(GetParam().transport_version,
1);
+ const QuicStreamId kTestPendingStreamId =
+ GetNthClientInitiatedUnidirectionalStreamId(GetParam().transport_version,
+ 1);
};
-INSTANTIATE_TEST_SUITE_P(QuicStreamTests,
- QuicStreamTest,
+INSTANTIATE_TEST_SUITE_P(QuicStreamTests, QuicStreamTest,
::testing::ValuesIn(AllSupportedVersions()),
::testing::PrintToStringParamName());
-TEST_P(QuicStreamTest, PendingStreamStaticness) {
+using PendingStreamTest = QuicStreamTest;
+
+INSTANTIATE_TEST_SUITE_P(PendingStreamTests, PendingStreamTest,
+ ::testing::ValuesIn(CurrentSupportedHttp3Versions()),
+ ::testing::PrintToStringParamName());
+
+TEST_P(PendingStreamTest, PendingStreamStaticness) {
Initialize();
- PendingStream pending(kTestStreamId + 2, session_.get());
- TestStream stream(&pending, session_.get(), StreamType::BIDIRECTIONAL, false);
+ PendingStream pending(kTestPendingStreamId, session_.get());
+ TestStream stream(&pending, session_.get(), false);
EXPECT_FALSE(stream.is_static());
- PendingStream pending2(kTestStreamId + 3, session_.get());
- TestStream stream2(&pending2, session_.get(), StreamType::BIDIRECTIONAL,
- true);
+ PendingStream pending2(kTestPendingStreamId + 4, session_.get());
+ TestStream stream2(&pending2, session_.get(), true);
EXPECT_TRUE(stream2.is_static());
}
-TEST_P(QuicStreamTest, PendingStreamTooMuchData) {
+TEST_P(PendingStreamTest, PendingStreamType) {
+ Initialize();
+
+ PendingStream pending(kTestPendingStreamId, session_.get());
+ TestStream stream(&pending, session_.get(), false);
+ EXPECT_EQ(stream.type(), READ_UNIDIRECTIONAL);
+}
+
+TEST_P(PendingStreamTest, PendingStreamTypeOnClient) {
+ Initialize(Perspective::IS_CLIENT);
+
+ QuicStreamId server_initiated_pending_stream_id =
+ GetNthServerInitiatedUnidirectionalStreamId(session_->transport_version(),
+ 1);
+ PendingStream pending(server_initiated_pending_stream_id, session_.get());
+ TestStream stream(&pending, session_.get(), false);
+ EXPECT_EQ(stream.type(), READ_UNIDIRECTIONAL);
+}
+
+TEST_P(PendingStreamTest, PendingStreamTooMuchData) {
Initialize();
- PendingStream pending(kTestStreamId + 2, session_.get());
+ PendingStream pending(kTestPendingStreamId, session_.get());
// Receive a stream frame that violates flow control: the byte offset is
// higher than the receive window offset.
- QuicStreamFrame frame(kTestStreamId + 2, false,
+ QuicStreamFrame frame(kTestPendingStreamId, false,
kInitialSessionFlowControlWindowForTest + 1, ".");
// Stream should not accept the frame, and the connection should be closed.
@@ -202,29 +223,43 @@ TEST_P(QuicStreamTest, PendingStreamTooMuchData) {
pending.OnStreamFrame(frame);
}
-TEST_P(QuicStreamTest, PendingStreamTooMuchDataInRstStream) {
+TEST_P(PendingStreamTest, PendingStreamTooMuchDataInRstStream) {
Initialize();
- PendingStream pending(kTestStreamId + 2, session_.get());
+ PendingStream pending1(kTestPendingStreamId, session_.get());
// Receive a rst stream frame that violates flow control: the byte offset is
// higher than the receive window offset.
- QuicRstStreamFrame frame(kInvalidControlFrameId, kTestStreamId + 2,
- QUIC_STREAM_CANCELLED,
- kInitialSessionFlowControlWindowForTest + 1);
+ QuicRstStreamFrame frame1(kInvalidControlFrameId, kTestPendingStreamId,
+ QUIC_STREAM_CANCELLED,
+ kInitialSessionFlowControlWindowForTest + 1);
// Pending stream should not accept the frame, and the connection should be
// closed.
EXPECT_CALL(*connection_,
CloseConnection(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA, _, _));
- pending.OnRstStreamFrame(frame);
+ pending1.OnRstStreamFrame(frame1);
+
+ QuicStreamId bidirection_stream_id = QuicUtils::GetFirstBidirectionalStreamId(
+ session_->transport_version(), Perspective::IS_CLIENT);
+ PendingStream pending2(bidirection_stream_id, session_.get());
+ // Receive a rst stream frame that violates flow control: the byte offset is
+ // higher than the receive window offset.
+ QuicRstStreamFrame frame2(kInvalidControlFrameId, bidirection_stream_id,
+ QUIC_STREAM_CANCELLED,
+ kInitialSessionFlowControlWindowForTest + 1);
+ // Bidirectional Pending stream should not accept the frame, and the
+ // connection should be closed.
+ EXPECT_CALL(*connection_,
+ CloseConnection(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA, _, _));
+ pending2.OnRstStreamFrame(frame2);
}
-TEST_P(QuicStreamTest, PendingStreamRstStream) {
+TEST_P(PendingStreamTest, PendingStreamRstStream) {
Initialize();
- PendingStream pending(kTestStreamId + 2, session_.get());
+ PendingStream pending(kTestPendingStreamId, session_.get());
QuicStreamOffset final_byte_offset = 7;
- QuicRstStreamFrame frame(kInvalidControlFrameId, kTestStreamId + 2,
+ QuicRstStreamFrame frame(kInvalidControlFrameId, kTestPendingStreamId,
QUIC_STREAM_CANCELLED, final_byte_offset);
// Pending stream should accept the frame and not close the connection.
@@ -232,19 +267,47 @@ TEST_P(QuicStreamTest, PendingStreamRstStream) {
pending.OnRstStreamFrame(frame);
}
-TEST_P(QuicStreamTest, FromPendingStream) {
+TEST_P(PendingStreamTest, PendingStreamWindowUpdate) {
+ Initialize();
+
+ QuicStreamId bidirection_stream_id = QuicUtils::GetFirstBidirectionalStreamId(
+ session_->transport_version(), Perspective::IS_CLIENT);
+ PendingStream pending(bidirection_stream_id, session_.get());
+ QuicWindowUpdateFrame frame(kInvalidControlFrameId, bidirection_stream_id,
+ kDefaultFlowControlSendWindow * 2);
+ pending.OnWindowUpdateFrame(frame);
+ TestStream stream(&pending, session_.get(), false);
+
+ EXPECT_EQ(QuicStreamPeer::SendWindowSize(&stream),
+ kDefaultFlowControlSendWindow * 2);
+}
+
+TEST_P(PendingStreamTest, PendingStreamStopSending) {
Initialize();
- PendingStream pending(kTestStreamId + 2, session_.get());
+ QuicStreamId bidirection_stream_id = QuicUtils::GetFirstBidirectionalStreamId(
+ session_->transport_version(), Perspective::IS_CLIENT);
+ PendingStream pending(bidirection_stream_id, session_.get());
+ QuicResetStreamError error =
+ QuicResetStreamError::FromInternal(QUIC_STREAM_INTERNAL_ERROR);
+ pending.OnStopSending(error);
+ EXPECT_TRUE(pending.GetStopSendingErrorCode());
+ auto actual_error = *pending.GetStopSendingErrorCode();
+ EXPECT_EQ(actual_error, error);
+}
- QuicStreamFrame frame(kTestStreamId + 2, false, 2, ".");
+TEST_P(PendingStreamTest, FromPendingStream) {
+ Initialize();
+
+ PendingStream pending(kTestPendingStreamId, session_.get());
+
+ QuicStreamFrame frame(kTestPendingStreamId, false, 2, ".");
pending.OnStreamFrame(frame);
pending.OnStreamFrame(frame);
- QuicStreamFrame frame2(kTestStreamId + 2, true, 3, ".");
+ QuicStreamFrame frame2(kTestPendingStreamId, true, 3, ".");
pending.OnStreamFrame(frame2);
- TestStream stream(&pending, session_.get(), StreamType::READ_UNIDIRECTIONAL,
- false);
+ TestStream stream(&pending, session_.get(), false);
EXPECT_EQ(3, stream.num_frames_received());
EXPECT_EQ(3u, stream.stream_bytes_read());
EXPECT_EQ(1, stream.num_duplicate_frames_received());
@@ -254,19 +317,18 @@ TEST_P(QuicStreamTest, FromPendingStream) {
session_->flow_controller()->highest_received_byte_offset());
}
-TEST_P(QuicStreamTest, FromPendingStreamThenData) {
+TEST_P(PendingStreamTest, FromPendingStreamThenData) {
Initialize();
- PendingStream pending(kTestStreamId + 2, session_.get());
+ PendingStream pending(kTestPendingStreamId, session_.get());
- QuicStreamFrame frame(kTestStreamId + 2, false, 2, ".");
+ QuicStreamFrame frame(kTestPendingStreamId, false, 2, ".");
pending.OnStreamFrame(frame);
- auto stream = new TestStream(&pending, session_.get(),
- StreamType::READ_UNIDIRECTIONAL, false);
+ auto stream = new TestStream(&pending, session_.get(), false);
session_->ActivateStream(absl::WrapUnique(stream));
- QuicStreamFrame frame2(kTestStreamId + 2, true, 3, ".");
+ QuicStreamFrame frame2(kTestPendingStreamId, true, 3, ".");
stream->OnStreamFrame(frame2);
EXPECT_EQ(2, stream->num_frames_received());
@@ -865,6 +927,7 @@ TEST_P(QuicStreamTest, StreamWaitsForAcks) {
EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size());
// FIN is acked.
+ EXPECT_CALL(*stream_, OnWriteSideInDataRecvdState());
EXPECT_TRUE(stream_->OnStreamFrameAcked(18, 0, true, QuicTime::Delta::Zero(),
QuicTime::Zero(),
&newly_acked_length));
@@ -908,6 +971,7 @@ TEST_P(QuicStreamTest, StreamDataGetAckedOutOfOrder) {
// FIN is not acked yet.
EXPECT_TRUE(stream_->IsWaitingForAcks());
EXPECT_TRUE(session_->HasUnackedStreamData());
+ EXPECT_CALL(*stream_, OnWriteSideInDataRecvdState());
EXPECT_TRUE(stream_->OnStreamFrameAcked(27, 0, true, QuicTime::Delta::Zero(),
QuicTime::Zero(),
&newly_acked_length));
@@ -977,8 +1041,11 @@ TEST_P(QuicStreamTest, RstFrameReceivedStreamNotFinishSending) {
QuicRstStreamFrame rst_frame(kInvalidControlFrameId, stream_->id(),
QUIC_STREAM_CANCELLED, 9);
- EXPECT_CALL(*session_, MaybeSendRstStreamFrame(stream_->id(),
- QUIC_RST_ACKNOWLEDGEMENT, 9));
+ EXPECT_CALL(
+ *session_,
+ MaybeSendRstStreamFrame(
+ stream_->id(),
+ QuicResetStreamError::FromInternal(QUIC_RST_ACKNOWLEDGEMENT), 9));
stream_->OnStreamReset(rst_frame);
EXPECT_EQ(1u, QuicStreamPeer::SendBuffer(stream_).size());
// Stream stops waiting for acks as it does not finish sending and rst is
@@ -1020,8 +1087,11 @@ TEST_P(QuicStreamTest, ConnectionClosed) {
stream_->WriteOrBufferData(kData1, false, nullptr);
EXPECT_TRUE(stream_->IsWaitingForAcks());
EXPECT_TRUE(session_->HasUnackedStreamData());
- EXPECT_CALL(*session_, MaybeSendRstStreamFrame(stream_->id(),
- QUIC_RST_ACKNOWLEDGEMENT, 9));
+ EXPECT_CALL(
+ *session_,
+ MaybeSendRstStreamFrame(
+ stream_->id(),
+ QuicResetStreamError::FromInternal(QUIC_RST_ACKNOWLEDGEMENT), 9));
QuicConnectionPeer::SetConnectionClose(connection_);
stream_->OnConnectionClosed(QUIC_INTERNAL_ERROR,
ConnectionCloseSource::FROM_SELF);
@@ -1243,26 +1313,20 @@ TEST_P(QuicStreamTest, WriteMemSlices) {
TEST_P(QuicStreamTest, WriteMemSlicesReachStreamLimit) {
Initialize();
QuicStreamPeer::SetStreamBytesWritten(kMaxStreamLength - 5u, stream_);
- char data[5];
std::vector<std::pair<char*, size_t>> buffers;
- buffers.push_back(std::make_pair(data, ABSL_ARRAYSIZE(data)));
- QuicTestMemSliceVector vector1(buffers);
- QuicMemSliceSpan span1 = vector1.span();
+ QuicMemSlice slice1 = MemSliceFromString("12345");
EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
.WillOnce(InvokeWithoutArgs([this]() {
return session_->ConsumeData(stream_->id(), 5u, 0u, NO_FIN,
NOT_RETRANSMISSION, absl::nullopt);
}));
// There is no buffered data before, all data should be consumed.
- QuicConsumedData consumed = stream_->WriteMemSlices(span1, false);
+ QuicConsumedData consumed = stream_->WriteMemSlice(std::move(slice1), false);
EXPECT_EQ(5u, consumed.bytes_consumed);
- std::vector<std::pair<char*, size_t>> buffers2;
- buffers2.push_back(std::make_pair(data, 1u));
- QuicTestMemSliceVector vector2(buffers);
- QuicMemSliceSpan span2 = vector2.span();
+ QuicMemSlice slice2 = MemSliceFromString("6");
EXPECT_CALL(*connection_, CloseConnection(QUIC_STREAM_LENGTH_OVERFLOW, _, _));
- EXPECT_QUIC_BUG(stream_->WriteMemSlices(span2, false),
+ EXPECT_QUIC_BUG(stream_->WriteMemSlice(std::move(slice2), false),
"Write too many data via stream");
}
@@ -1313,6 +1377,7 @@ TEST_P(QuicStreamTest, StreamDataGetAckedMultipleTimes) {
EXPECT_TRUE(session_->HasUnackedStreamData());
// Ack Fin.
+ EXPECT_CALL(*stream_, OnWriteSideInDataRecvdState()).Times(1);
EXPECT_TRUE(stream_->OnStreamFrameAcked(27, 0, true, QuicTime::Delta::Zero(),
QuicTime::Zero(),
&newly_acked_length));
@@ -1549,10 +1614,14 @@ TEST_P(QuicStreamTest, ResetStreamOnTtlExpiresRetransmitLostData) {
// Verify stream gets reset because TTL expires.
if (session_->version().UsesHttp3()) {
EXPECT_CALL(*session_,
- MaybeSendStopSendingFrame(_, QUIC_STREAM_TTL_EXPIRED))
+ MaybeSendStopSendingFrame(_, QuicResetStreamError::FromInternal(
+ QUIC_STREAM_TTL_EXPIRED)))
.Times(1);
}
- EXPECT_CALL(*session_, MaybeSendRstStreamFrame(_, QUIC_STREAM_TTL_EXPIRED, _))
+ EXPECT_CALL(
+ *session_,
+ MaybeSendRstStreamFrame(
+ _, QuicResetStreamError::FromInternal(QUIC_STREAM_TTL_EXPIRED), _))
.Times(1);
stream_->OnCanWrite();
}
@@ -1573,10 +1642,14 @@ TEST_P(QuicStreamTest, ResetStreamOnTtlExpiresEarlyRetransmitData) {
// Verify stream gets reset because TTL expires.
if (session_->version().UsesHttp3()) {
EXPECT_CALL(*session_,
- MaybeSendStopSendingFrame(_, QUIC_STREAM_TTL_EXPIRED))
+ MaybeSendStopSendingFrame(_, QuicResetStreamError::FromInternal(
+ QUIC_STREAM_TTL_EXPIRED)))
.Times(1);
}
- EXPECT_CALL(*session_, MaybeSendRstStreamFrame(_, QUIC_STREAM_TTL_EXPIRED, _))
+ EXPECT_CALL(
+ *session_,
+ MaybeSendRstStreamFrame(
+ _, QuicResetStreamError::FromInternal(QUIC_STREAM_TTL_EXPIRED), _))
.Times(1);
stream_->RetransmitStreamData(0, 100, false, PTO_RETRANSMISSION);
}
@@ -1647,6 +1720,15 @@ TEST_P(QuicStreamTest, EmptyStreamFrameWithNoFin) {
stream_->OnStreamFrame(empty_stream_frame);
}
+TEST_P(QuicStreamTest, SendRstWithCustomIetfCode) {
+ Initialize();
+ QuicResetStreamError error(QUIC_STREAM_CANCELLED, 0x1234abcd);
+ EXPECT_CALL(*session_, MaybeSendRstStreamFrame(kTestStreamId, error, _))
+ .Times(1);
+ stream_->ResetWithError(error);
+ EXPECT_TRUE(rst_sent());
+}
+
} // namespace
} // namespace test
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_time.cc b/chromium/net/third_party/quiche/src/quic/core/quic_time.cc
index daf8e299dcd..08e0906c7cb 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_time.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_time.cc
@@ -21,11 +21,11 @@ std::string QuicTime::Delta::ToDebuggingValue() const {
// For debugging purposes, always display the value with the highest precision
// available.
- if (absolute_value > kSecondInMicroseconds &&
+ if (absolute_value >= kSecondInMicroseconds &&
absolute_value % kSecondInMicroseconds == 0) {
return absl::StrCat(time_offset_ / kSecondInMicroseconds, "s");
}
- if (absolute_value > kMillisecondInMicroseconds &&
+ if (absolute_value >= kMillisecondInMicroseconds &&
absolute_value % kMillisecondInMicroseconds == 0) {
return absl::StrCat(time_offset_ / kMillisecondInMicroseconds, "ms");
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_time_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_time_test.cc
index eaaf75568d8..e5bb2857d0a 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_time_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_time_test.cc
@@ -87,8 +87,11 @@ TEST_F(QuicTimeDeltaTest, DebuggingValue) {
const QuicTime::Delta one_ms = QuicTime::Delta::FromMilliseconds(1);
const QuicTime::Delta one_s = QuicTime::Delta::FromSeconds(1);
+ EXPECT_EQ("1s", one_s.ToDebuggingValue());
EXPECT_EQ("3s", (3 * one_s).ToDebuggingValue());
+ EXPECT_EQ("1ms", one_ms.ToDebuggingValue());
EXPECT_EQ("3ms", (3 * one_ms).ToDebuggingValue());
+ EXPECT_EQ("1us", one_us.ToDebuggingValue());
EXPECT_EQ("3us", (3 * one_us).ToDebuggingValue());
EXPECT_EQ("3001us", (3 * one_ms + one_us).ToDebuggingValue());
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 12f5ef9aae2..c92b6368272 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
@@ -30,7 +30,7 @@ namespace quic {
// A very simple alarm that just informs the QuicTimeWaitListManager to clean
// up old connection_ids. This alarm should be cancelled and deleted before
// the QuicTimeWaitListManager is deleted.
-class ConnectionIdCleanUpAlarm : public QuicAlarm::Delegate {
+class ConnectionIdCleanUpAlarm : public QuicAlarm::DelegateWithoutContext {
public:
explicit ConnectionIdCleanUpAlarm(
QuicTimeWaitListManager* time_wait_list_manager)
@@ -91,9 +91,6 @@ QuicTimeWaitListManager::~QuicTimeWaitListManager() {
QuicTimeWaitListManager::ConnectionIdMap::iterator
QuicTimeWaitListManager::FindConnectionIdDataInMap(
const QuicConnectionId& connection_id) {
- if (!use_indirect_connection_id_map_) {
- return connection_id_map_.find(connection_id);
- }
auto it = indirect_connection_id_map_.find(connection_id);
if (it == indirect_connection_id_map_.end()) {
return connection_id_map_.end();
@@ -106,12 +103,8 @@ void QuicTimeWaitListManager::AddConnectionIdDataToMap(
int num_packets,
TimeWaitAction action,
TimeWaitConnectionInfo info) {
- if (use_indirect_connection_id_map_) {
- QUIC_RESTART_FLAG_COUNT_N(quic_time_wait_list_support_multiple_cid_v2, 1,
- 3);
- for (const auto& cid : info.active_connection_ids) {
- indirect_connection_id_map_[cid] = canonical_connection_id;
- }
+ for (const auto& cid : info.active_connection_ids) {
+ indirect_connection_id_map_[cid] = canonical_connection_id;
}
ConnectionIdData data(num_packets, clock_->ApproximateNow(), action,
std::move(info));
@@ -121,24 +114,18 @@ void QuicTimeWaitListManager::AddConnectionIdDataToMap(
void QuicTimeWaitListManager::RemoveConnectionDataFromMap(
ConnectionIdMap::iterator it) {
- if (use_indirect_connection_id_map_) {
- QUIC_RESTART_FLAG_COUNT_N(quic_time_wait_list_support_multiple_cid_v2, 2,
- 3);
- for (const auto& cid : it->second.info.active_connection_ids) {
- indirect_connection_id_map_.erase(cid);
- }
+ for (const auto& cid : it->second.info.active_connection_ids) {
+ indirect_connection_id_map_.erase(cid);
}
connection_id_map_.erase(it);
}
void QuicTimeWaitListManager::AddConnectionIdToTimeWait(
- QuicConnectionId connection_id,
TimeWaitAction action,
TimeWaitConnectionInfo info) {
QUICHE_DCHECK(!info.active_connection_ids.empty());
const QuicConnectionId& canonical_connection_id =
- use_indirect_connection_id_map_ ? info.active_connection_ids.front()
- : connection_id;
+ info.active_connection_ids.front();
QUICHE_DCHECK(action != SEND_TERMINATION_PACKETS ||
!info.termination_packets.empty());
QUICHE_DCHECK(action != DO_NOTHING || info.ietf_quic);
@@ -154,26 +141,18 @@ void QuicTimeWaitListManager::AddConnectionIdToTimeWait(
GetQuicFlag(FLAGS_quic_time_wait_list_max_connections);
QUICHE_DCHECK(connection_id_map_.empty() ||
num_connections() < static_cast<size_t>(max_connections));
- if (use_indirect_connection_id_map_ && new_connection_id) {
- QUIC_RESTART_FLAG_COUNT_N(quic_time_wait_list_support_multiple_cid_v2, 3,
- 3);
+ if (new_connection_id) {
for (const auto& cid : info.active_connection_ids) {
visitor_->OnConnectionAddedToTimeWaitList(cid);
}
}
AddConnectionIdDataToMap(canonical_connection_id, num_packets, action,
std::move(info));
- if (!use_indirect_connection_id_map_ && new_connection_id) {
- visitor_->OnConnectionAddedToTimeWaitList(canonical_connection_id);
- }
}
bool QuicTimeWaitListManager::IsConnectionIdInTimeWait(
QuicConnectionId connection_id) const {
- if (use_indirect_connection_id_map_) {
- return indirect_connection_id_map_.contains(connection_id);
- }
- return connection_id_map_.contains(connection_id);
+ return indirect_connection_id_map_.contains(connection_id);
}
void QuicTimeWaitListManager::OnBlockedWriterCanWrite() {
@@ -324,8 +303,7 @@ void QuicTimeWaitListManager::SendPublicReset(
if (ietf_quic) {
std::unique_ptr<QuicEncryptedPacket> ietf_reset_packet =
BuildIetfStatelessResetPacket(connection_id, received_packet_length);
- if (GetQuicRestartFlag(quic_fix_stateless_reset2) &&
- ietf_reset_packet == nullptr) {
+ if (ietf_reset_packet == nullptr) {
// This could happen when trying to reject a short header packet of
// a connection which is in the time wait list (and with no termination
// packet).
@@ -392,6 +370,13 @@ bool QuicTimeWaitListManager::SendOrQueuePacket(
QUIC_LOG(ERROR) << "Tried to send or queue a null packet";
return true;
}
+ if (GetQuicReloadableFlag(quic_add_upperbound_for_queued_packets) &&
+ pending_packets_queue_.size() >=
+ GetQuicFlag(FLAGS_quic_time_wait_list_max_pending_packets)) {
+ // There are too many pending packets.
+ QUIC_CODE_COUNT(quic_too_many_pending_packets_in_time_wait);
+ return true;
+ }
if (WriteToWire(packet.get())) {
// Allow the packet to be deleted upon leaving this function.
return true;
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.h b/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.h
index fe15159d98c..a0844840876 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
@@ -99,14 +99,13 @@ class QUIC_NO_EXPORT QuicTimeWaitListManager
QuicTimeWaitListManager& operator=(const QuicTimeWaitListManager&) = delete;
~QuicTimeWaitListManager() override;
- // Adds the given connection_id to time wait state for time_wait_period_.
- // If |termination_packets| are provided, copies of these packets will be sent
- // when a packet with this connection ID is processed. Any termination packets
- // will be move from |termination_packets| and will become owned by the
- // manager. |action| specifies what the time wait list manager should do when
- // processing packets of the connection.
- virtual void AddConnectionIdToTimeWait(QuicConnectionId connection_id,
- TimeWaitAction action,
+ // Adds the connection IDs in info to time wait state for time_wait_period_.
+ // If |info|.termination_packets are provided, copies of these packets will be
+ // sent when a packet with one of these connection IDs is processed. Any
+ // termination packets will be move from |info|.termination_packets and will
+ // become owned by the manager. |action| specifies what the time wait list
+ // manager should do when processing packets of the connection.
+ virtual void AddConnectionIdToTimeWait(TimeWaitAction action,
TimeWaitConnectionInfo info);
// Returns true if the connection_id is in time wait state, false otherwise.
@@ -337,11 +336,6 @@ class QUIC_NO_EXPORT QuicTimeWaitListManager
// Interface that manages blocked writers.
Visitor* visitor_;
-
- // When this is default true, remove the connection_id argument of
- // AddConnectionIdToTimeWait.
- bool use_indirect_connection_id_map_ =
- GetQuicRestartFlag(quic_time_wait_list_support_multiple_cid_v2);
};
} // namespace quic
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 f47bdf2fed8..36105358e99 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
@@ -157,7 +157,7 @@ class QuicTimeWaitListManagerTest : public QuicTest {
termination_packets.push_back(std::unique_ptr<QuicEncryptedPacket>(
new QuicEncryptedPacket(nullptr, 0, false)));
time_wait_list_manager_.AddConnectionIdToTimeWait(
- connection_id, QuicTimeWaitListManager::SEND_TERMINATION_PACKETS,
+ QuicTimeWaitListManager::SEND_TERMINATION_PACKETS,
TimeWaitConnectionInfo(false, &termination_packets, {connection_id}));
}
@@ -167,9 +167,8 @@ class QuicTimeWaitListManagerTest : public QuicTest {
QuicTimeWaitListManager::TimeWaitAction action,
std::vector<std::unique_ptr<QuicEncryptedPacket>>* packets) {
time_wait_list_manager_.AddConnectionIdToTimeWait(
- connection_id, action,
- TimeWaitConnectionInfo(version.HasIetfInvariantHeader(), packets,
- {connection_id}));
+ action, TimeWaitConnectionInfo(version.HasIetfInvariantHeader(),
+ packets, {connection_id}));
}
bool IsConnectionIdInTimeWait(QuicConnectionId connection_id) {
@@ -450,10 +449,6 @@ TEST_F(QuicTimeWaitListManagerTest, CleanUpOldConnectionIds) {
TEST_F(QuicTimeWaitListManagerTest,
CleanUpOldConnectionIdsForMultipleConnectionIdsPerConnection) {
- if (!GetQuicRestartFlag(quic_time_wait_list_support_multiple_cid_v2)) {
- return;
- }
-
connection_id_ = TestConnectionId(7);
const size_t kConnectionCloseLength = 100;
EXPECT_CALL(visitor_, OnConnectionAddedToTimeWaitList(connection_id_));
@@ -467,7 +462,7 @@ TEST_F(QuicTimeWaitListManagerTest,
std::vector<QuicConnectionId> active_connection_ids{connection_id_,
TestConnectionId(8)};
time_wait_list_manager_.AddConnectionIdToTimeWait(
- connection_id_, QuicTimeWaitListManager::SEND_CONNECTION_CLOSE_PACKETS,
+ QuicTimeWaitListManager::SEND_CONNECTION_CLOSE_PACKETS,
TimeWaitConnectionInfo(/*ietf_quic=*/true, &termination_packets,
active_connection_ids, QuicTime::Delta::Zero()));
@@ -675,7 +670,7 @@ TEST_F(QuicTimeWaitListManagerTest,
std::unique_ptr<QuicEncryptedPacket>(new QuicEncryptedPacket(
new char[kConnectionCloseLength], kConnectionCloseLength, true)));
time_wait_list_manager_.AddConnectionIdToTimeWait(
- connection_id_, QuicTimeWaitListManager::SEND_TERMINATION_PACKETS,
+ QuicTimeWaitListManager::SEND_TERMINATION_PACKETS,
TimeWaitConnectionInfo(/*ietf_quic=*/true, &termination_packets,
{connection_id_}));
@@ -701,7 +696,7 @@ TEST_F(QuicTimeWaitListManagerTest,
new char[kConnectionCloseLength], kConnectionCloseLength, true)));
// Add a CONNECTION_CLOSE termination packet.
time_wait_list_manager_.AddConnectionIdToTimeWait(
- connection_id_, QuicTimeWaitListManager::SEND_CONNECTION_CLOSE_PACKETS,
+ QuicTimeWaitListManager::SEND_CONNECTION_CLOSE_PACKETS,
TimeWaitConnectionInfo(/*ietf_quic=*/true, &termination_packets,
{connection_id_}));
EXPECT_CALL(writer_, WritePacket(_, kConnectionCloseLength,
@@ -717,10 +712,6 @@ TEST_F(QuicTimeWaitListManagerTest,
TEST_F(QuicTimeWaitListManagerTest,
SendConnectionClosePacketsForMultipleConnectionIds) {
- if (!GetQuicRestartFlag(quic_time_wait_list_support_multiple_cid_v2)) {
- return;
- }
-
connection_id_ = TestConnectionId(7);
const size_t kConnectionCloseLength = 100;
EXPECT_CALL(visitor_, OnConnectionAddedToTimeWaitList(connection_id_));
@@ -734,7 +725,7 @@ TEST_F(QuicTimeWaitListManagerTest,
std::vector<QuicConnectionId> active_connection_ids{connection_id_,
TestConnectionId(8)};
time_wait_list_manager_.AddConnectionIdToTimeWait(
- connection_id_, QuicTimeWaitListManager::SEND_CONNECTION_CLOSE_PACKETS,
+ QuicTimeWaitListManager::SEND_CONNECTION_CLOSE_PACKETS,
TimeWaitConnectionInfo(/*ietf_quic=*/true, &termination_packets,
active_connection_ids, QuicTime::Delta::Zero()));
@@ -768,6 +759,37 @@ TEST_F(QuicTimeWaitListManagerTest, SendOrQueueNullPacket) {
nullptr, nullptr);
}
+TEST_F(QuicTimeWaitListManagerTest, TooManyPendingPackets) {
+ SetQuicFlag(FLAGS_quic_time_wait_list_max_pending_packets, 5);
+ const size_t kNumOfUnProcessablePackets = 2048;
+ EXPECT_CALL(visitor_, OnWriteBlocked(&time_wait_list_manager_))
+ .Times(testing::AnyNumber());
+ // Write block for the next packets.
+ EXPECT_CALL(writer_,
+ WritePacket(_, _, self_address_.host(), peer_address_, _))
+ .With(Args<0, 1>(PublicResetPacketEq(TestConnectionId(1))))
+ .WillOnce(DoAll(Assign(&writer_is_blocked_, true),
+ Return(WriteResult(WRITE_STATUS_BLOCKED, EAGAIN))));
+ for (size_t i = 0; i < kNumOfUnProcessablePackets; ++i) {
+ time_wait_list_manager_.SendPublicReset(
+ self_address_, peer_address_, TestConnectionId(1),
+ /*ietf_quic=*/true,
+ /*received_packet_length=*/
+ QuicFramer::GetMinStatelessResetPacketLength() + 1,
+ /*packet_context=*/nullptr);
+ }
+ if (GetQuicReloadableFlag(quic_add_upperbound_for_queued_packets)) {
+ // Verify pending packet queue size is limited.
+ EXPECT_EQ(5u, QuicTimeWaitListManagerPeer::PendingPacketsQueueSize(
+ &time_wait_list_manager_));
+ } else {
+ // The pending packet queue grows unbounded.
+ EXPECT_EQ(kNumOfUnProcessablePackets,
+ QuicTimeWaitListManagerPeer::PendingPacketsQueueSize(
+ &time_wait_list_manager_));
+ }
+}
+
} // namespace
} // namespace test
} // 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 eb4db074ef4..edfa78b5e76 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
@@ -56,6 +56,10 @@ using StatelessResetToken = std::array<char, kStatelessResetTokenLength>;
// WebTransport session IDs are stream IDs.
using WebTransportSessionId = uint64_t;
+// WebTransport stream reset codes are 8-bit.
+using WebTransportStreamError = uint8_t;
+// WebTransport session error codes are 32-bit.
+using WebTransportSessionError = uint32_t;
enum : size_t { kQuicPathFrameBufferSize = 8 };
using QuicPathFrameBuffer = std::array<uint8_t, kQuicPathFrameBufferSize>;
@@ -79,8 +83,7 @@ struct QUIC_EXPORT_PRIVATE QuicConsumedData {
// default gtest object printer to read uninitialize memory. So we need
// to teach gtest how to print this object.
QUIC_EXPORT_PRIVATE friend std::ostream& operator<<(
- std::ostream& os,
- const QuicConsumedData& s);
+ std::ostream& os, const QuicConsumedData& s);
// How many bytes were consumed.
size_t bytes_consumed;
@@ -198,8 +201,7 @@ QUIC_EXPORT_PRIVATE std::string TransmissionTypeToString(
TransmissionType transmission_type);
QUIC_EXPORT_PRIVATE std::ostream& operator<<(
- std::ostream& os,
- TransmissionType transmission_type);
+ std::ostream& os, TransmissionType transmission_type);
enum HasRetransmittableData : uint8_t {
NO_RETRANSMITTABLE_DATA,
@@ -220,8 +222,7 @@ 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);
+ std::ostream& os, const ConnectionCloseSource& connection_close_source);
// Should a connection be closed silently or not.
enum class ConnectionCloseBehavior {
@@ -233,8 +234,7 @@ enum class ConnectionCloseBehavior {
QUIC_EXPORT_PRIVATE std::string ConnectionCloseBehaviorToString(
ConnectionCloseBehavior connection_close_behavior);
QUIC_EXPORT_PRIVATE std::ostream& operator<<(
- std::ostream& os,
- const ConnectionCloseBehavior& connection_close_behavior);
+ std::ostream& os, const ConnectionCloseBehavior& connection_close_behavior);
enum QuicFrameType : uint8_t {
// Regular frame types. The values set here cannot change without the
@@ -338,7 +338,12 @@ enum QuicIetfFrameType : uint64_t {
IETF_EXTENSION_MESSAGE_V99 = 0x31,
// An QUIC extension frame for sender control of acknowledgement delays
- IETF_ACK_FREQUENCY = 0xaf
+ IETF_ACK_FREQUENCY = 0xaf,
+
+ // A QUIC extension frame which augments the IETF_ACK frame definition with
+ // packet receive timestamps.
+ // TODO(ianswett): Determine a proper value to replace this temporary value.
+ IETF_ACK_RECEIVE_TIMESTAMPS = 0x22,
};
QUIC_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
const QuicIetfFrameType& c);
@@ -574,8 +579,7 @@ struct QUIC_EXPORT_PRIVATE AckedPacket {
receive_timestamp(receive_timestamp) {}
friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(
- std::ostream& os,
- const AckedPacket& acked_packet);
+ std::ostream& os, const AckedPacket& acked_packet);
QuicPacketNumber packet_number;
// Number of bytes sent in the packet that was acknowledged.
@@ -595,8 +599,7 @@ struct QUIC_EXPORT_PRIVATE LostPacket {
: packet_number(packet_number), bytes_lost(bytes_lost) {}
friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(
- std::ostream& os,
- const LostPacket& lost_packet);
+ std::ostream& os, const LostPacket& lost_packet);
QuicPacketNumber packet_number;
// Number of bytes sent in the packet that was lost.
@@ -681,7 +684,7 @@ enum WriteStreamDataResult {
WRITE_FAILED, // Trying to write nonexistent data of a stream
};
-enum StreamType {
+enum StreamType : uint8_t {
// Bidirectional streams allow for data to be sent in both directions.
BIDIRECTIONAL,
@@ -744,8 +747,7 @@ enum QuicConnectionCloseType {
};
QUIC_EXPORT_PRIVATE std::ostream& operator<<(
- std::ostream& os,
- const QuicConnectionCloseType type);
+ std::ostream& os, const QuicConnectionCloseType type);
QUIC_EXPORT_PRIVATE std::string QuicConnectionCloseTypeString(
QuicConnectionCloseType type);
@@ -838,6 +840,9 @@ QUIC_EXPORT_PRIVATE std::string KeyUpdateReasonString(KeyUpdateReason reason);
struct QUIC_NO_EXPORT QuicSSLConfig {
// Whether TLS early data should be enabled. If not set, default to enabled.
absl::optional<bool> early_data_enabled;
+ // Whether TLS session tickets are supported. If not set, default to
+ // supported.
+ absl::optional<bool> disable_ticket_support;
// If set, used to configure the SSL object with
// SSL_set_signing_algorithm_prefs.
absl::optional<absl::InlinedVector<uint16_t, 8>> signing_algorithm_prefs;
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map.cc b/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map.cc
index 9f9919c1be9..dada106a6a4 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map.cc
@@ -159,7 +159,13 @@ void QuicUnackedPacketMap::AddSentPacket(SerializedPacket* mutable_packet,
largest_sent_largest_acked_.UpdateMax(packet.largest_acked);
if (!measure_rtt) {
- QUIC_BUG_IF(quic_bug_12645_2, set_in_flight);
+ QUIC_BUG_IF(quic_bug_12645_2, set_in_flight)
+ << "Packet " << mutable_packet->packet_number << ", transmission type "
+ << TransmissionTypeToString(mutable_packet->transmission_type)
+ << ", retransmittable frames: "
+ << QuicFramesToString(mutable_packet->retransmittable_frames)
+ << ", nonretransmittable_frames: "
+ << QuicFramesToString(mutable_packet->nonretransmittable_frames);
info.state = NOT_CONTRIBUTING_RTT;
}
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 911370f2618..58c0c51d55a 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
@@ -15,17 +15,27 @@ namespace quic {
QuicVersionManager::QuicVersionManager(
ParsedQuicVersionVector supported_versions)
- : disable_version_rfcv1_(GetQuicReloadableFlag(quic_disable_version_rfcv1)),
+ : lazy_(GetQuicRestartFlag(quic_lazy_quic_version_manager)),
+ disable_version_rfcv1_(
+ lazy_ ? true : GetQuicReloadableFlag(quic_disable_version_rfcv1)),
disable_version_draft_29_(
- GetQuicReloadableFlag(quic_disable_version_draft_29)),
- disable_version_t051_(GetQuicReloadableFlag(quic_disable_version_t051)),
- disable_version_q050_(GetQuicReloadableFlag(quic_disable_version_q050)),
- disable_version_q046_(GetQuicReloadableFlag(quic_disable_version_q046)),
- disable_version_q043_(GetQuicReloadableFlag(quic_disable_version_q043)),
+ lazy_ ? true : GetQuicReloadableFlag(quic_disable_version_draft_29)),
+ disable_version_t051_(
+ lazy_ ? true : GetQuicReloadableFlag(quic_disable_version_t051)),
+ disable_version_q050_(
+ lazy_ ? true : GetQuicReloadableFlag(quic_disable_version_q050)),
+ disable_version_q046_(
+ lazy_ ? true : GetQuicReloadableFlag(quic_disable_version_q046)),
+ disable_version_q043_(
+ lazy_ ? true : GetQuicReloadableFlag(quic_disable_version_q043)),
allowed_supported_versions_(std::move(supported_versions)) {
static_assert(SupportedVersions().size() == 6u,
"Supported versions out of sync");
- RefilterSupportedVersions();
+ if (lazy_) {
+ QUIC_RESTART_FLAG_COUNT(quic_lazy_quic_version_manager);
+ } else {
+ RefilterSupportedVersions();
+ }
}
QuicVersionManager::~QuicVersionManager() {}
@@ -36,6 +46,12 @@ const ParsedQuicVersionVector& QuicVersionManager::GetSupportedVersions() {
}
const ParsedQuicVersionVector&
+QuicVersionManager::GetSupportedVersionsWithOnlyHttp3() {
+ MaybeRefilterSupportedVersions();
+ return filtered_supported_versions_with_http3_;
+}
+
+const ParsedQuicVersionVector&
QuicVersionManager::GetSupportedVersionsWithQuicCrypto() {
MaybeRefilterSupportedVersions();
return filtered_supported_versions_with_quic_crypto_;
@@ -76,6 +92,7 @@ void QuicVersionManager::MaybeRefilterSupportedVersions() {
void QuicVersionManager::RefilterSupportedVersions() {
filtered_supported_versions_ =
FilterSupportedVersions(allowed_supported_versions_);
+ filtered_supported_versions_with_http3_.clear();
filtered_supported_versions_with_quic_crypto_.clear();
filtered_transport_versions_.clear();
filtered_supported_alpns_.clear();
@@ -86,6 +103,9 @@ void QuicVersionManager::RefilterSupportedVersions() {
transport_version) == filtered_transport_versions_.end()) {
filtered_transport_versions_.push_back(transport_version);
}
+ if (version.UsesHttp3()) {
+ filtered_supported_versions_with_http3_.push_back(version);
+ }
if (version.handshake_protocol == PROTOCOL_QUIC_CRYPTO) {
filtered_supported_versions_with_quic_crypto_.push_back(version);
}
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 da73f37b910..501ecc5c373 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
@@ -22,6 +22,9 @@ class QUIC_EXPORT_PRIVATE QuicVersionManager {
// as the versions passed to the constructor.
const ParsedQuicVersionVector& GetSupportedVersions();
+ // Returns currently supported versions using HTTP/3.
+ const ParsedQuicVersionVector& GetSupportedVersionsWithOnlyHttp3();
+
// Returns currently supported versions using QUIC crypto.
const ParsedQuicVersionVector& GetSupportedVersionsWithQuicCrypto();
@@ -33,22 +36,31 @@ class QUIC_EXPORT_PRIVATE QuicVersionManager {
// If the value of any reloadable flag is different from the cached value,
// re-filter |filtered_supported_versions_| and update the cached flag values.
// Otherwise, does nothing.
+ // TODO(dschinazi): Make private when deprecating
+ // FLAGS_gfe2_restart_flag_quic_disable_old_alt_svc_format.
void MaybeRefilterSupportedVersions();
// Refilters filtered_supported_versions_.
virtual void RefilterSupportedVersions();
+ // RefilterSupportedVersions() must be called before calling this method.
+ // TODO(dschinazi): Remove when deprecating
+ // FLAGS_gfe2_restart_flag_quic_disable_old_alt_svc_format.
const QuicTransportVersionVector& filtered_transport_versions() const {
return filtered_transport_versions_;
}
- // Mechanism for subclasses to add custom ALPNs to the supported list.
- // Should be called in constructor and RefilterSupportedVersions.
+ // Subclasses may add custom ALPNs to the supported list by overriding
+ // RefilterSupportedVersions() to first call
+ // QuicVersionManager::RefilterSupportedVersions() then AddCustomAlpn().
+ // Must not be called elsewhere.
void AddCustomAlpn(const std::string& alpn);
- bool disable_version_q050() const { return disable_version_q050_; }
-
private:
+ // Cached value of gfe2_restart_flag_quic_lazy_quic_version_manager for
+ // brevity.
+ const bool lazy_;
+
// Cached value of reloadable flags.
// quic_disable_version_rfcv1 flag
bool disable_version_rfcv1_;
@@ -64,10 +76,18 @@ class QUIC_EXPORT_PRIVATE QuicVersionManager {
bool disable_version_q043_;
// The list of versions that may be supported.
- ParsedQuicVersionVector allowed_supported_versions_;
+ const ParsedQuicVersionVector allowed_supported_versions_;
+
+ // The following vectors are calculated from reloadable flags by
+ // RefilterSupportedVersions(). It is performed lazily when first needed, and
+ // after that, since the calculation is relatively expensive, only if the flag
+ // values change.
+
// This vector contains QUIC versions which are currently supported based on
// flags.
ParsedQuicVersionVector filtered_supported_versions_;
+ // Currently supported versions using HTTP/3.
+ ParsedQuicVersionVector filtered_supported_versions_with_http3_;
// Currently supported versions using QUIC crypto.
ParsedQuicVersionVector filtered_supported_versions_with_quic_crypto_;
// This vector contains the transport versions from
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 5776b3916c3..75ceed46b8f 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
@@ -37,6 +37,7 @@ TEST_F(QuicVersionManagerTest, QuicVersionManager) {
EXPECT_EQ(FilterSupportedVersions(AllSupportedVersions()),
manager.GetSupportedVersions());
+ EXPECT_TRUE(manager.GetSupportedVersionsWithOnlyHttp3().empty());
EXPECT_EQ(CurrentSupportedVersionsWithQuicCrypto(),
manager.GetSupportedVersionsWithQuicCrypto());
EXPECT_THAT(manager.GetSupportedAlpns(),
@@ -51,6 +52,9 @@ TEST_F(QuicVersionManagerTest, QuicVersionManager) {
manager.GetSupportedVersionsWithQuicCrypto().size());
EXPECT_EQ(FilterSupportedVersions(AllSupportedVersions()),
manager.GetSupportedVersions());
+ EXPECT_EQ(1u, manager.GetSupportedVersionsWithOnlyHttp3().size());
+ EXPECT_EQ(CurrentSupportedHttp3Versions(),
+ manager.GetSupportedVersionsWithOnlyHttp3());
EXPECT_EQ(CurrentSupportedVersionsWithQuicCrypto(),
manager.GetSupportedVersionsWithQuicCrypto());
EXPECT_THAT(manager.GetSupportedAlpns(),
@@ -65,6 +69,9 @@ TEST_F(QuicVersionManagerTest, QuicVersionManager) {
manager.GetSupportedVersionsWithQuicCrypto().size());
EXPECT_EQ(FilterSupportedVersions(AllSupportedVersions()),
manager.GetSupportedVersions());
+ EXPECT_EQ(1u, manager.GetSupportedVersionsWithOnlyHttp3().size());
+ EXPECT_EQ(CurrentSupportedHttp3Versions(),
+ manager.GetSupportedVersionsWithOnlyHttp3());
EXPECT_EQ(CurrentSupportedVersionsWithQuicCrypto(),
manager.GetSupportedVersionsWithQuicCrypto());
EXPECT_THAT(manager.GetSupportedAlpns(),
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
index c6d04552f43..4b1cf31a8e0 100644
--- 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
@@ -177,7 +177,7 @@ class QUIC_NO_EXPORT TlsChloExtractor
void OnDataAvailable() override;
void OnFinRead() override {}
void AddBytesConsumed(QuicByteCount /*bytes*/) override {}
- void Reset(QuicRstStreamErrorCode /*error*/) override {}
+ void ResetWithError(QuicResetStreamError /*error*/) override {}
void OnUnrecoverableError(QuicErrorCode error,
const std::string& details) override;
void OnUnrecoverableError(QuicErrorCode error,
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 737f449c59f..50ba8148342 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
@@ -74,13 +74,14 @@ bool TlsClientHandshaker::CryptoConnect() {
// TODO(b/193650832) Add SetFromConfig to QUIC handshakers and remove reliance
// on session pointer.
- if (session()->permutes_tls_extensions()) {
- // Ask BoringSSL to randomize the order of TLS extensions.
+ const bool permutes_tls_extensions = session()->permutes_tls_extensions();
+ if (!permutes_tls_extensions) {
+ QUIC_DLOG(INFO) << "Disabling TLS extension permutation";
+ }
#if BORINGSSL_API_VERSION >= 16
- QUIC_DLOG(INFO) << "Enabling TLS extension permutation";
- SSL_set_permute_extensions(ssl(), true);
+ // Ask BoringSSL to randomize the order of TLS extensions.
+ SSL_set_permute_extensions(ssl(), permutes_tls_extensions);
#endif // BORINGSSL_API_VERSION
- }
// Set the SNI to send, if any.
SSL_set_connect_state(ssl());
@@ -325,6 +326,13 @@ std::string TlsClientHandshaker::chlo_hash() const {
return "";
}
+bool TlsClientHandshaker::ExportKeyingMaterial(absl::string_view label,
+ absl::string_view context,
+ size_t result_len,
+ std::string* result) {
+ return ExportKeyingMaterialForLabel(label, context, result_len, result);
+}
+
bool TlsClientHandshaker::encryption_established() const {
return encryption_established_;
}
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 eb39ccf9fab..4543f9b2007 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
@@ -50,6 +50,8 @@ class QUIC_EXPORT_PRIVATE TlsClientHandshaker
bool ReceivedInchoateReject() const override;
int num_scup_messages_received() const override;
std::string chlo_hash() const override;
+ bool ExportKeyingMaterial(absl::string_view label, absl::string_view context,
+ size_t result_len, std::string* result) override;
// From QuicCryptoClientStream::HandshakerInterface and TlsHandshaker
bool encryption_established() const override;
@@ -81,8 +83,9 @@ class QUIC_EXPORT_PRIVATE TlsClientHandshaker
void AllowEmptyAlpnForTests() { allow_empty_alpn_for_tests_ = true; }
void AllowInvalidSNIForTests() { allow_invalid_sni_for_tests_ = true; }
- SSL* GetSslForTests() { return tls_connection_.ssl(); }
- const SSL* GetSslForTests() const { return tls_connection_.ssl(); }
+
+ // Make the SSL object from BoringSSL publicly accessible.
+ using TlsHandshaker::ssl;
protected:
const TlsConnection* tls_connection() const override {
diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_handshaker.cc b/chromium/net/third_party/quiche/src/quic/core/tls_handshaker.cc
index 4b2d717befc..dee634ba2cc 100644
--- a/chromium/net/third_party/quiche/src/quic/core/tls_handshaker.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/tls_handshaker.cc
@@ -328,6 +328,23 @@ std::unique_ptr<QuicEncrypter> TlsHandshaker::CreateCurrentOneRttEncrypter() {
return encrypter;
}
+bool TlsHandshaker::ExportKeyingMaterialForLabel(absl::string_view label,
+ absl::string_view context,
+ size_t result_len,
+ std::string* result) {
+ // TODO(haoyuewang) Adding support of keying material export when 0-RTT is
+ // accepted.
+ if (SSL_in_init(ssl())) {
+ return false;
+ }
+ result->resize(result_len);
+ return SSL_export_keying_material(
+ ssl(), reinterpret_cast<uint8_t*>(&*result->begin()), result_len,
+ label.data(), label.size(),
+ reinterpret_cast<const uint8_t*>(context.data()), context.size(),
+ !context.empty()) == 1;
+}
+
void TlsHandshaker::WriteMessage(EncryptionLevel level,
absl::string_view data) {
stream_->WriteCryptoData(level, data);
diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_handshaker.h b/chromium/net/third_party/quiche/src/quic/core/tls_handshaker.h
index 72ae0993983..33355649550 100644
--- a/chromium/net/third_party/quiche/src/quic/core/tls_handshaker.h
+++ b/chromium/net/third_party/quiche/src/quic/core/tls_handshaker.h
@@ -53,6 +53,9 @@ class QUIC_EXPORT_PRIVATE TlsHandshaker : public TlsConnection::Delegate,
std::unique_ptr<QuicDecrypter> AdvanceKeysAndCreateCurrentOneRttDecrypter();
std::unique_ptr<QuicEncrypter> CreateCurrentOneRttEncrypter();
virtual HandshakeState GetHandshakeState() const = 0;
+ bool ExportKeyingMaterialForLabel(absl::string_view label,
+ absl::string_view context,
+ size_t result_len, std::string* result);
protected:
// Called when a new message is received on the crypto stream and is available
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 b2817b15b22..4e47a6395ce 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
@@ -77,13 +77,15 @@ TlsServerHandshaker::DefaultProofSourceHandle::SelectCertificate(
return QUIC_FAILURE;
}
+ bool cert_matched_sni;
QuicReferenceCountedPointer<ProofSource::Chain> chain =
- proof_source_->GetCertChain(server_address, client_address, hostname);
+ proof_source_->GetCertChain(server_address, client_address, hostname,
+ &cert_matched_sni);
handshaker_->OnSelectCertificateDone(
/*ok=*/true, /*is_sync=*/true, chain.get(),
/*handshake_hints=*/absl::string_view(),
- /*ticket_encryption_key=*/absl::string_view());
+ /*ticket_encryption_key=*/absl::string_view(), cert_matched_sni);
if (!handshaker_->select_cert_status().has_value()) {
QUIC_BUG(quic_bug_12423_1)
<< "select_cert_status() has no value after a synchronous select cert";
@@ -138,26 +140,42 @@ void TlsServerHandshaker::DecryptCallback::Run(std::vector<uint8_t> plaintext) {
// The callback was cancelled before we could run.
return;
}
- handshaker_->decrypted_session_ticket_ = std::move(plaintext);
+
+ TlsServerHandshaker* handshaker = handshaker_;
+ handshaker_ = nullptr;
+
+ handshaker->decrypted_session_ticket_ = std::move(plaintext);
+ const bool is_async =
+ (handshaker->expected_ssl_error() == SSL_ERROR_PENDING_TICKET);
+
+ absl::optional<QuicConnectionContextSwitcher> context_switcher;
+ if (handshaker->restore_connection_context_in_callbacks_) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(
+ quic_tls_restore_connection_context_in_callbacks, 1, 3);
+ if (is_async) {
+ context_switcher.emplace(handshaker->connection_context());
+ }
+ QUIC_TRACESTRING(
+ absl::StrCat("TLS ticket decryption done. len(decrypted_ticket):",
+ handshaker->decrypted_session_ticket_.size()));
+ }
+
// 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.
+ // (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
+ // 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_->expected_ssl_error() == SSL_ERROR_PENDING_TICKET) {
- handshaker_->AdvanceHandshakeFromCallback();
- }
- // 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;
+ if (is_async) {
+ handshaker->AdvanceHandshakeFromCallback();
+ }
+
+ handshaker->ticket_decryption_callback_ = nullptr;
}
void TlsServerHandshaker::DecryptCallback::Cancel() {
@@ -188,13 +206,15 @@ TlsServerHandshaker::TlsServerHandshaker(
}
SSL_set_quic_use_legacy_codepoint(ssl(), use_legacy_extension);
- if (GetQuicFlag(FLAGS_quic_disable_server_tls_resumption)) {
- SSL_set_options(ssl(), SSL_OP_NO_TICKET);
+ if (!session->quic_tls_disable_resumption_refactor()) {
+ if (GetQuicFlag(FLAGS_quic_disable_server_tls_resumption)) {
+ SSL_set_options(ssl(), SSL_OP_NO_TICKET);
+ }
+ } else {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_tls_disable_resumption_refactor);
}
- if (GetQuicReloadableFlag(quic_trace_ssl_events) &&
- session->connection()->context()->tracer) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_trace_ssl_events);
+ if (session->connection()->context()->tracer) {
tls_connection_.EnableInfoCallback();
}
}
@@ -337,10 +357,19 @@ bool TlsServerHandshaker::ShouldSendExpectCTHeader() const {
return false;
}
+bool TlsServerHandshaker::DidCertMatchSni() const { return cert_matched_sni_; }
+
const ProofSource::Details* TlsServerHandshaker::ProofSourceDetails() const {
return proof_source_details_.get();
}
+bool TlsServerHandshaker::ExportKeyingMaterial(absl::string_view label,
+ absl::string_view context,
+ size_t result_len,
+ std::string* result) {
+ return ExportKeyingMaterialForLabel(label, context, result_len, result);
+}
+
void TlsServerHandshaker::OnConnectionClosed(QuicErrorCode error,
ConnectionCloseSource source) {
TlsHandshaker::OnConnectionClosed(error, source);
@@ -663,6 +692,19 @@ void TlsServerHandshaker::OnComputeSignatureDone(
QUIC_DVLOG(1) << "OnComputeSignatureDone. ok:" << ok
<< ", is_sync:" << is_sync
<< ", len(signature):" << signature.size();
+ absl::optional<QuicConnectionContextSwitcher> context_switcher;
+ if (restore_connection_context_in_callbacks_) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(
+ quic_tls_restore_connection_context_in_callbacks, 2, 3);
+
+ if (!is_sync) {
+ context_switcher.emplace(connection_context());
+ }
+
+ QUIC_TRACESTRING(absl::StrCat("TLS compute signature done. ok:", ok,
+ ", len(signature):", signature.size()));
+ }
+
if (ok) {
cert_verify_sig_ = std::move(signature);
proof_source_details_ = std::move(details);
@@ -713,7 +755,7 @@ ssl_ticket_aead_result_t TlsServerHandshaker::SessionTicketOpen(
absl::string_view in) {
QUICHE_DCHECK(proof_source_->GetTicketCrypter());
- if (allow_ignore_ticket_open_ && ignore_ticket_open_) {
+ if (ignore_ticket_open_) {
// SetIgnoreTicketOpen has been called. Typically this means the caller is
// using handshake hints and expect the hints to contain ticket decryption
// results.
@@ -722,21 +764,20 @@ ssl_ticket_aead_result_t TlsServerHandshaker::SessionTicketOpen(
}
if (!ticket_decryption_callback_) {
- if (!allow_ignore_ticket_open_) {
- ticket_received_ = true;
- }
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.
+ // returning ssl_ticket_aead_retry, we should continue processing to
+ // return the decrypted ticket.
//
// If the callback is not run synchronously, 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_) {
+ QUICHE_DCHECK(!ticket_decryption_callback_->IsDone());
set_expected_ssl_error(SSL_ERROR_PENDING_TICKET);
if (async_op_timer_.has_value()) {
QUIC_CODE_COUNT(
@@ -744,10 +785,16 @@ ssl_ticket_aead_result_t TlsServerHandshaker::SessionTicketOpen(
}
async_op_timer_ = QuicTimeAccumulator();
async_op_timer_->Start(now());
- return ssl_ticket_aead_retry;
}
}
+ // If the async ticket decryption is pending, either started by this
+ // SessionTicketOpen call or one that happened earlier, return
+ // ssl_ticket_aead_retry.
+ if (ticket_decryption_callback_ && !ticket_decryption_callback_->IsDone()) {
+ return ssl_ticket_aead_retry;
+ }
+
ssl_ticket_aead_result_t result =
FinalizeSessionTicketOpen(out, out_len, max_out_len);
@@ -817,8 +864,7 @@ ssl_select_cert_result_t TlsServerHandshaker::EarlySelectCertCallback(
return ssl_select_cert_error;
}
- if (allow_ignore_ticket_open_) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_tls_allow_ignore_ticket_open);
+ {
const uint8_t* unused_extension_bytes;
size_t unused_extension_len;
ticket_received_ = SSL_early_callback_ctx_extension_get(
@@ -919,15 +965,30 @@ ssl_select_cert_result_t TlsServerHandshaker::EarlySelectCertCallback(
void TlsServerHandshaker::OnSelectCertificateDone(
bool ok, bool is_sync, const ProofSource::Chain* chain,
- absl::string_view handshake_hints,
- absl::string_view ticket_encryption_key) {
+ absl::string_view handshake_hints, absl::string_view ticket_encryption_key,
+ bool cert_matched_sni) {
QUIC_DVLOG(1) << "OnSelectCertificateDone. ok:" << ok
<< ", is_sync:" << is_sync
<< ", len(handshake_hints):" << handshake_hints.size()
<< ", len(ticket_encryption_key):"
<< ticket_encryption_key.size();
+ absl::optional<QuicConnectionContextSwitcher> context_switcher;
+ if (restore_connection_context_in_callbacks_) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(
+ quic_tls_restore_connection_context_in_callbacks, 3, 3);
+
+ if (!is_sync) {
+ context_switcher.emplace(connection_context());
+ }
+
+ QUIC_TRACESTRING(absl::StrCat(
+ "TLS select certificate done: ok:", ok,
+ ", len(handshake_hints):", handshake_hints.size(),
+ ", len(ticket_encryption_key):", ticket_encryption_key.size()));
+ }
ticket_encryption_key_ = std::string(ticket_encryption_key);
select_cert_status_ = QUIC_FAILURE;
+ cert_matched_sni_ = cert_matched_sni;
if (ok) {
if (chain && !chain->certs.empty()) {
tls_connection_.SetCertChain(chain->ToCryptoBuffers().value);
@@ -945,7 +1006,9 @@ void TlsServerHandshaker::OnSelectCertificateDone(
} else {
QUIC_LOG(ERROR) << "No certs provided for host '"
<< crypto_negotiated_params_->sni << "', server_address:"
- << session()->connection()->self_address();
+ << session()->connection()->self_address()
+ << ", client_address:"
+ << session()->connection()->peer_address();
}
}
@@ -1047,14 +1110,11 @@ TlsServerHandshaker::SetApplicationSettings(absl::string_view alpn) {
const std::string& hostname = crypto_negotiated_params_->sni;
std::string accept_ch_value = GetAcceptChValueForHostname(hostname);
std::string origin = absl::StrCat("https://", hostname);
- if (GetQuicReloadableFlag(quic_include_port_in_alps_origin)) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_include_port_in_alps_origin);
- uint16_t port = session()->self_address().port();
- if (port != kDefaultPort) {
- // This should be rare in production, but useful for test servers.
- QUIC_CODE_COUNT(quic_server_alps_non_default_port);
- absl::StrAppend(&origin, ":", port);
- }
+ uint16_t port = session()->self_address().port();
+ if (port != kDefaultPort) {
+ // This should be rare in production, but useful for test servers.
+ QUIC_CODE_COUNT(quic_server_alps_non_default_port);
+ absl::StrAppend(&origin, ":", port);
}
if (!accept_ch_value.empty()) {
@@ -1075,4 +1135,6 @@ TlsServerHandshaker::SetApplicationSettings(absl::string_view alpn) {
return result;
}
+SSL* TlsServerHandshaker::GetSsl() const { return ssl(); }
+
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.h b/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.h
index 998cc15ad7c..b7179a76607 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
@@ -62,7 +62,11 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker
bool ValidateAddressToken(absl::string_view token) const override;
void OnNewTokenReceived(absl::string_view token) override;
bool ShouldSendExpectCTHeader() const override;
+ bool DidCertMatchSni() const override;
const ProofSource::Details* ProofSourceDetails() const override;
+ bool ExportKeyingMaterial(absl::string_view label, absl::string_view context,
+ size_t result_len, std::string* result) override;
+ SSL* GetSsl() const override;
// From QuicCryptoServerStreamBase and TlsHandshaker
ssl_early_data_reason_t EarlyDataReason() const override;
@@ -169,10 +173,11 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker
bool HasValidSignature(size_t max_signature_size) const;
// ProofSourceHandleCallback implementation:
- void OnSelectCertificateDone(
- bool ok, bool is_sync, const ProofSource::Chain* chain,
- absl::string_view handshake_hints,
- absl::string_view ticket_encryption_key) override;
+ void OnSelectCertificateDone(bool ok, bool is_sync,
+ const ProofSource::Chain* chain,
+ absl::string_view handshake_hints,
+ absl::string_view ticket_encryption_key,
+ bool cert_matched_sni) override;
void OnComputeSignatureDone(
bool ok,
@@ -188,9 +193,6 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker
void SetIgnoreTicketOpen(bool value) { ignore_ticket_open_ = value; }
- const bool allow_ignore_ticket_open_ =
- GetQuicReloadableFlag(quic_tls_allow_ignore_ticket_open);
-
private:
class QUIC_EXPORT_PRIVATE DecryptCallback
: public ProofSource::DecryptCallback {
@@ -201,6 +203,11 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker
// If called, Cancel causes the pending callback to be a no-op.
void Cancel();
+ // Return true if either
+ // - Cancel() has been called.
+ // - Run() has been called, or is in the middle of it.
+ bool IsDone() const { return handshaker_ == nullptr; }
+
private:
TlsServerHandshaker* handshaker_;
};
@@ -259,22 +266,12 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker
return;
}
- if (GetQuicReloadableFlag(quic_run_default_signature_callback_once)) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_run_default_signature_callback_once);
- DefaultProofSourceHandle* handle = handle_;
- handle_ = nullptr;
-
- handle->signature_callback_ = nullptr;
- if (handle->handshaker_ != nullptr) {
- handle->handshaker_->OnComputeSignatureDone(
- ok, is_sync_, std::move(signature), std::move(details));
- }
- return;
- }
+ DefaultProofSourceHandle* handle = handle_;
+ handle_ = nullptr;
- handle_->signature_callback_ = nullptr;
- if (handle_->handshaker_ != nullptr) {
- handle_->handshaker_->OnComputeSignatureDone(
+ handle->signature_callback_ = nullptr;
+ if (handle->handshaker_ != nullptr) {
+ handle->handshaker_->OnComputeSignatureDone(
ok, is_sync_, std::move(signature), std::move(details));
}
}
@@ -321,6 +318,11 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker
}
QuicTime now() const { return session()->GetClock()->Now(); }
+ QuicConnectionContext* connection_context() {
+ QUICHE_DCHECK(restore_connection_context_in_callbacks_);
+ return session()->connection()->context();
+ }
+
std::unique_ptr<ProofSourceHandle> proof_source_handle_;
ProofSource* proof_source_;
@@ -365,6 +367,10 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker
crypto_negotiated_params_;
TlsServerConnection tls_connection_;
const QuicCryptoServerConfig* crypto_config_; // Unowned.
+ const bool restore_connection_context_in_callbacks_ =
+ GetQuicReloadableFlag(quic_tls_restore_connection_context_in_callbacks);
+
+ bool cert_matched_sni_ = false;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker_test.cc b/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker_test.cc
index 6f8db123c99..bf68c8513f9 100644
--- a/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker_test.cc
@@ -101,6 +101,7 @@ class TestTlsServerHandshaker : public TlsServerHandshaker {
return fake_proof_source_handle_;
}
+ using TlsServerHandshaker::AdvanceHandshake;
using TlsServerHandshaker::expected_ssl_error;
private:
@@ -565,7 +566,7 @@ TEST_P(TlsServerHandshakerTest, SSLConfigForCertSelection) {
InitializeServerWithFakeProofSourceHandle();
// Disable early data.
- server_session_->ssl_config()->early_data_enabled = false;
+ server_session_->set_early_data_enabled(false);
server_handshaker_->SetupProofSourceHandle(
/*select_cert_action=*/FakeProofSourceHandle::Action::DELEGATE_SYNC,
@@ -708,6 +709,41 @@ TEST_P(TlsServerHandshakerTest, ResumptionWithAsyncDecryptCallback) {
EXPECT_TRUE(server_stream()->ResumptionAttempted());
}
+TEST_P(TlsServerHandshakerTest, AdvanceHandshakeDuringAsyncDecryptCallback) {
+ if (GetParam().disable_resumption) {
+ return;
+ }
+
+ // Do the first handshake
+ InitializeFakeClient();
+ CompleteCryptoHandshake();
+ ExpectHandshakeSuccessful();
+
+ ticket_crypter_->SetRunCallbacksAsync(true);
+ // Now do another handshake
+ InitializeServerWithFakeProofSourceHandle();
+ server_handshaker_->SetupProofSourceHandle(
+ /*select_cert_action=*/FakeProofSourceHandle::Action::DELEGATE_SYNC,
+ /*compute_signature_action=*/FakeProofSourceHandle::Action::
+ DELEGATE_SYNC);
+ InitializeFakeClient();
+
+ AdvanceHandshakeWithFakeClient();
+
+ // Ensure an async DecryptCallback is now pending.
+ ASSERT_EQ(ticket_crypter_->NumPendingCallbacks(), 1u);
+
+ {
+ QuicConnection::ScopedPacketFlusher flusher(server_connection_);
+ server_handshaker_->AdvanceHandshake();
+ }
+
+ // This will delete |server_handshaker_|.
+ server_session_ = nullptr;
+
+ ticket_crypter_->RunPendingCallback(0); // Should not crash.
+}
+
TEST_P(TlsServerHandshakerTest, ResumptionWithFailingDecryptCallback) {
if (GetParam().disable_resumption) {
return;
diff --git a/chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager_test.cc
index cf612feab1d..77731fb2d47 100644
--- a/chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager_test.cc
@@ -368,7 +368,6 @@ TEST_F(UberReceivedPacketManagerTest,
EXPECT_FALSE(HasPendingAck());
QuicConfig config;
QuicTagVector connection_options;
- connection_options.push_back(kACKD);
// No limit on the number of packets received before sending an ack.
connection_options.push_back(kAKDU);
config.SetConnectionOptionsToSend(connection_options);
diff --git a/chromium/net/third_party/quiche/src/quic/core/web_transport_interface.h b/chromium/net/third_party/quiche/src/quic/core/web_transport_interface.h
index 154d242b1e8..102fd1fccef 100644
--- a/chromium/net/third_party/quiche/src/quic/core/web_transport_interface.h
+++ b/chromium/net/third_party/quiche/src/quic/core/web_transport_interface.h
@@ -16,6 +16,7 @@
#include "quic/core/quic_datagram_queue.h"
#include "quic/core/quic_types.h"
#include "quic/platform/api/quic_export.h"
+#include "spdy/core/spdy_header_block.h"
namespace quic {
@@ -28,6 +29,14 @@ class QUIC_EXPORT_PRIVATE WebTransportStreamVisitor {
virtual void OnCanRead() = 0;
// Called whenever the stream is not write-blocked and can accept new data.
virtual void OnCanWrite() = 0;
+
+ // Called when RESET_STREAM is received for the stream.
+ virtual void OnResetStreamReceived(WebTransportStreamError error) = 0;
+ // Called when STOP_SENDING is received for the stream.
+ virtual void OnStopSendingReceived(WebTransportStreamError error) = 0;
+ // Called when the write side of the stream is closed and all of the data sent
+ // has been acknowledged ("Data Recvd" state of RFC 9000).
+ virtual void OnWriteSideInDataRecvdState() = 0;
};
// A stream (either bidirectional or unidirectional) that is contained within a
@@ -66,9 +75,9 @@ class QUIC_EXPORT_PRIVATE WebTransportStream {
virtual QuicStreamId GetStreamId() const = 0;
// Resets the stream with the specified error code.
- // TODO(b/184048994): change the error code type based on IETF consensus.
- virtual void ResetWithUserCode(QuicRstStreamErrorCode error) = 0;
+ virtual void ResetWithUserCode(WebTransportStreamError error) = 0;
virtual void ResetDueToInternalError() = 0;
+ virtual void SendStopSending(WebTransportStreamError error) = 0;
// Called when the owning object has been garbage-collected.
virtual void MaybeResetDueToStreamObjectGone() = 0;
@@ -84,7 +93,11 @@ class QUIC_EXPORT_PRIVATE WebTransportVisitor {
// Notifies the visitor when the session is ready to exchange application
// data.
- virtual void OnSessionReady() = 0;
+ virtual void OnSessionReady(const spdy::SpdyHeaderBlock& headers) = 0;
+
+ // Notifies the visitor when the session has been closed.
+ virtual void OnSessionClosed(WebTransportSessionError error_code,
+ const std::string& error_message) = 0;
// Notifies the visitor when a new stream has been received. The stream in
// question can be retrieved using AcceptIncomingBidirectionalStream() or
@@ -105,6 +118,11 @@ class QUIC_EXPORT_PRIVATE WebTransportSession {
public:
virtual ~WebTransportSession() {}
+ // Closes the WebTransport session in question with the specified |error_code|
+ // and |error_message|.
+ virtual void CloseSession(WebTransportSessionError error_code,
+ absl::string_view error_message) = 0;
+
// Return the earliest incoming stream that has been received by the session
// but has not been accepted. Returns nullptr if there are no incoming
// streams.
@@ -120,6 +138,9 @@ class QUIC_EXPORT_PRIVATE WebTransportSession {
virtual WebTransportStream* OpenOutgoingUnidirectionalStream() = 0;
virtual MessageStatus SendOrQueueDatagram(QuicMemSlice datagram) = 0;
+ // Returns a conservative estimate of the largest datagram size that the
+ // session would be able to send.
+ virtual QuicByteCount GetMaxDatagramSize() const = 0;
// Sets the largest duration that a datagram can spend in the queue before
// being silently dropped.
virtual void SetDatagramMaxTimeInQueue(QuicTime::Delta max_time_in_queue) = 0;
diff --git a/chromium/net/third_party/quiche/src/quic/masque/masque_client_session.cc b/chromium/net/third_party/quiche/src/quic/masque/masque_client_session.cc
index 0d865692e46..19269688a0d 100644
--- a/chromium/net/third_party/quiche/src/quic/masque/masque_client_session.cc
+++ b/chromium/net/third_party/quiche/src/quic/masque/masque_client_session.cc
@@ -3,7 +3,9 @@
// found in the LICENSE file.
#include "quic/masque/masque_client_session.h"
+
#include "absl/algorithm/container.h"
+#include "absl/strings/str_cat.h"
#include "quic/core/http/spdy_utils.h"
#include "quic/core/quic_data_reader.h"
#include "quic/core/quic_utils.h"
@@ -11,20 +13,13 @@
namespace quic {
MasqueClientSession::MasqueClientSession(
- MasqueMode masque_mode,
- const QuicConfig& config,
+ MasqueMode masque_mode, const QuicConfig& config,
const ParsedQuicVersionVector& supported_versions,
- QuicConnection* connection,
- const QuicServerId& server_id,
+ QuicConnection* connection, const QuicServerId& server_id,
QuicCryptoClientConfig* crypto_config,
- QuicClientPushPromiseIndex* push_promise_index,
- Owner* owner)
- : QuicSpdyClientSession(config,
- supported_versions,
- connection,
- server_id,
- crypto_config,
- push_promise_index),
+ QuicClientPushPromiseIndex* push_promise_index, Owner* owner)
+ : QuicSpdyClientSession(config, supported_versions, connection, server_id,
+ crypto_config, push_promise_index),
masque_mode_(masque_mode),
owner_(owner),
compression_engine_(this) {}
@@ -101,7 +96,9 @@ MasqueClientSession::GetOrCreateConnectUdpClientState(
headers[":scheme"] = "masque";
headers[":path"] = "/";
headers[":authority"] = target_server_address.ToString();
- SpdyUtils::AddDatagramFlowIdHeader(&headers, stream->id());
+ if (http_datagram_support() == HttpDatagramSupport::kDraft00) {
+ SpdyUtils::AddDatagramFlowIdHeader(&headers, stream->id());
+ }
size_t bytes_sent =
stream->SendRequest(std::move(headers), /*body=*/"", /*fin=*/false);
if (bytes_sent == 0) {
@@ -118,8 +115,7 @@ MasqueClientSession::GetOrCreateConnectUdpClientState(
void MasqueClientSession::SendPacket(
QuicConnectionId client_connection_id,
- QuicConnectionId server_connection_id,
- absl::string_view packet,
+ QuicConnectionId server_connection_id, absl::string_view packet,
const QuicSocketAddress& target_server_address,
EncapsulatedClientSession* encapsulated_client_session) {
if (masque_mode_ == MasqueMode::kLegacy) {
@@ -142,8 +138,8 @@ void MasqueClientSession::SendPacket(
<< " compressed with stream ID " << connect_udp->stream()->id()
<< " context ID "
<< (connect_udp->context_id().has_value()
- ? connect_udp->context_id().value()
- : 0)
+ ? absl::StrCat(connect_udp->context_id().value())
+ : "none")
<< " and got message status "
<< MessageStatusToString(message_status);
}
@@ -182,8 +178,8 @@ void MasqueClientSession::UnregisterConnectionId(
QUIC_DLOG(INFO) << "Removing state for stream ID " << it->stream()->id()
<< " context ID "
<< (it->context_id().has_value()
- ? it->context_id().value()
- : 0);
+ ? absl::StrCat(it->context_id().value())
+ : "none");
auto* stream = it->stream();
it = connect_udp_client_states_.erase(it);
if (!stream->write_side_closed()) {
@@ -196,8 +192,7 @@ void MasqueClientSession::UnregisterConnectionId(
}
void MasqueClientSession::OnConnectionClosed(
- const QuicConnectionCloseFrame& frame,
- ConnectionCloseSource source) {
+ const QuicConnectionCloseFrame& frame, ConnectionCloseSource source) {
QuicSpdyClientSession::OnConnectionClosed(frame, source);
// Close all encapsulated sessions.
for (const auto& client_state : connect_udp_client_states_) {
@@ -224,8 +219,8 @@ void MasqueClientSession::OnStreamClosed(QuicStreamId stream_id) {
QUIC_DLOG(INFO) << "Stream " << stream_id
<< " was closed, removing state for context ID "
<< (it->context_id().has_value()
- ? it->context_id().value()
- : 0);
+ ? absl::StrCat(it->context_id().value())
+ : "none");
auto* encapsulated_client_session = it->encapsulated_client_session();
it = connect_udp_client_states_.erase(it);
encapsulated_client_session->CloseConnection(
@@ -241,6 +236,7 @@ void MasqueClientSession::OnStreamClosed(QuicStreamId stream_id) {
}
bool MasqueClientSession::OnSettingsFrame(const SettingsFrame& frame) {
+ QUIC_DLOG(INFO) << "Received SETTINGS: " << frame;
if (!QuicSpdyClientSession::OnSettingsFrame(frame)) {
QUIC_DLOG(ERROR) << "Failed to parse received settings";
return false;
@@ -249,6 +245,7 @@ bool MasqueClientSession::OnSettingsFrame(const SettingsFrame& frame) {
QUIC_DLOG(ERROR) << "Refusing to use MASQUE without HTTP/3 Datagrams";
return false;
}
+ QUIC_DLOG(INFO) << "Using HTTP Datagram: " << http_datagram_support();
owner_->OnSettingsReceived();
return true;
}
@@ -266,9 +263,9 @@ MasqueClientSession::ConnectUdpClientState::ConnectUdpClientState(
target_server_address_(target_server_address) {
QUICHE_DCHECK_NE(masque_session_, nullptr);
this->stream()->RegisterHttp3DatagramRegistrationVisitor(this);
- Http3DatagramContextExtensions extensions;
- this->stream()->RegisterHttp3DatagramContextId(this->context_id(), extensions,
- this);
+ this->stream()->RegisterHttp3DatagramContextId(
+ this->context_id(), DatagramFormatType::UDP_PAYLOAD,
+ /*format_additional_data=*/absl::string_view(), this);
}
MasqueClientSession::ConnectUdpClientState::~ConnectUdpClientState() {
@@ -308,24 +305,40 @@ void MasqueClientSession::ConnectUdpClientState::OnHttp3Datagram(
QUIC_DVLOG(1) << "Sent " << payload.size()
<< " bytes to connection for stream ID " << stream_id
<< " context ID "
- << (context_id.has_value() ? context_id.value() : 0);
+ << (context_id.has_value() ? absl::StrCat(context_id.value())
+ : "none");
}
void MasqueClientSession::ConnectUdpClientState::OnContextReceived(
QuicStreamId stream_id, absl::optional<QuicDatagramContextId> context_id,
- const Http3DatagramContextExtensions& /*extensions*/) {
+ DatagramFormatType format_type, absl::string_view format_additional_data) {
if (stream_id != stream_->id()) {
QUIC_BUG(MASQUE client bad datagram context registration)
<< "Registered stream ID " << stream_id << ", expected "
<< stream_->id();
return;
}
+ if (format_type != DatagramFormatType::UDP_PAYLOAD) {
+ QUIC_DLOG(INFO) << "Ignoring unexpected datagram format type "
+ << DatagramFormatTypeToString(format_type);
+ return;
+ }
+ if (!format_additional_data.empty()) {
+ QUIC_DLOG(ERROR)
+ << "Received non-empty format additional data for context ID "
+ << (context_id_.has_value() ? context_id_.value() : 0)
+ << " on stream ID " << stream()->id();
+ masque_session_->ResetStream(stream()->id(), QUIC_STREAM_CANCELLED);
+ return;
+ }
if (context_id != context_id_) {
- QUIC_DLOG(INFO) << "Ignoring unexpected context ID "
- << (context_id.has_value() ? context_id.value() : 0)
- << " instead of "
- << (context_id_.has_value() ? context_id_.value() : 0)
- << " on stream ID " << stream_->id();
+ QUIC_DLOG(INFO)
+ << "Ignoring unexpected context ID "
+ << (context_id.has_value() ? absl::StrCat(context_id.value()) : "none")
+ << " instead of "
+ << (context_id_.has_value() ? absl::StrCat(context_id_.value())
+ : "none")
+ << " on stream ID " << stream_->id();
return;
}
// Do nothing since the client registers first and we currently ignore
@@ -334,7 +347,7 @@ void MasqueClientSession::ConnectUdpClientState::OnContextReceived(
void MasqueClientSession::ConnectUdpClientState::OnContextClosed(
QuicStreamId stream_id, absl::optional<QuicDatagramContextId> context_id,
- const Http3DatagramContextExtensions& /*extensions*/) {
+ ContextCloseCode close_code, absl::string_view close_details) {
if (stream_id != stream_->id()) {
QUIC_BUG(MASQUE client bad datagram context registration)
<< "Closed context on stream ID " << stream_id << ", expected "
@@ -342,15 +355,18 @@ void MasqueClientSession::ConnectUdpClientState::OnContextClosed(
return;
}
if (context_id != context_id_) {
- QUIC_DLOG(INFO) << "Ignoring unexpected close of context ID "
- << (context_id.has_value() ? context_id.value() : 0)
- << " instead of "
- << (context_id_.has_value() ? context_id_.value() : 0)
- << " on stream ID " << stream_->id();
+ QUIC_DLOG(INFO)
+ << "Ignoring unexpected close of context ID "
+ << (context_id.has_value() ? absl::StrCat(context_id.value()) : "none")
+ << " instead of "
+ << (context_id_.has_value() ? absl::StrCat(context_id_.value())
+ : "none")
+ << " on stream ID " << stream_->id();
return;
}
- QUIC_DLOG(INFO) << "Received datagram context close on stream ID "
- << stream_->id() << ", closing stream";
+ QUIC_DLOG(INFO) << "Received datagram context close with close code "
+ << close_code << " close details \"" << close_details
+ << "\" on stream ID " << stream_->id() << ", closing stream";
masque_session_->ResetStream(stream_->id(), QUIC_STREAM_CANCELLED);
}
diff --git a/chromium/net/third_party/quiche/src/quic/masque/masque_client_session.h b/chromium/net/third_party/quiche/src/quic/masque/masque_client_session.h
index 1c130873340..662783a8cdc 100644
--- a/chromium/net/third_party/quiche/src/quic/masque/masque_client_session.h
+++ b/chromium/net/third_party/quiche/src/quic/masque/masque_client_session.h
@@ -144,14 +144,14 @@ class QUIC_NO_EXPORT MasqueClientSession : public QuicSpdyClientSession {
absl::string_view payload) override;
// From QuicSpdyStream::Http3DatagramRegistrationVisitor.
- void OnContextReceived(
- QuicStreamId stream_id,
- absl::optional<QuicDatagramContextId> context_id,
- const Http3DatagramContextExtensions& extensions) override;
- void OnContextClosed(
- QuicStreamId stream_id,
- absl::optional<QuicDatagramContextId> context_id,
- const Http3DatagramContextExtensions& extensions) override;
+ void OnContextReceived(QuicStreamId stream_id,
+ absl::optional<QuicDatagramContextId> context_id,
+ DatagramFormatType format_type,
+ absl::string_view format_additional_data) override;
+ void OnContextClosed(QuicStreamId stream_id,
+ absl::optional<QuicDatagramContextId> context_id,
+ ContextCloseCode close_code,
+ absl::string_view close_details) override;
private:
QuicSpdyClientStream* stream_; // Unowned.
@@ -161,7 +161,9 @@ class QUIC_NO_EXPORT MasqueClientSession : public QuicSpdyClientSession {
QuicSocketAddress target_server_address_;
};
- bool ShouldNegotiateHttp3Datagram() override { return true; }
+ HttpDatagramSupport LocalHttpDatagramSupport() override {
+ return HttpDatagramSupport::kDraft00And04;
+ }
const ConnectUdpClientState* GetOrCreateConnectUdpClientState(
const QuicSocketAddress& target_server_address,
diff --git a/chromium/net/third_party/quiche/src/quic/masque/masque_epoll_client.cc b/chromium/net/third_party/quiche/src/quic/masque/masque_epoll_client.cc
index ec475205ac8..2b835cf05f3 100644
--- a/chromium/net/third_party/quiche/src/quic/masque/masque_epoll_client.cc
+++ b/chromium/net/third_party/quiche/src/quic/masque/masque_epoll_client.cc
@@ -68,7 +68,7 @@ std::unique_ptr<MasqueEpollClient> MasqueEpollClient::Create(
return nullptr;
}
- masque_client->set_initial_max_packet_length(kDefaultMaxPacketSize);
+ masque_client->set_initial_max_packet_length(kMasqueMaxOuterPacketSize);
masque_client->set_drop_response_body(false);
if (!masque_client->Initialize()) {
QUIC_LOG(ERROR) << "Failed to initialize masque_client";
diff --git a/chromium/net/third_party/quiche/src/quic/masque/masque_server_session.cc b/chromium/net/third_party/quiche/src/quic/masque/masque_server_session.cc
index effc17ff316..693f0094a27 100644
--- a/chromium/net/third_party/quiche/src/quic/masque/masque_server_session.cc
+++ b/chromium/net/third_party/quiche/src/quic/masque/masque_server_session.cc
@@ -196,19 +196,20 @@ std::unique_ptr<QuicBackendResponse> MasqueServerSession::HandleMasqueRequest(
}
if (scheme.empty()) {
return CreateBackendErrorResponse("400", "Empty scheme");
- return nullptr;
}
if (method != "CONNECT-UDP") {
QUIC_DLOG(ERROR) << "MASQUE request with bad method \"" << method << "\"";
return CreateBackendErrorResponse("400", "Bad method");
}
- absl::optional<QuicDatagramStreamId> flow_id =
- SpdyUtils::ParseDatagramFlowIdHeader(request_headers);
- if (!flow_id.has_value()) {
- QUIC_DLOG(ERROR)
- << "MASQUE request with bad or missing DatagramFlowId header";
- return CreateBackendErrorResponse("400",
- "Bad or missing DatagramFlowId header");
+ absl::optional<QuicDatagramStreamId> flow_id;
+ if (http_datagram_support() == HttpDatagramSupport::kDraft00) {
+ flow_id = SpdyUtils::ParseDatagramFlowIdHeader(request_headers);
+ if (!flow_id.has_value()) {
+ QUIC_DLOG(ERROR)
+ << "MASQUE request with bad or missing DatagramFlowId header";
+ return CreateBackendErrorResponse(
+ "400", "Bad or missing DatagramFlowId header");
+ }
}
QuicUrl url(absl::StrCat("https://", authority));
if (!url.IsValid() || url.PathParamsQuery() != "/") {
@@ -235,7 +236,9 @@ std::unique_ptr<QuicBackendResponse> MasqueServerSession::HandleMasqueRequest(
info_list, freeaddrinfo);
QuicSocketAddress target_server_address(info_list->ai_addr,
info_list->ai_addrlen);
- QUIC_DLOG(INFO) << "Got CONNECT_UDP request flow_id=" << *flow_id
+ QUIC_DLOG(INFO) << "Got CONNECT_UDP request on stream ID "
+ << request_handler->stream_id() << " flow_id="
+ << (flow_id.has_value() ? absl::StrCat(*flow_id) : "none")
<< " target_server_address=\"" << target_server_address
<< "\"";
@@ -264,20 +267,27 @@ std::unique_ptr<QuicBackendResponse> MasqueServerSession::HandleMasqueRequest(
<< request_handler->stream_id();
return CreateBackendErrorResponse("500", "Bad stream type");
}
- stream->RegisterHttp3DatagramFlowId(*flow_id);
+ if (flow_id.has_value()) {
+ stream->RegisterHttp3DatagramFlowId(*flow_id);
+ }
connect_udp_server_states_.push_back(
ConnectUdpServerState(stream, context_id, target_server_address,
fd_wrapper.extract_fd(), this));
- // TODO(b/181256914) remove this when we drop support for
- // draft-ietf-masque-h3-datagram-00 in favor of later drafts.
- Http3DatagramContextExtensions extensions;
- stream->RegisterHttp3DatagramContextId(context_id, extensions,
- &connect_udp_server_states_.back());
+ if (http_datagram_support() == HttpDatagramSupport::kDraft00) {
+ // TODO(b/181256914) remove this when we drop support for
+ // draft-ietf-masque-h3-datagram-00 in favor of later drafts.
+ stream->RegisterHttp3DatagramContextId(
+ context_id, DatagramFormatType::UDP_PAYLOAD,
+ /*format_additional_data=*/absl::string_view(),
+ &connect_udp_server_states_.back());
+ }
spdy::Http2HeaderBlock response_headers;
response_headers[":status"] = "200";
- SpdyUtils::AddDatagramFlowIdHeader(&response_headers, *flow_id);
+ if (flow_id.has_value()) {
+ SpdyUtils::AddDatagramFlowIdHeader(&response_headers, *flow_id);
+ }
auto response = std::make_unique<QuicBackendResponse>();
response->set_response_type(QuicBackendResponse::INCOMPLETE_RESPONSE);
response->set_headers(std::move(response_headers));
@@ -424,6 +434,19 @@ std::string MasqueServerSession::Name() const {
return std::string("MasqueServerSession-") + connection_id().ToString();
}
+bool MasqueServerSession::OnSettingsFrame(const SettingsFrame& frame) {
+ QUIC_DLOG(INFO) << "Received SETTINGS: " << frame;
+ if (!QuicSimpleServerSession::OnSettingsFrame(frame)) {
+ return false;
+ }
+ if (!SupportsH3Datagram()) {
+ QUIC_DLOG(ERROR) << "Refusing to use MASQUE without HTTP Datagrams";
+ return false;
+ }
+ QUIC_DLOG(INFO) << "Using HTTP Datagram: " << http_datagram_support();
+ return true;
+}
+
MasqueServerSession::ConnectUdpServerState::ConnectUdpServerState(
QuicSpdyStream* stream, absl::optional<QuicDatagramContextId> context_id,
const QuicSocketAddress& target_server_address, QuicUdpSocketFd fd,
@@ -440,10 +463,10 @@ MasqueServerSession::ConnectUdpServerState::ConnectUdpServerState(
MasqueServerSession::ConnectUdpServerState::~ConnectUdpServerState() {
if (stream() != nullptr) {
- stream()->UnregisterHttp3DatagramRegistrationVisitor();
if (context_registered_) {
stream()->UnregisterHttp3DatagramContextId(context_id());
}
+ stream()->UnregisterHttp3DatagramRegistrationVisitor();
}
if (fd_ == kQuicInvalidSocketFd) {
return;
@@ -503,39 +526,55 @@ void MasqueServerSession::ConnectUdpServerState::OnHttp3Datagram(
void MasqueServerSession::ConnectUdpServerState::OnContextReceived(
QuicStreamId stream_id, absl::optional<QuicDatagramContextId> context_id,
- const Http3DatagramContextExtensions& /*extensions*/) {
+ DatagramFormatType format_type, absl::string_view format_additional_data) {
if (stream_id != stream()->id()) {
QUIC_BUG(MASQUE server bad datagram context registration)
<< "Registered stream ID " << stream_id << ", expected "
<< stream()->id();
return;
}
+ if (format_type != DatagramFormatType::UDP_PAYLOAD) {
+ QUIC_DLOG(INFO) << "Ignoring unexpected datagram format type "
+ << DatagramFormatTypeToString(format_type);
+ return;
+ }
+ if (!format_additional_data.empty()) {
+ QUIC_DLOG(ERROR)
+ << "Received non-empty format additional data for context ID "
+ << (context_id_.has_value() ? context_id_.value() : 0)
+ << " on stream ID " << stream()->id();
+ masque_session_->ResetStream(stream()->id(), QUIC_STREAM_CANCELLED);
+ return;
+ }
if (!context_received_) {
context_received_ = true;
context_id_ = context_id;
}
if (context_id != context_id_) {
- QUIC_DLOG(INFO) << "Ignoring unexpected context ID "
- << (context_id.has_value() ? context_id.value() : 0)
- << " instead of "
- << (context_id_.has_value() ? context_id_.value() : 0)
- << " on stream ID " << stream()->id();
+ QUIC_DLOG(INFO)
+ << "Ignoring unexpected context ID "
+ << (context_id.has_value() ? absl::StrCat(context_id.value()) : "none")
+ << " instead of "
+ << (context_id_.has_value() ? absl::StrCat(context_id_.value())
+ : "none")
+ << " on stream ID " << stream()->id();
return;
}
if (context_registered_) {
QUIC_BUG(MASQUE server double datagram context registration)
<< "Try to re-register stream ID " << stream_id << " context ID "
- << (context_id_.has_value() ? context_id_.value() : 0);
+ << (context_id_.has_value() ? absl::StrCat(context_id_.value())
+ : "none");
return;
}
context_registered_ = true;
- Http3DatagramContextExtensions reply_extensions;
- stream()->RegisterHttp3DatagramContextId(context_id_, reply_extensions, this);
+ stream()->RegisterHttp3DatagramContextId(context_id_, format_type,
+ format_additional_data, this);
}
void MasqueServerSession::ConnectUdpServerState::OnContextClosed(
QuicStreamId stream_id, absl::optional<QuicDatagramContextId> context_id,
- const Http3DatagramContextExtensions& /*extensions*/) {
+ ContextCloseCode close_code, absl::string_view close_details) {
if (stream_id != stream()->id()) {
QUIC_BUG(MASQUE server bad datagram context registration)
<< "Closed context on stream ID " << stream_id << ", expected "
@@ -543,15 +582,18 @@ void MasqueServerSession::ConnectUdpServerState::OnContextClosed(
return;
}
if (context_id != context_id_) {
- QUIC_DLOG(INFO) << "Ignoring unexpected close of context ID "
- << (context_id.has_value() ? context_id.value() : 0)
- << " instead of "
- << (context_id_.has_value() ? context_id_.value() : 0)
- << " on stream ID " << stream()->id();
+ QUIC_DLOG(INFO)
+ << "Ignoring unexpected close of context ID "
+ << (context_id.has_value() ? absl::StrCat(context_id.value()) : "none")
+ << " instead of "
+ << (context_id_.has_value() ? absl::StrCat(context_id_.value())
+ : "none")
+ << " on stream ID " << stream()->id();
return;
}
- QUIC_DLOG(INFO) << "Received datagram context close on stream ID "
- << stream()->id() << ", closing stream";
+ QUIC_DLOG(INFO) << "Received datagram context close with close code "
+ << close_code << " close details \"" << close_details
+ << "\" on stream ID " << stream()->id() << ", closing stream";
masque_session_->ResetStream(stream()->id(), QUIC_STREAM_CANCELLED);
}
diff --git a/chromium/net/third_party/quiche/src/quic/masque/masque_server_session.h b/chromium/net/third_party/quiche/src/quic/masque/masque_server_session.h
index 1bec14c5464..b3c327f5446 100644
--- a/chromium/net/third_party/quiche/src/quic/masque/masque_server_session.h
+++ b/chromium/net/third_party/quiche/src/quic/masque/masque_server_session.h
@@ -117,14 +117,14 @@ class QUIC_NO_EXPORT MasqueServerSession
absl::string_view payload) override;
// From QuicSpdyStream::Http3DatagramRegistrationVisitor.
- void OnContextReceived(
- QuicStreamId stream_id,
- absl::optional<QuicDatagramContextId> context_id,
- const Http3DatagramContextExtensions& extensions) override;
- void OnContextClosed(
- QuicStreamId stream_id,
- absl::optional<QuicDatagramContextId> context_id,
- const Http3DatagramContextExtensions& extensions) override;
+ void OnContextReceived(QuicStreamId stream_id,
+ absl::optional<QuicDatagramContextId> context_id,
+ DatagramFormatType format_type,
+ absl::string_view format_additional_data) override;
+ void OnContextClosed(QuicStreamId stream_id,
+ absl::optional<QuicDatagramContextId> context_id,
+ ContextCloseCode close_code,
+ absl::string_view close_details) override;
private:
QuicSpdyStream* stream_;
@@ -136,7 +136,11 @@ class QUIC_NO_EXPORT MasqueServerSession
bool context_registered_ = false;
};
- bool ShouldNegotiateHttp3Datagram() override { return true; }
+ // From QuicSpdySession.
+ bool OnSettingsFrame(const SettingsFrame& frame) override;
+ HttpDatagramSupport LocalHttpDatagramSupport() override {
+ return HttpDatagramSupport::kDraft00And04;
+ }
MasqueServerBackend* masque_server_backend_; // Unowned.
Visitor* owner_; // Unowned.
diff --git a/chromium/net/third_party/quiche/src/quic/masque/masque_utils.h b/chromium/net/third_party/quiche/src/quic/masque/masque_utils.h
index 8113047768c..abaeda7fa43 100644
--- a/chromium/net/third_party/quiche/src/quic/masque/masque_utils.h
+++ b/chromium/net/third_party/quiche/src/quic/masque/masque_utils.h
@@ -18,7 +18,10 @@ QUIC_NO_EXPORT ParsedQuicVersionVector MasqueSupportedVersions();
QUIC_NO_EXPORT QuicConfig MasqueEncapsulatedConfig();
// Maximum packet size for encapsulated connections.
-enum : QuicByteCount { kMasqueMaxEncapsulatedPacketSize = 1300 };
+enum : QuicByteCount {
+ kMasqueMaxEncapsulatedPacketSize = 1300,
+ kMasqueMaxOuterPacketSize = 1350,
+};
// Mode that MASQUE is operating in.
enum class MasqueMode : uint8_t {
diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/quic_containers.h b/chromium/net/third_party/quiche/src/quic/platform/api/quic_containers.h
index eb16bfa18c3..19795e71a6f 100644
--- a/chromium/net/third_party/quiche/src/quic/platform/api/quic_containers.h
+++ b/chromium/net/third_party/quiche/src/quic/platform/api/quic_containers.h
@@ -5,7 +5,7 @@
#ifndef QUICHE_QUIC_PLATFORM_API_QUIC_CONTAINERS_H_
#define QUICHE_QUIC_PLATFORM_API_QUIC_CONTAINERS_H_
-#include "net/quic/platform/impl/quic_containers_impl.h"
+#include "quiche_platform_impl/quiche_containers_impl.h"
namespace quic {
@@ -15,7 +15,7 @@ namespace quic {
//
// DOES NOT GUARANTEE POINTER OR ITERATOR STABILITY!
template <typename Key, typename Compare = std::less<Key>>
-using QuicSmallOrderedSet = QuicSmallOrderedSetImpl<Key, Compare>;
+using QuicSmallOrderedSet = ::quiche::QuicheSmallOrderedSetImpl<Key, Compare>;
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/quic_mem_slice_span.h b/chromium/net/third_party/quiche/src/quic/platform/api/quic_mem_slice_span.h
deleted file mode 100644
index c33707a1763..00000000000
--- a/chromium/net/third_party/quiche/src/quic/platform/api/quic_mem_slice_span.h
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef QUICHE_QUIC_PLATFORM_API_QUIC_MEM_SLICE_SPAN_H_
-#define QUICHE_QUIC_PLATFORM_API_QUIC_MEM_SLICE_SPAN_H_
-
-#include "absl/strings/string_view.h"
-#include "quic/platform/api/quic_export.h"
-#include "net/quic/platform/impl/quic_mem_slice_span_impl.h"
-
-namespace quic {
-
-// QuicMemSliceSpan is effectively wrapper around an array of data structures
-// used as QuicMemSlice. So it could implemented with:
-// QuicMemSlice* slices_;
-// size_t num_slices_;
-// But for efficiency reasons, the actual implementation is an array of
-// platform-specific objects. This could avoid the translation from
-// platform-specific object to QuicMemSlice.
-// QuicMemSliceSpan does not own the underling data buffers.
-class QUIC_EXPORT_PRIVATE QuicMemSliceSpan {
- public:
- explicit QuicMemSliceSpan(QuicMemSliceSpanImpl impl) : impl_(impl) {}
-
- // Constructs a span with a single QuicMemSlice.
- explicit QuicMemSliceSpan(QuicMemSlice* slice) : impl_(slice->impl()) {}
-
- QuicMemSliceSpan(const QuicMemSliceSpan& other) = default;
- QuicMemSliceSpan& operator=(const QuicMemSliceSpan& other) = default;
- QuicMemSliceSpan(QuicMemSliceSpan&& other) = default;
- QuicMemSliceSpan& operator=(QuicMemSliceSpan&& other) = default;
-
- ~QuicMemSliceSpan() = default;
-
- template <typename ConsumeFunction>
- QuicByteCount ConsumeAll(ConsumeFunction consume) {
- return impl_.ConsumeAll(consume);
- }
-
- // Return data of the span at |index| by the form of a
- // absl::string_view.
- absl::string_view GetData(int index) { return impl_.GetData(index); }
-
- // Return the total length of the data inside the span.
- QuicByteCount total_length() { return impl_.total_length(); }
-
- // Return total number of slices in the span.
- size_t NumSlices() { return impl_.NumSlices(); }
-
- bool empty() const { return impl_.empty(); }
-
- private:
- QuicMemSliceSpanImpl impl_;
-};
-
-} // namespace quic
-
-#endif // QUICHE_QUIC_PLATFORM_API_QUIC_MEM_SLICE_SPAN_H_
diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/quic_mem_slice_span_test.cc b/chromium/net/third_party/quiche/src/quic/platform/api/quic_mem_slice_span_test.cc
deleted file mode 100644
index 99a11df5a2e..00000000000
--- a/chromium/net/third_party/quiche/src/quic/platform/api/quic_mem_slice_span_test.cc
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "quic/platform/api/quic_mem_slice_span.h"
-
-#include "quic/core/quic_simple_buffer_allocator.h"
-#include "quic/core/quic_types.h"
-#include "quic/platform/api/quic_flags.h"
-#include "quic/platform/api/quic_test.h"
-#include "quic/platform/api/quic_test_mem_slice_vector.h"
-
-namespace quic {
-namespace test {
-namespace {
-
-class QuicMemSliceSpanImplTest : public QuicTest {
- public:
- QuicMemSliceSpanImplTest() {
- for (size_t i = 0; i < 10; ++i) {
- buffers_.push_back(std::make_pair(data_, 1024));
- }
- }
-
- char data_[1024];
- std::vector<std::pair<char*, size_t>> buffers_;
-};
-
-TEST_F(QuicMemSliceSpanImplTest, ConsumeAll) {
- SimpleBufferAllocator allocator;
- QuicTestMemSliceVector vector(buffers_);
-
- int num_slices = 0;
- QuicByteCount bytes_consumed =
- vector.span().ConsumeAll([&](QuicMemSlice slice) {
- EXPECT_EQ(data_, slice.data());
- EXPECT_EQ(1024u, slice.length());
- ++num_slices;
- });
-
- EXPECT_EQ(10 * 1024u, bytes_consumed);
- EXPECT_EQ(10, num_slices);
-}
-
-} // namespace
-} // namespace test
-} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/quic_mem_slice_storage.cc b/chromium/net/third_party/quiche/src/quic/platform/api/quic_mem_slice_storage.cc
new file mode 100644
index 00000000000..87bce7f07fc
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/platform/api/quic_mem_slice_storage.cc
@@ -0,0 +1,35 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "quic/platform/api/quic_mem_slice_storage.h"
+
+#include "quic/core/quic_utils.h"
+
+namespace quic {
+
+QuicMemSliceStorage::QuicMemSliceStorage(const struct iovec* iov, int iov_count,
+ QuicBufferAllocator* allocator,
+ const QuicByteCount max_slice_len) {
+ if (iov == nullptr) {
+ return;
+ }
+ QuicByteCount write_len = 0;
+ for (int i = 0; i < iov_count; ++i) {
+ write_len += iov[i].iov_len;
+ }
+ QUICHE_DCHECK_LT(0u, write_len);
+
+ size_t io_offset = 0;
+ while (write_len > 0) {
+ size_t slice_len = std::min(write_len, max_slice_len);
+ QuicBuffer buffer(allocator, slice_len);
+ QuicUtils::CopyToBuffer(iov, iov_count, io_offset, slice_len,
+ buffer.data());
+ storage_.push_back(QuicMemSlice(std::move(buffer)));
+ write_len -= slice_len;
+ io_offset += slice_len;
+ }
+}
+
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/quic_mem_slice_storage.h b/chromium/net/third_party/quiche/src/quic/platform/api/quic_mem_slice_storage.h
index 3ec1fc4503c..4cccee3045f 100644
--- a/chromium/net/third_party/quiche/src/quic/platform/api/quic_mem_slice_storage.h
+++ b/chromium/net/third_party/quiche/src/quic/platform/api/quic_mem_slice_storage.h
@@ -5,8 +5,14 @@
#ifndef QUICHE_QUIC_PLATFORM_API_QUIC_MEM_SLICE_STORAGE_H_
#define QUICHE_QUIC_PLATFORM_API_QUIC_MEM_SLICE_STORAGE_H_
+#include <vector>
+
+#include "absl/types/span.h"
+#include "quic/core/quic_buffer_allocator.h"
+#include "quic/core/quic_types.h"
#include "quic/platform/api/quic_export.h"
-#include "net/quic/platform/impl/quic_mem_slice_storage_impl.h"
+#include "quic/platform/api/quic_iovec.h"
+#include "quic/platform/api/quic_mem_slice.h"
namespace quic {
@@ -14,11 +20,9 @@ namespace quic {
// use cases such as turning into QuicMemSliceSpan.
class QUIC_EXPORT_PRIVATE QuicMemSliceStorage {
public:
- QuicMemSliceStorage(const struct iovec* iov,
- int iov_count,
+ QuicMemSliceStorage(const struct iovec* iov, int iov_count,
QuicBufferAllocator* allocator,
- const QuicByteCount max_slice_len)
- : impl_(iov, iov_count, allocator, max_slice_len) {}
+ const QuicByteCount max_slice_len);
QuicMemSliceStorage(const QuicMemSliceStorage& other) = default;
QuicMemSliceStorage& operator=(const QuicMemSliceStorage& other) = default;
@@ -28,12 +32,10 @@ class QUIC_EXPORT_PRIVATE QuicMemSliceStorage {
~QuicMemSliceStorage() = default;
// Return a QuicMemSliceSpan form of the storage.
- QuicMemSliceSpan ToSpan() { return impl_.ToSpan(); }
-
- void Append(QuicMemSlice slice) { impl_.Append(std::move(*slice.impl())); }
+ absl::Span<QuicMemSlice> ToSpan() { return absl::MakeSpan(storage_); }
private:
- QuicMemSliceStorageImpl impl_;
+ std::vector<QuicMemSlice> storage_;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/quic_mem_slice_storage_test.cc b/chromium/net/third_party/quiche/src/quic/platform/api/quic_mem_slice_storage_test.cc
index 086e218d312..4bef774a0c6 100644
--- a/chromium/net/third_party/quiche/src/quic/platform/api/quic_mem_slice_storage_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/platform/api/quic_mem_slice_storage_test.cc
@@ -6,7 +6,6 @@
#include "quic/core/quic_simple_buffer_allocator.h"
#include "quic/platform/api/quic_test.h"
-#include "quic/platform/api/quic_test_mem_slice_vector.h"
namespace quic {
namespace test {
@@ -28,8 +27,8 @@ TEST_F(QuicMemSliceStorageImplTest, SingleIov) {
struct iovec iov = {const_cast<char*>(body.data()), body.length()};
QuicMemSliceStorage storage(&iov, 1, &allocator, 1024);
auto span = storage.ToSpan();
- EXPECT_EQ("ccc", span.GetData(0));
- EXPECT_NE(static_cast<const void*>(span.GetData(0).data()), body.data());
+ EXPECT_EQ("ccc", span[0].AsStringView());
+ EXPECT_NE(static_cast<const void*>(span[0].data()), body.data());
}
TEST_F(QuicMemSliceStorageImplTest, MultipleIovInSingleSlice) {
@@ -41,7 +40,7 @@ TEST_F(QuicMemSliceStorageImplTest, MultipleIovInSingleSlice) {
QuicMemSliceStorage storage(iov, 2, &allocator, 1024);
auto span = storage.ToSpan();
- EXPECT_EQ("aaabbbb", span.GetData(0));
+ EXPECT_EQ("aaabbbb", span[0].AsStringView());
}
TEST_F(QuicMemSliceStorageImplTest, MultipleIovInMultipleSlice) {
@@ -53,26 +52,8 @@ TEST_F(QuicMemSliceStorageImplTest, MultipleIovInMultipleSlice) {
QuicMemSliceStorage storage(iov, 2, &allocator, 4);
auto span = storage.ToSpan();
- EXPECT_EQ("aaaa", span.GetData(0));
- EXPECT_EQ("bbbb", span.GetData(1));
-}
-
-TEST_F(QuicMemSliceStorageImplTest, AppendMemSlices) {
- std::string body1(3, 'a');
- std::string body2(4, 'b');
- std::vector<std::pair<char*, size_t>> buffers;
- buffers.push_back(
- std::make_pair(const_cast<char*>(body1.data()), body1.length()));
- buffers.push_back(
- std::make_pair(const_cast<char*>(body2.data()), body2.length()));
- QuicTestMemSliceVector mem_slices(buffers);
-
- QuicMemSliceStorage storage(nullptr, 0, nullptr, 0);
- mem_slices.span().ConsumeAll(
- [&storage](QuicMemSlice slice) { storage.Append(std::move(slice)); });
-
- EXPECT_EQ("aaa", storage.ToSpan().GetData(0));
- EXPECT_EQ("bbbb", storage.ToSpan().GetData(1));
+ EXPECT_EQ("aaaa", span[0].AsStringView());
+ EXPECT_EQ("bbbb", span[1].AsStringView());
}
} // namespace
diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/quic_socket_address.cc b/chromium/net/third_party/quiche/src/quic/platform/api/quic_socket_address.cc
index 4c60c1e6da1..f0b667cae53 100644
--- a/chromium/net/third_party/quiche/src/quic/platform/api/quic_socket_address.cc
+++ b/chromium/net/third_party/quiche/src/quic/platform/api/quic_socket_address.cc
@@ -15,6 +15,23 @@
namespace quic {
+namespace {
+
+uint32_t HashIP(const QuicIpAddress& ip) {
+ if (ip.IsIPv4()) {
+ return ip.GetIPv4().s_addr;
+ }
+ if (ip.IsIPv6()) {
+ auto v6addr = ip.GetIPv6();
+ const uint32_t* v6_as_ints =
+ reinterpret_cast<const uint32_t*>(&v6addr.s6_addr);
+ return v6_as_ints[0] ^ v6_as_ints[1] ^ v6_as_ints[2] ^ v6_as_ints[3];
+ }
+ return 0;
+}
+
+} // namespace
+
QuicSocketAddress::QuicSocketAddress(QuicIpAddress address, uint16_t port)
: host_(address), port_(port) {}
@@ -131,4 +148,11 @@ sockaddr_storage QuicSocketAddress::generic_address() const {
return result.storage;
}
+uint32_t QuicSocketAddress::Hash() const {
+ uint32_t value = 0;
+ value ^= HashIP(host_);
+ value ^= port_ | (port_ << 16);
+ return value;
+}
+
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/quic_socket_address.h b/chromium/net/third_party/quiche/src/quic/platform/api/quic_socket_address.h
index 0831985e6a4..df6b9b7cf83 100644
--- a/chromium/net/third_party/quiche/src/quic/platform/api/quic_socket_address.h
+++ b/chromium/net/third_party/quiche/src/quic/platform/api/quic_socket_address.h
@@ -37,6 +37,9 @@ class QUIC_EXPORT_PRIVATE QuicSocketAddress {
uint16_t port() const;
sockaddr_storage generic_address() const;
+ // Hashes this address to an uint32_t.
+ uint32_t Hash() const;
+
private:
QuicIpAddress host_;
uint16_t port_ = 0;
@@ -48,6 +51,13 @@ inline std::ostream& operator<<(std::ostream& os,
return os;
}
+class QUIC_EXPORT_PRIVATE QuicSocketAddressHash {
+ public:
+ size_t operator()(QuicSocketAddress const& address) const noexcept {
+ return address.Hash();
+ }
+};
+
} // namespace quic
#endif // QUICHE_QUIC_PLATFORM_API_QUIC_SOCKET_ADDRESS_H_
diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/quic_test.h b/chromium/net/third_party/quiche/src/quic/platform/api/quic_test.h
index 58896f76d5e..644c25501b5 100644
--- a/chromium/net/third_party/quiche/src/quic/platform/api/quic_test.h
+++ b/chromium/net/third_party/quiche/src/quic/platform/api/quic_test.h
@@ -7,6 +7,7 @@
#include "quic/platform/api/quic_logging.h"
#include "net/quic/platform/impl/quic_test_impl.h"
+#include "common/platform/api/quiche_test.h"
using QuicFlagSaver = QuicFlagSaverImpl;
diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/quic_test_mem_slice_vector.h b/chromium/net/third_party/quiche/src/quic/platform/api/quic_test_mem_slice_vector.h
deleted file mode 100644
index 17d5853523c..00000000000
--- a/chromium/net/third_party/quiche/src/quic/platform/api/quic_test_mem_slice_vector.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef QUICHE_QUIC_PLATFORM_API_QUIC_TEST_MEM_SLICE_VECTOR_H_
-#define QUICHE_QUIC_PLATFORM_API_QUIC_TEST_MEM_SLICE_VECTOR_H_
-
-#include <utility>
-
-#include "quic/platform/api/quic_mem_slice_span.h"
-#include "net/quic/platform/impl/quic_test_mem_slice_vector_impl.h"
-
-namespace quic {
-namespace test {
-// QuicTestMemSliceVector is a test only class which creates a vector of
-// platform-specific data structure (used as QuicMemSlice) from an array of data
-// buffers. QuicTestMemSliceVector does not own the underlying data buffer.
-// Tests using QuicTestMemSliceVector need to make sure the actual data buffers
-// outlive QuicTestMemSliceVector, and QuicTestMemSliceVector outlive the
-// returned QuicMemSliceSpan.
-class QUIC_NO_EXPORT QuicTestMemSliceVector {
- public:
- explicit QuicTestMemSliceVector(std::vector<std::pair<char*, size_t>> buffers)
- : impl_(std::move(buffers)) {}
-
- QuicMemSliceSpan span() { return QuicMemSliceSpan(impl_.span()); }
-
- private:
- QuicTestMemSliceVectorImpl impl_;
-};
-
-} // namespace test
-} // namespace quic
-
-#endif // QUICHE_QUIC_PLATFORM_API_QUIC_TEST_MEM_SLICE_VECTOR_H_
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device.cc b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device.cc
index 65197cdd4d9..3768a439bec 100644
--- a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device.cc
+++ b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device.cc
@@ -24,26 +24,25 @@ namespace quic {
const int kInvalidFd = -1;
-TunDevice::TunDevice(const std::string& interface_name,
- int mtu,
- bool persist,
- bool setup_tun,
- KernelInterface* kernel)
+TunTapDevice::TunTapDevice(const std::string& interface_name, int mtu,
+ bool persist, bool setup_tun, bool is_tap,
+ KernelInterface* kernel)
: interface_name_(interface_name),
mtu_(mtu),
persist_(persist),
setup_tun_(setup_tun),
+ is_tap_(is_tap),
file_descriptor_(kInvalidFd),
kernel_(*kernel) {}
-TunDevice::~TunDevice() {
+TunTapDevice::~TunTapDevice() {
if (!persist_) {
Down();
}
CloseDevice();
}
-bool TunDevice::Init() {
+bool TunTapDevice::Init() {
if (interface_name_.empty() || interface_name_.size() >= IFNAMSIZ) {
QUIC_BUG(quic_bug_10995_1)
<< "interface_name must be nonempty and shorter than " << IFNAMSIZ;
@@ -63,7 +62,7 @@ bool TunDevice::Init() {
// TODO(pengg): might be better to use netlink socket, once we have a library to
// use
-bool TunDevice::Up() {
+bool TunTapDevice::Up() {
if (!setup_tun_) {
return true;
}
@@ -79,7 +78,7 @@ bool TunDevice::Up() {
// TODO(pengg): might be better to use netlink socket, once we have a library to
// use
-bool TunDevice::Down() {
+bool TunTapDevice::Down() {
if (!setup_tun_) {
return true;
}
@@ -93,11 +92,9 @@ bool TunDevice::Down() {
return NetdeviceIoctl(SIOCSIFFLAGS, reinterpret_cast<void*>(&if_request));
}
-int TunDevice::GetFileDescriptor() const {
- return file_descriptor_;
-}
+int TunTapDevice::GetFileDescriptor() const { return file_descriptor_; }
-bool TunDevice::OpenDevice() {
+bool TunTapDevice::OpenDevice() {
if (file_descriptor_ != kInvalidFd) {
CloseDevice();
}
@@ -113,7 +110,12 @@ bool TunDevice::OpenDevice() {
// destroy the device and create a new one, but that deletes any existing
// routing associated with the interface, which makes the meaning of the
// 'persist' bit ambiguous.
- if_request.ifr_flags = IFF_TUN | IFF_MULTI_QUEUE | IFF_NO_PI;
+ if_request.ifr_flags = IFF_MULTI_QUEUE | IFF_NO_PI;
+ if (is_tap_) {
+ if_request.ifr_flags |= IFF_TAP;
+ } else {
+ if_request.ifr_flags |= IFF_TUN;
+ }
// When the device is running with IFF_MULTI_QUEUE set, each call to open will
// create a queue which can be used to read/write packets from/to the device.
@@ -154,7 +156,7 @@ bool TunDevice::OpenDevice() {
// TODO(pengg): might be better to use netlink socket, once we have a library to
// use
-bool TunDevice::ConfigureInterface() {
+bool TunTapDevice::ConfigureInterface() {
if (!setup_tun_) {
return true;
}
@@ -174,7 +176,7 @@ bool TunDevice::ConfigureInterface() {
return true;
}
-bool TunDevice::CheckFeatures(int tun_device_fd) {
+bool TunTapDevice::CheckFeatures(int tun_device_fd) {
unsigned int actual_features;
if (kernel_.ioctl(tun_device_fd, TUNGETFEATURES, &actual_features) != 0) {
QUIC_PLOG(WARNING) << "Failed to TUNGETFEATURES";
@@ -191,7 +193,7 @@ bool TunDevice::CheckFeatures(int tun_device_fd) {
return true;
}
-bool TunDevice::NetdeviceIoctl(int request, void* argp) {
+bool TunTapDevice::NetdeviceIoctl(int request, void* argp) {
int fd = kernel_.socket(AF_INET6, SOCK_DGRAM, 0);
if (fd < 0) {
QUIC_PLOG(WARNING) << "Failed to create AF_INET6 socket.";
@@ -207,7 +209,7 @@ bool TunDevice::NetdeviceIoctl(int request, void* argp) {
return true;
}
-void TunDevice::CloseDevice() {
+void TunTapDevice::CloseDevice() {
if (file_descriptor_ != kInvalidFd) {
kernel_.close(file_descriptor_);
file_descriptor_ = kInvalidFd;
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device.h b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device.h
index 129e1d121c6..66c06d204e6 100644
--- a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device.h
+++ b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device.h
@@ -13,7 +13,7 @@
namespace quic {
-class TunDevice : public TunDeviceInterface {
+class TunTapDevice : public TunDeviceInterface {
public:
// This represents a tun device created in the OS kernel, which is a virtual
// network interface that any packets sent to it can be read by a user space
@@ -32,13 +32,10 @@ class TunDevice : public TunDeviceInterface {
// routing rules go away.
//
// The caller should own kernel and make sure it outlives this.
- TunDevice(const std::string& interface_name,
- int mtu,
- bool persist,
- bool setup_tun,
- KernelInterface* kernel);
+ TunTapDevice(const std::string& interface_name, int mtu, bool persist,
+ bool setup_tun, bool is_tap, KernelInterface* kernel);
- ~TunDevice() override;
+ ~TunTapDevice() override;
// Actually creates/reopens and configures the device.
bool Init() override;
@@ -50,7 +47,7 @@ class TunDevice : public TunDeviceInterface {
bool Down() override;
// Closes the open file descriptor for the TUN device (if one exists).
- // It is safe to reinitialize and reuse this TunDevice after calling
+ // It is safe to reinitialize and reuse this TunTapDevice after calling
// CloseDevice.
void CloseDevice() override;
@@ -75,6 +72,7 @@ class TunDevice : public TunDeviceInterface {
const int mtu_;
const bool persist_;
const bool setup_tun_;
+ const bool is_tap_;
int file_descriptor_;
KernelInterface& kernel_;
};
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_interface.h b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_interface.h
index 3c6f9624960..e88efa97186 100644
--- a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_interface.h
+++ b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_interface.h
@@ -24,7 +24,7 @@ class TunDeviceInterface {
virtual bool Down() = 0;
// Closes the open file descriptor for the TUN device (if one exists).
- // It is safe to reinitialize and reuse this TunDevice after calling
+ // It is safe to reinitialize and reuse this TunTapDevice after calling
// CloseDevice.
virtual void CloseDevice() = 0;
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger.cc b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger.cc
index 4783e9cc9c3..3381cd2b3f4 100644
--- a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger.cc
+++ b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger.cc
@@ -4,27 +4,36 @@
#include "quic/qbone/bonnet/tun_device_packet_exchanger.h"
+#include <netinet/icmp6.h>
+#include <netinet/ip6.h>
+
#include <utility>
#include "absl/strings/str_cat.h"
+#include "quic/qbone/platform/icmp_packet.h"
+#include "quic/qbone/platform/netlink_interface.h"
+#include "quic/qbone/qbone_constants.h"
namespace quic {
TunDevicePacketExchanger::TunDevicePacketExchanger(
- size_t mtu,
- KernelInterface* kernel,
- QbonePacketExchanger::Visitor* visitor,
- size_t max_pending_packets,
- StatsInterface* stats)
+ size_t mtu, KernelInterface* kernel, NetlinkInterface* netlink,
+ QbonePacketExchanger::Visitor* visitor, size_t max_pending_packets,
+ bool is_tap, StatsInterface* stats, absl::string_view ifname)
: QbonePacketExchanger(visitor, max_pending_packets),
mtu_(mtu),
kernel_(kernel),
- stats_(stats) {}
+ netlink_(netlink),
+ ifname_(ifname),
+ is_tap_(is_tap),
+ stats_(stats) {
+ if (is_tap_) {
+ mtu_ += ETH_HLEN;
+ }
+}
-bool TunDevicePacketExchanger::WritePacket(const char* packet,
- size_t size,
- bool* blocked,
- std::string* error) {
+bool TunDevicePacketExchanger::WritePacket(const char* packet, size_t size,
+ bool* blocked, std::string* error) {
*blocked = false;
if (fd_ < 0) {
*error = absl::StrCat("Invalid file descriptor of the TUN device: ", fd_);
@@ -32,7 +41,11 @@ bool TunDevicePacketExchanger::WritePacket(const char* packet,
return false;
}
- int result = kernel_->write(fd_, packet, size);
+ auto buffer = std::make_unique<QuicData>(packet, size);
+ if (is_tap_) {
+ buffer = ApplyL2Headers(*buffer);
+ }
+ int result = kernel_->write(fd_, buffer->data(), buffer->length());
if (result == -1) {
if (errno == EWOULDBLOCK || errno == EAGAIN) {
// The tunnel is blocked. Note that this does not mean the receive buffer
@@ -50,8 +63,7 @@ bool TunDevicePacketExchanger::WritePacket(const char* packet,
}
std::unique_ptr<QuicData> TunDevicePacketExchanger::ReadPacket(
- bool* blocked,
- std::string* error) {
+ bool* blocked, std::string* error) {
*blocked = false;
if (fd_ < 0) {
*error = absl::StrCat("Invalid file descriptor of the TUN device: ", fd_);
@@ -72,17 +84,147 @@ std::unique_ptr<QuicData> TunDevicePacketExchanger::ReadPacket(
}
return nullptr;
}
- stats_->OnPacketRead(result);
- return std::make_unique<QuicData>(read_buffer.release(), result, true);
-}
-void TunDevicePacketExchanger::set_file_descriptor(int fd) {
- fd_ = fd;
+ auto buffer = std::make_unique<QuicData>(read_buffer.release(), result, true);
+ if (is_tap_) {
+ buffer = ConsumeL2Headers(*buffer);
+ }
+ if (buffer) {
+ stats_->OnPacketRead(buffer->length());
+ }
+ return buffer;
}
+void TunDevicePacketExchanger::set_file_descriptor(int fd) { fd_ = fd; }
+
const TunDevicePacketExchanger::StatsInterface*
TunDevicePacketExchanger::stats_interface() const {
return stats_;
}
+std::unique_ptr<QuicData> TunDevicePacketExchanger::ApplyL2Headers(
+ const QuicData& l3_packet) {
+ if (is_tap_ && !mac_initialized_) {
+ NetlinkInterface::LinkInfo link_info{};
+ if (netlink_->GetLinkInfo(ifname_, &link_info)) {
+ memcpy(tap_mac_, link_info.hardware_address, ETH_ALEN);
+ mac_initialized_ = true;
+ } else {
+ QUIC_LOG_EVERY_N_SEC(ERROR, 30)
+ << "Unable to get link info for: " << ifname_;
+ }
+ }
+
+ const auto l2_packet_size = l3_packet.length() + ETH_HLEN;
+ auto l2_buffer = std::make_unique<char[]>(l2_packet_size);
+
+ // Populate the Ethernet header
+ auto* hdr = reinterpret_cast<ethhdr*>(l2_buffer.get());
+ // Set src & dst to my own address
+ memcpy(hdr->h_dest, tap_mac_, ETH_ALEN);
+ memcpy(hdr->h_source, tap_mac_, ETH_ALEN);
+ // Assume ipv6 for now
+ // TODO(b/195113643): Support additional protocols.
+ hdr->h_proto = absl::ghtons(ETH_P_IPV6);
+
+ // Copy the l3 packet into buffer, just after the ethernet header.
+ memcpy(l2_buffer.get() + ETH_HLEN, l3_packet.data(), l3_packet.length());
+
+ return std::make_unique<QuicData>(l2_buffer.release(), l2_packet_size, true);
+}
+
+std::unique_ptr<QuicData> TunDevicePacketExchanger::ConsumeL2Headers(
+ const QuicData& l2_packet) {
+ if (l2_packet.length() < ETH_HLEN) {
+ // Packet is too short for ethernet headers. Drop it.
+ return nullptr;
+ }
+ auto* hdr = reinterpret_cast<const ethhdr*>(l2_packet.data());
+ if (hdr->h_proto != absl::ghtons(ETH_P_IPV6)) {
+ return nullptr;
+ }
+ constexpr auto kIp6PrefixLen = ETH_HLEN + sizeof(ip6_hdr);
+ constexpr auto kIcmp6PrefixLen = kIp6PrefixLen + sizeof(icmp6_hdr);
+ if (l2_packet.length() < kIp6PrefixLen) {
+ // Packet is too short to be ipv6. Drop it.
+ return nullptr;
+ }
+ auto* ip_hdr = reinterpret_cast<const ip6_hdr*>(l2_packet.data() + ETH_HLEN);
+ const bool is_icmp = ip_hdr->ip6_ctlun.ip6_un1.ip6_un1_nxt == IPPROTO_ICMPV6;
+
+ bool is_neighbor_solicit = false;
+ if (is_icmp) {
+ if (l2_packet.length() < kIcmp6PrefixLen) {
+ // Packet is too short to be icmp6. Drop it.
+ return nullptr;
+ }
+ is_neighbor_solicit =
+ reinterpret_cast<const icmp6_hdr*>(l2_packet.data() + kIp6PrefixLen)
+ ->icmp6_type == ND_NEIGHBOR_SOLICIT;
+ }
+
+ if (is_neighbor_solicit) {
+ // If we've received a neighbor solicitation, craft an advertisement to
+ // respond with and write it back to the local interface.
+ auto* icmp6_payload = l2_packet.data() + kIcmp6PrefixLen;
+
+ QuicIpAddress target_address(
+ *reinterpret_cast<const in6_addr*>(icmp6_payload));
+ if (target_address != *QboneConstants::GatewayAddress()) {
+ // Only respond to solicitations for our gateway address
+ return nullptr;
+ }
+
+ // Neighbor Advertisement crafted per:
+ // https://datatracker.ietf.org/doc/html/rfc4861#section-4.4
+ //
+ // Using the Target link-layer address option defined at:
+ // https://datatracker.ietf.org/doc/html/rfc4861#section-4.6.1
+ constexpr size_t kIcmpv6OptionSize = 8;
+ const int payload_size = sizeof(in6_addr) + kIcmpv6OptionSize;
+ auto payload = std::make_unique<char[]>(payload_size);
+ // Place the solicited IPv6 address at the beginning of the response payload
+ memcpy(payload.get(), icmp6_payload, sizeof(in6_addr));
+ // Setup the Target link-layer address option:
+ // 0 1 2 3
+ // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // | Type | Length | Link-Layer Address ...
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ int pos = sizeof(in6_addr);
+ payload[pos++] = ND_OPT_TARGET_LINKADDR; // Type
+ payload[pos++] = 1; // Length in units of 8 octets
+ memcpy(&payload[pos], tap_mac_, ETH_ALEN); // This interfaces' MAC address
+
+ // Populate the ICMPv6 header
+ icmp6_hdr response_hdr{};
+ response_hdr.icmp6_type = ND_NEIGHBOR_ADVERT;
+ // Set the solicited bit to true
+ response_hdr.icmp6_dataun.icmp6_un_data8[0] = 64;
+ // Craft the full ICMPv6 packet and then ship it off to WritePacket
+ // to have it frame it with L2 headers and send it back to the requesting
+ // neighbor.
+ CreateIcmpPacket(ip_hdr->ip6_src, ip_hdr->ip6_src, response_hdr,
+ absl::string_view(payload.get(), payload_size),
+ [this](absl::string_view packet) {
+ bool blocked;
+ std::string error;
+ WritePacket(packet.data(), packet.size(), &blocked,
+ &error);
+ });
+ // Do not forward the neighbor solicitation through the tunnel since it's
+ // link-local.
+ return nullptr;
+ }
+
+ // If this isn't a Neighbor Solicitation, remove the L2 headers and forward
+ // it as though it were an L3 packet.
+ const auto l3_packet_size = l2_packet.length() - ETH_HLEN;
+ auto shift_buffer = std::make_unique<char[]>(l3_packet_size);
+ memcpy(shift_buffer.get(), l2_packet.data() + ETH_HLEN, l3_packet_size);
+
+ return std::make_unique<QuicData>(shift_buffer.release(), l3_packet_size,
+ true);
+}
+
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger.h b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger.h
index 115f5b580c6..3136b42862a 100644
--- a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger.h
+++ b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger.h
@@ -5,8 +5,11 @@
#ifndef QUICHE_QUIC_QBONE_BONNET_TUN_DEVICE_PACKET_EXCHANGER_H_
#define QUICHE_QUIC_QBONE_BONNET_TUN_DEVICE_PACKET_EXCHANGER_H_
+#include <linux/if_ether.h>
+
#include "quic/core/quic_packets.h"
#include "quic/qbone/platform/kernel_interface.h"
+#include "quic/qbone/platform/netlink_interface.h"
#include "quic/qbone/qbone_client_interface.h"
#include "quic/qbone/qbone_packet_exchanger.h"
@@ -42,11 +45,11 @@ class TunDevicePacketExchanger : public QbonePacketExchanger {
// the TUN device become blocked.
// |stats| is notified about packet read/write statistics. It is not owned,
// but should outlive objects of this class.
- TunDevicePacketExchanger(size_t mtu,
- KernelInterface* kernel,
+ TunDevicePacketExchanger(size_t mtu, KernelInterface* kernel,
+ NetlinkInterface* netlink,
QbonePacketExchanger::Visitor* visitor,
- size_t max_pending_packets,
- StatsInterface* stats);
+ size_t max_pending_packets, bool is_tap,
+ StatsInterface* stats, absl::string_view ifname);
void set_file_descriptor(int fd);
@@ -63,9 +66,19 @@ class TunDevicePacketExchanger : public QbonePacketExchanger {
bool* blocked,
std::string* error) override;
+ std::unique_ptr<QuicData> ApplyL2Headers(const QuicData& l3_packet);
+
+ std::unique_ptr<QuicData> ConsumeL2Headers(const QuicData& l2_packet);
+
int fd_ = -1;
size_t mtu_;
KernelInterface* kernel_;
+ NetlinkInterface* netlink_;
+ const std::string ifname_;
+
+ const bool is_tap_;
+ uint8_t tap_mac_[ETH_ALEN]{};
+ bool mac_initialized_ = false;
StatsInterface* stats_;
};
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger_test.cc b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger_test.cc
index c8f3ff0c861..8abf9a35fe6 100644
--- a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger_test.cc
@@ -30,11 +30,9 @@ class MockVisitor : public QbonePacketExchanger::Visitor {
class TunDevicePacketExchangerTest : public QuicTest {
protected:
TunDevicePacketExchangerTest()
- : exchanger_(kMtu,
- &mock_kernel_,
- &mock_visitor_,
- kMaxPendingPackets,
- &mock_stats_) {
+ : exchanger_(kMtu, &mock_kernel_, nullptr, &mock_visitor_,
+ kMaxPendingPackets, false, &mock_stats_,
+ absl::string_view()) {
exchanger_.set_file_descriptor(kFd);
}
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_test.cc b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_test.cc
index 6a02f07062e..18b818ccd51 100644
--- a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_test.cc
@@ -120,10 +120,10 @@ class TunDeviceTest : public QuicTest {
int next_fd_ = 100;
};
-// A TunDevice can be initialized and up
+// A TunTapDevice can be initialized and up
TEST_F(TunDeviceTest, BasicWorkFlow) {
SetInitExpectations(/* mtu = */ 1500, /* persist = */ false);
- TunDevice tun_device(kDeviceName, 1500, false, true, &mock_kernel_);
+ TunTapDevice tun_device(kDeviceName, 1500, false, true, false, &mock_kernel_);
EXPECT_TRUE(tun_device.Init());
EXPECT_GT(tun_device.GetFileDescriptor(), -1);
@@ -136,7 +136,7 @@ TEST_F(TunDeviceTest, FailToOpenTunDevice) {
SetInitExpectations(/* mtu = */ 1500, /* persist = */ false);
EXPECT_CALL(mock_kernel_, open(StrEq("/dev/net/tun"), _))
.WillOnce(Return(-1));
- TunDevice tun_device(kDeviceName, 1500, false, true, &mock_kernel_);
+ TunTapDevice tun_device(kDeviceName, 1500, false, true, false, &mock_kernel_);
EXPECT_FALSE(tun_device.Init());
EXPECT_EQ(tun_device.GetFileDescriptor(), -1);
ExpectDown(false);
@@ -145,7 +145,7 @@ TEST_F(TunDeviceTest, FailToOpenTunDevice) {
TEST_F(TunDeviceTest, FailToCheckFeature) {
SetInitExpectations(/* mtu = */ 1500, /* persist = */ false);
EXPECT_CALL(mock_kernel_, ioctl(_, TUNGETFEATURES, _)).WillOnce(Return(-1));
- TunDevice tun_device(kDeviceName, 1500, false, true, &mock_kernel_);
+ TunTapDevice tun_device(kDeviceName, 1500, false, true, false, &mock_kernel_);
EXPECT_FALSE(tun_device.Init());
EXPECT_EQ(tun_device.GetFileDescriptor(), -1);
ExpectDown(false);
@@ -159,7 +159,7 @@ TEST_F(TunDeviceTest, TooFewFeature) {
*actual_features = IFF_TUN | IFF_ONE_QUEUE;
return 0;
}));
- TunDevice tun_device(kDeviceName, 1500, false, true, &mock_kernel_);
+ TunTapDevice tun_device(kDeviceName, 1500, false, true, false, &mock_kernel_);
EXPECT_FALSE(tun_device.Init());
EXPECT_EQ(tun_device.GetFileDescriptor(), -1);
ExpectDown(false);
@@ -168,7 +168,7 @@ TEST_F(TunDeviceTest, TooFewFeature) {
TEST_F(TunDeviceTest, FailToSetFlag) {
SetInitExpectations(/* mtu = */ 1500, /* persist = */ true);
EXPECT_CALL(mock_kernel_, ioctl(_, TUNSETIFF, _)).WillOnce(Return(-1));
- TunDevice tun_device(kDeviceName, 1500, true, true, &mock_kernel_);
+ TunTapDevice tun_device(kDeviceName, 1500, true, true, false, &mock_kernel_);
EXPECT_FALSE(tun_device.Init());
EXPECT_EQ(tun_device.GetFileDescriptor(), -1);
}
@@ -176,7 +176,7 @@ TEST_F(TunDeviceTest, FailToSetFlag) {
TEST_F(TunDeviceTest, FailToPersistDevice) {
SetInitExpectations(/* mtu = */ 1500, /* persist = */ true);
EXPECT_CALL(mock_kernel_, ioctl(_, TUNSETPERSIST, _)).WillOnce(Return(-1));
- TunDevice tun_device(kDeviceName, 1500, true, true, &mock_kernel_);
+ TunTapDevice tun_device(kDeviceName, 1500, true, true, false, &mock_kernel_);
EXPECT_FALSE(tun_device.Init());
EXPECT_EQ(tun_device.GetFileDescriptor(), -1);
}
@@ -184,7 +184,7 @@ TEST_F(TunDeviceTest, FailToPersistDevice) {
TEST_F(TunDeviceTest, FailToOpenSocket) {
SetInitExpectations(/* mtu = */ 1500, /* persist = */ true);
EXPECT_CALL(mock_kernel_, socket(AF_INET6, _, _)).WillOnce(Return(-1));
- TunDevice tun_device(kDeviceName, 1500, true, true, &mock_kernel_);
+ TunTapDevice tun_device(kDeviceName, 1500, true, true, false, &mock_kernel_);
EXPECT_FALSE(tun_device.Init());
EXPECT_EQ(tun_device.GetFileDescriptor(), -1);
}
@@ -192,14 +192,14 @@ TEST_F(TunDeviceTest, FailToOpenSocket) {
TEST_F(TunDeviceTest, FailToSetMtu) {
SetInitExpectations(/* mtu = */ 1500, /* persist = */ true);
EXPECT_CALL(mock_kernel_, ioctl(_, SIOCSIFMTU, _)).WillOnce(Return(-1));
- TunDevice tun_device(kDeviceName, 1500, true, true, &mock_kernel_);
+ TunTapDevice tun_device(kDeviceName, 1500, true, true, false, &mock_kernel_);
EXPECT_FALSE(tun_device.Init());
EXPECT_EQ(tun_device.GetFileDescriptor(), -1);
}
TEST_F(TunDeviceTest, FailToUp) {
SetInitExpectations(/* mtu = */ 1500, /* persist = */ true);
- TunDevice tun_device(kDeviceName, 1500, true, true, &mock_kernel_);
+ TunTapDevice tun_device(kDeviceName, 1500, true, true, false, &mock_kernel_);
EXPECT_TRUE(tun_device.Init());
EXPECT_GT(tun_device.GetFileDescriptor(), -1);
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/platform/icmp_packet.cc b/chromium/net/third_party/quiche/src/quic/qbone/platform/icmp_packet.cc
index 50e3f2b6d78..0acd71216bf 100644
--- a/chromium/net/third_party/quiche/src/quic/qbone/platform/icmp_packet.cc
+++ b/chromium/net/third_party/quiche/src/quic/qbone/platform/icmp_packet.cc
@@ -17,7 +17,10 @@ constexpr size_t kIPv6AddressSize = sizeof(in6_addr);
constexpr size_t kIPv6HeaderSize = sizeof(ip6_hdr);
constexpr size_t kICMPv6HeaderSize = sizeof(icmp6_hdr);
constexpr size_t kIPv6MinPacketSize = 1280;
-constexpr size_t kIcmpTtl = 64;
+
+// Hop limit set to 255 to satisfy:
+// https://datatracker.ietf.org/doc/html/rfc4861#section-11.2
+constexpr size_t kIcmpTtl = 255;
constexpr size_t kICMPv6BodyMaxSize =
kIPv6MinPacketSize - kIPv6HeaderSize - kICMPv6HeaderSize;
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/platform/icmp_packet_test.cc b/chromium/net/third_party/quiche/src/quic/qbone/platform/icmp_packet_test.cc
index 9721e36aa40..1e6a2e92a77 100644
--- a/chromium/net/third_party/quiche/src/quic/qbone/platform/icmp_packet_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/qbone/platform/icmp_packet_test.cc
@@ -37,8 +37,8 @@ constexpr uint8_t kReferenceICMPPacket[] = {
0x00, 0x40,
// Next header is 58
0x3a,
- // Hop limit is 64
- 0x40,
+ // Hop limit is 255
+ 0xFF,
// Source address of fe80:1:2:3:4::1
0xfe, 0x80, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03,
0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/platform/netlink.cc b/chromium/net/third_party/quiche/src/quic/qbone/platform/netlink.cc
index 985632ab72c..2f4bbe27124 100644
--- a/chromium/net/third_party/quiche/src/quic/qbone/platform/netlink.cc
+++ b/chromium/net/third_party/quiche/src/quic/qbone/platform/netlink.cc
@@ -5,6 +5,7 @@
#include "quic/qbone/platform/netlink.h"
#include <linux/fib_rules.h>
+
#include <utility>
#include "absl/base/attributes.h"
@@ -13,6 +14,7 @@
#include "quic/platform/api/quic_ip_address.h"
#include "quic/platform/api/quic_logging.h"
#include "quic/qbone/platform/rtnetlink_message.h"
+#include "quic/qbone/qbone_constants.h"
namespace quic {
@@ -570,10 +572,17 @@ bool Netlink::ChangeRoute(Netlink::Verb verb,
// This is the source address to use in the IP packet should this routing rule
// is used.
if (preferred_source.IsInitialized()) {
+ auto src_str = preferred_source.ToPackedString();
message.AppendAttribute(RTA_PREFSRC,
- reinterpret_cast<const void*>(
- preferred_source.ToPackedString().c_str()),
- preferred_source.ToPackedString().size());
+ reinterpret_cast<const void*>(src_str.c_str()),
+ src_str.size());
+ }
+
+ if (verb != Verb::kRemove) {
+ auto gateway_str = QboneConstants::GatewayAddress()->ToPackedString();
+ message.AppendAttribute(RTA_GATEWAY,
+ reinterpret_cast<const void*>(gateway_str.c_str()),
+ gateway_str.size());
}
if (!Send(message.BuildIoVec().get(), message.IoVecSize())) {
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/platform/netlink_test.cc b/chromium/net/third_party/quiche/src/quic/qbone/platform/netlink_test.cc
index 16d2a19dc60..f6fe7cda9df 100644
--- a/chromium/net/third_party/quiche/src/quic/qbone/platform/netlink_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/qbone/platform/netlink_test.cc
@@ -564,6 +564,15 @@ TEST_F(NetlinkTest, ChangeRouteAdd) {
EXPECT_EQ(preferred_ip, address);
break;
}
+ case RTA_GATEWAY: {
+ const auto* raw_address =
+ reinterpret_cast<const char*>(RTA_DATA(rta));
+ ASSERT_EQ(sizeof(struct in6_addr), RTA_PAYLOAD(rta));
+ QuicIpAddress address;
+ address.FromPackedString(raw_address, RTA_PAYLOAD(rta));
+ EXPECT_EQ(*QboneConstants::GatewayAddress(), address);
+ break;
+ }
case RTA_OIF: {
ASSERT_EQ(sizeof(int), RTA_PAYLOAD(rta));
const auto* interface_index =
@@ -591,7 +600,7 @@ TEST_F(NetlinkTest, ChangeRouteAdd) {
}
++num_rta;
}
- EXPECT_EQ(4, num_rta);
+ EXPECT_EQ(5, num_rta);
});
EXPECT_TRUE(netlink->ChangeRoute(
Netlink::Verb::kAdd, QboneConstants::kQboneRouteTableId, subnet,
@@ -728,6 +737,15 @@ TEST_F(NetlinkTest, ChangeRouteReplace) {
EXPECT_EQ(preferred_ip, address);
break;
}
+ case RTA_GATEWAY: {
+ const auto* raw_address =
+ reinterpret_cast<const char*>(RTA_DATA(rta));
+ ASSERT_EQ(sizeof(struct in6_addr), RTA_PAYLOAD(rta));
+ QuicIpAddress address;
+ address.FromPackedString(raw_address, RTA_PAYLOAD(rta));
+ EXPECT_EQ(*QboneConstants::GatewayAddress(), address);
+ break;
+ }
case RTA_OIF: {
ASSERT_EQ(sizeof(int), RTA_PAYLOAD(rta));
const auto* interface_index =
@@ -755,7 +773,7 @@ TEST_F(NetlinkTest, ChangeRouteReplace) {
}
++num_rta;
}
- EXPECT_EQ(4, num_rta);
+ EXPECT_EQ(5, num_rta);
});
EXPECT_TRUE(netlink->ChangeRoute(
Netlink::Verb::kReplace, QboneConstants::kQboneRouteTableId, subnet,
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/qbone_constants.cc b/chromium/net/third_party/quiche/src/quic/qbone/qbone_constants.cc
index fb92af7319f..f54ebc3edef 100644
--- a/chromium/net/third_party/quiche/src/quic/qbone/qbone_constants.cc
+++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_constants.cc
@@ -19,7 +19,7 @@ QuicStreamId QboneConstants::GetControlStreamId(QuicTransportVersion version) {
const QuicIpAddress* QboneConstants::TerminatorLocalAddress() {
static auto* terminator_address = []() {
- QuicIpAddress* address = new QuicIpAddress;
+ auto* address = new QuicIpAddress;
// 0x71 0x62 0x6f 0x6e 0x65 is 'qbone' in ascii.
address->FromString("fe80::71:626f:6e65");
return address;
@@ -33,4 +33,13 @@ const IpRange* QboneConstants::TerminatorLocalAddressRange() {
return range;
}
+const QuicIpAddress* QboneConstants::GatewayAddress() {
+ static auto* gateway_address = []() {
+ auto* address = new QuicIpAddress;
+ address->FromString("fe80::1");
+ return address;
+ }();
+ return gateway_address;
+}
+
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/qbone_constants.h b/chromium/net/third_party/quiche/src/quic/qbone/qbone_constants.h
index 8053013abf9..141bb6c00d2 100644
--- a/chromium/net/third_party/quiche/src/quic/qbone/qbone_constants.h
+++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_constants.h
@@ -25,6 +25,9 @@ struct QboneConstants {
static const QuicIpAddress* TerminatorLocalAddress();
// The IPRange containing the TerminatorLocalAddress
static const IpRange* TerminatorLocalAddressRange();
+ // The gateway address to provide when configuring routes to the QBONE
+ // interface
+ static const QuicIpAddress* GatewayAddress();
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/qbone_session_test.cc b/chromium/net/third_party/quiche/src/quic/qbone/qbone_session_test.cc
index 9887f79a46e..c3ae3be1fd1 100644
--- a/chromium/net/third_party/quiche/src/quic/qbone/qbone_session_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_session_test.cc
@@ -79,9 +79,9 @@ class IndirectionProofSource : public ProofSource {
absl::string_view chlo_hash,
std::unique_ptr<Callback> callback) override {
if (!proof_source_) {
- QuicReferenceCountedPointer<ProofSource::Chain> chain =
- GetCertChain(server_address, client_address, hostname);
QuicCryptoProof proof;
+ QuicReferenceCountedPointer<ProofSource::Chain> chain = GetCertChain(
+ server_address, client_address, hostname, &proof.cert_matched_sni);
callback->Run(/*ok=*/false, chain, proof, /*details=*/nullptr);
return;
}
@@ -92,13 +92,13 @@ class IndirectionProofSource : public ProofSource {
QuicReferenceCountedPointer<Chain> GetCertChain(
const QuicSocketAddress& server_address,
- const QuicSocketAddress& client_address,
- const std::string& hostname) override {
+ const QuicSocketAddress& client_address, const std::string& hostname,
+ bool* cert_matched_sni) override {
if (!proof_source_) {
return QuicReferenceCountedPointer<Chain>();
}
- return proof_source_->GetCertChain(server_address, client_address,
- hostname);
+ return proof_source_->GetCertChain(server_address, client_address, hostname,
+ cert_matched_sni);
}
void ComputeTlsSignature(
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/qbone_stream_test.cc b/chromium/net/third_party/quiche/src/quic/qbone/qbone_stream_test.cc
index fc2ce819d90..8e724a4195a 100644
--- a/chromium/net/third_party/quiche/src/quic/qbone/qbone_stream_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_stream_test.cc
@@ -31,11 +31,8 @@ using ::testing::StrictMock;
class MockQuicSession : public QboneSessionBase {
public:
MockQuicSession(QuicConnection* connection, const QuicConfig& config)
- : QboneSessionBase(connection,
- nullptr /*visitor*/,
- config,
- CurrentSupportedVersions(),
- nullptr /*writer*/) {}
+ : QboneSessionBase(connection, nullptr /*visitor*/, config,
+ CurrentSupportedVersions(), nullptr /*writer*/) {}
~MockQuicSession() override {}
@@ -56,16 +53,12 @@ class MockQuicSession : public QboneSessionBase {
}
// Called by QuicStream when they want to close stream.
- MOCK_METHOD(void,
- MaybeSendRstStreamFrame,
- (QuicStreamId stream_id,
- QuicRstStreamErrorCode error,
+ MOCK_METHOD(void, MaybeSendRstStreamFrame,
+ (QuicStreamId stream_id, QuicResetStreamError error,
QuicStreamOffset bytes_written),
(override));
- MOCK_METHOD(void,
- MaybeSendStopSendingFrame,
- (QuicStreamId stream_id, QuicRstStreamErrorCode error),
- (override));
+ MOCK_METHOD(void, MaybeSendStopSendingFrame,
+ (QuicStreamId stream_id, QuicResetStreamError error), (override));
// Sets whether data is written to buffer, or else if this is write blocked.
void set_writable(bool writable) { writable_ = writable; }
@@ -104,8 +97,7 @@ class DummyPacketWriter : public QuicPacketWriter {
DummyPacketWriter() {}
// QuicPacketWriter overrides.
- WriteResult WritePacket(const char* buffer,
- size_t buf_len,
+ WriteResult WritePacket(const char* buffer, size_t buf_len,
const QuicIpAddress& self_address,
const QuicSocketAddress& peer_address,
PerPacketOptions* options) override {
@@ -181,8 +173,7 @@ class QboneReadOnlyStreamTest : public ::testing::Test,
SimpleBufferAllocator buffer_allocator_;
MockClock clock_;
const QuicStreamId kStreamId = QuicUtils::GetFirstUnidirectionalStreamId(
- CurrentSupportedVersions()[0].transport_version,
- Perspective::IS_CLIENT);
+ CurrentSupportedVersions()[0].transport_version, Perspective::IS_CLIENT);
};
// Read an entire string.
@@ -240,9 +231,13 @@ TEST_F(QboneReadOnlyStreamTest, ReadBufferedTooLarge) {
std::string packet = "0123456789";
int iterations = (QboneConstants::kMaxQbonePacketBytes / packet.size()) + 2;
EXPECT_CALL(*session_, MaybeSendStopSendingFrame(
- kStreamId, QUIC_BAD_APPLICATION_PAYLOAD));
- EXPECT_CALL(*session_, MaybeSendRstStreamFrame(
- kStreamId, QUIC_BAD_APPLICATION_PAYLOAD, _));
+ kStreamId, QuicResetStreamError::FromInternal(
+ QUIC_BAD_APPLICATION_PAYLOAD)));
+ EXPECT_CALL(
+ *session_,
+ MaybeSendRstStreamFrame(
+ kStreamId,
+ QuicResetStreamError::FromInternal(QUIC_BAD_APPLICATION_PAYLOAD), _));
for (int i = 0; i < iterations; ++i) {
QuicStreamFrame frame(kStreamId, i == (iterations - 1), i * packet.size(),
packet);
diff --git a/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_client_session.cc b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_client_session.cc
index 17f9194abfe..1a2160b0e9d 100644
--- a/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_client_session.cc
+++ b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_client_session.cc
@@ -242,7 +242,7 @@ void QuicTransportClientSession::SendClientIndication() {
}
ready_ = true;
- visitor_->OnSessionReady();
+ visitor_->OnSessionReady(spdy::SpdyHeaderBlock());
}
void QuicTransportClientSession::OnMessageReceived(absl::string_view message) {
diff --git a/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_client_session.h b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_client_session.h
index ad29a150b58..87854575bb0 100644
--- a/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_client_session.h
+++ b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_client_session.h
@@ -17,6 +17,7 @@
#include "quic/core/quic_crypto_client_stream.h"
#include "quic/core/quic_crypto_stream.h"
#include "quic/core/quic_datagram_queue.h"
+#include "quic/core/quic_error_codes.h"
#include "quic/core/quic_server_id.h"
#include "quic/core/quic_session.h"
#include "quic/core/quic_stream.h"
@@ -113,6 +114,17 @@ class QUIC_EXPORT_PRIVATE QuicTransportClientSession
void OnProofVerifyDetailsAvailable(
const ProofVerifyDetails& verify_details) override;
+ void CloseSession(WebTransportSessionError /*error_code*/,
+ absl::string_view error_message) override {
+ connection()->CloseConnection(
+ QUIC_NO_ERROR, std::string(error_message),
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ }
+
+ QuicByteCount GetMaxDatagramSize() const override {
+ return GetGuaranteedLargestMessagePayload();
+ }
+
protected:
class QUIC_EXPORT_PRIVATE ClientIndication : public QuicStream {
public:
diff --git a/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_client_session_test.cc b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_client_session_test.cc
index 8e6a0e27882..90c449cb746 100644
--- a/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_client_session_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_client_session_test.cc
@@ -104,7 +104,7 @@ TEST_F(QuicTransportClientSessionTest, SuccessfulConnection) {
"\0\x01" // length
"/"; // value
- EXPECT_CALL(visitor_, OnSessionReady());
+ EXPECT_CALL(visitor_, OnSessionReady(_));
Connect();
EXPECT_TRUE(session_->IsSessionReady());
diff --git a/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_integration_test.cc b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_integration_test.cc
index 36607b3918e..7bb8479af31 100644
--- a/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_integration_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_integration_test.cc
@@ -212,7 +212,7 @@ class QuicTransportIntegrationTest : public QuicTest {
TEST_F(QuicTransportIntegrationTest, SuccessfulHandshake) {
CreateDefaultEndpoints("/discard");
WireUpEndpoints();
- EXPECT_CALL(*client_->visitor(), OnSessionReady());
+ EXPECT_CALL(*client_->visitor(), OnSessionReady(_));
RunHandshake();
EXPECT_TRUE(client_->session()->IsSessionReady());
EXPECT_TRUE(server_->session()->IsSessionReady());
diff --git a/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_stream.h b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_stream.h
index 87ef5fb3b83..5d574afe3c4 100644
--- a/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_stream.h
+++ b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_stream.h
@@ -10,11 +10,11 @@
#include "absl/base/attributes.h"
#include "absl/strings/string_view.h"
+#include "quic/core/http/web_transport_stream_adapter.h"
#include "quic/core/quic_session.h"
#include "quic/core/quic_stream.h"
#include "quic/core/quic_types.h"
#include "quic/core/web_transport_interface.h"
-#include "quic/core/web_transport_stream_adapter.h"
#include "quic/quic_transport/quic_transport_session_interface.h"
namespace quic {
@@ -50,12 +50,15 @@ class QUIC_EXPORT_PRIVATE QuicTransportStream : public QuicStream,
QuicStreamId GetStreamId() const override { return id(); }
- void ResetWithUserCode(QuicRstStreamErrorCode error) override {
- adapter_.ResetWithUserCode(error);
+ void ResetWithUserCode(WebTransportStreamError /*error*/) override {
+ adapter_.ResetWithUserCode(0);
}
void ResetDueToInternalError() override {
adapter_.ResetDueToInternalError();
}
+ void SendStopSending(WebTransportStreamError /*error*/) override {
+ adapter_.SendStopSending(0);
+ }
void MaybeResetDueToStreamObjectGone() override {
adapter_.MaybeResetDueToStreamObjectGone();
}
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/crypto_test_utils.cc b/chromium/net/third_party/quiche/src/quic/test_tools/crypto_test_utils.cc
index d28b4faff85..febd8d30b32 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/crypto_test_utils.cc
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/crypto_test_utils.cc
@@ -634,22 +634,6 @@ void CompareClientAndServerKeys(QuicCryptoClientStream* client,
"subkey secret", client_subkey_secret.data(),
client_subkey_secret.length(), server_subkey_secret.data(),
server_subkey_secret.length());
-
- const char kSampleLabel[] = "label";
- const char kSampleContext[] = "context";
- const size_t kSampleOutputLength = 32;
- std::string client_key_extraction;
- std::string server_key_extraction;
- EXPECT_TRUE(client->ExportKeyingMaterial(kSampleLabel, kSampleContext,
- kSampleOutputLength,
- &client_key_extraction));
- EXPECT_TRUE(server->ExportKeyingMaterial(kSampleLabel, kSampleContext,
- kSampleOutputLength,
- &server_key_extraction));
- quiche::test::CompareCharArraysWithHexError(
- "sample key extraction", client_key_extraction.data(),
- client_key_extraction.length(), server_key_extraction.data(),
- server_key_extraction.length());
}
QuicTag ParseTag(const char* tagstr) {
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/failing_proof_source.cc b/chromium/net/third_party/quiche/src/quic/test_tools/failing_proof_source.cc
index fad128d9a39..1f17c8a1f35 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/failing_proof_source.cc
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/failing_proof_source.cc
@@ -22,7 +22,9 @@ void FailingProofSource::GetProof(const QuicSocketAddress& /*server_address*/,
QuicReferenceCountedPointer<ProofSource::Chain>
FailingProofSource::GetCertChain(const QuicSocketAddress& /*server_address*/,
const QuicSocketAddress& /*client_address*/,
- const std::string& /*hostname*/) {
+ const std::string& /*hostname*/,
+ bool* cert_matched_sni) {
+ *cert_matched_sni = false;
return QuicReferenceCountedPointer<Chain>();
}
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/failing_proof_source.h b/chromium/net/third_party/quiche/src/quic/test_tools/failing_proof_source.h
index 447b77066bd..db5a19714cb 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/failing_proof_source.h
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/failing_proof_source.h
@@ -23,8 +23,8 @@ class FailingProofSource : public ProofSource {
QuicReferenceCountedPointer<Chain> GetCertChain(
const QuicSocketAddress& server_address,
- const QuicSocketAddress& client_address,
- const std::string& hostname) override;
+ const QuicSocketAddress& client_address, const std::string& hostname,
+ bool* cert_matched_sni) override;
void ComputeTlsSignature(
const QuicSocketAddress& server_address,
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/fake_proof_source.cc b/chromium/net/third_party/quiche/src/quic/test_tools/fake_proof_source.cc
index 1109d659fac..0f7cb194df6 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/fake_proof_source.cc
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/fake_proof_source.cc
@@ -96,9 +96,10 @@ void FakeProofSource::GetProof(
QuicReferenceCountedPointer<ProofSource::Chain> FakeProofSource::GetCertChain(
const QuicSocketAddress& server_address,
- const QuicSocketAddress& client_address,
- const std::string& hostname) {
- return delegate_->GetCertChain(server_address, client_address, hostname);
+ const QuicSocketAddress& client_address, const std::string& hostname,
+ bool* cert_matched_sni) {
+ return delegate_->GetCertChain(server_address, client_address, hostname,
+ cert_matched_sni);
}
void FakeProofSource::ComputeTlsSignature(
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/fake_proof_source.h b/chromium/net/third_party/quiche/src/quic/test_tools/fake_proof_source.h
index c088d43a9bb..b135129c08c 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/fake_proof_source.h
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/fake_proof_source.h
@@ -43,8 +43,8 @@ class FakeProofSource : public ProofSource {
std::unique_ptr<ProofSource::Callback> callback) override;
QuicReferenceCountedPointer<Chain> GetCertChain(
const QuicSocketAddress& server_address,
- const QuicSocketAddress& client_address,
- const std::string& hostname) override;
+ const QuicSocketAddress& client_address, const std::string& hostname,
+ bool* cert_matched_sni) override;
void ComputeTlsSignature(
const QuicSocketAddress& server_address,
const QuicSocketAddress& client_address,
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/fake_proof_source_handle.cc b/chromium/net/third_party/quiche/src/quic/test_tools/fake_proof_source_handle.cc
index f34247e9bae..8c1e7f870f1 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/fake_proof_source_handle.cc
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/fake_proof_source_handle.cc
@@ -94,19 +94,23 @@ QuicAsyncStatus FakeProofSourceHandle::SelectCertificate(
callback()->OnSelectCertificateDone(
/*ok=*/false,
/*is_sync=*/true, nullptr, /*handshake_hints=*/absl::string_view(),
- /*ticket_encryption_key=*/absl::string_view());
+ /*ticket_encryption_key=*/absl::string_view(),
+ /*cert_matched_sni=*/false);
return QUIC_FAILURE;
}
QUICHE_DCHECK(select_cert_action_ == Action::DELEGATE_SYNC);
+ bool cert_matched_sni;
QuicReferenceCountedPointer<ProofSource::Chain> chain =
- delegate_->GetCertChain(server_address, client_address, hostname);
+ delegate_->GetCertChain(server_address, client_address, hostname,
+ &cert_matched_sni);
bool ok = chain && !chain->certs.empty();
callback_->OnSelectCertificateDone(
ok, /*is_sync=*/true, chain.get(),
/*handshake_hints=*/absl::string_view(),
- /*ticket_encryption_key=*/absl::string_view());
+ /*ticket_encryption_key=*/absl::string_view(),
+ /*cert_matched_sni=*/cert_matched_sni);
return ok ? QUIC_SUCCESS : QUIC_FAILURE;
}
@@ -182,16 +186,19 @@ void FakeProofSourceHandle::SelectCertOperation::Run() {
/*ok=*/false,
/*is_sync=*/false, nullptr,
/*handshake_hints=*/absl::string_view(),
- /*ticket_encryption_key=*/absl::string_view());
+ /*ticket_encryption_key=*/absl::string_view(),
+ /*cert_matched_sni=*/false);
} else if (action_ == Action::DELEGATE_ASYNC) {
+ bool cert_matched_sni;
QuicReferenceCountedPointer<ProofSource::Chain> chain =
delegate_->GetCertChain(args_.server_address, args_.client_address,
- args_.hostname);
+ args_.hostname, &cert_matched_sni);
bool ok = chain && !chain->certs.empty();
callback_->OnSelectCertificateDone(
ok, /*is_sync=*/false, chain.get(),
/*handshake_hints=*/absl::string_view(),
- /*ticket_encryption_key=*/absl::string_view());
+ /*ticket_encryption_key=*/absl::string_view(),
+ /*cert_matched_sni=*/cert_matched_sni);
} else {
QUIC_BUG(quic_bug_10139_1)
<< "Unexpected action: " << static_cast<int>(action_);
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_time_wait_list_manager.cc b/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_time_wait_list_manager.cc
index 6274f201d86..63858c94a1a 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_time_wait_list_manager.cc
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_time_wait_list_manager.cc
@@ -18,9 +18,9 @@ MockTimeWaitListManager::MockTimeWaitListManager(
: QuicTimeWaitListManager(writer, visitor, clock, alarm_factory) {
// Though AddConnectionIdToTimeWait is mocked, we want to retain its
// functionality.
- EXPECT_CALL(*this, AddConnectionIdToTimeWait(_, _, _))
+ EXPECT_CALL(*this, AddConnectionIdToTimeWait(_, _))
.Times(testing::AnyNumber());
- ON_CALL(*this, AddConnectionIdToTimeWait(_, _, _))
+ ON_CALL(*this, AddConnectionIdToTimeWait(_, _))
.WillByDefault(
Invoke(this, &MockTimeWaitListManager::
QuicTimeWaitListManager_AddConnectionIdToTimeWait));
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_time_wait_list_manager.h b/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_time_wait_list_manager.h
index 12bf0801082..1d3cfd51a70 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_time_wait_list_manager.h
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_time_wait_list_manager.h
@@ -19,19 +19,15 @@ class MockTimeWaitListManager : public QuicTimeWaitListManager {
QuicAlarmFactory* alarm_factory);
~MockTimeWaitListManager() override;
- MOCK_METHOD(void,
- AddConnectionIdToTimeWait,
- (QuicConnectionId connection_id,
- QuicTimeWaitListManager::TimeWaitAction action,
+ MOCK_METHOD(void, AddConnectionIdToTimeWait,
+ (QuicTimeWaitListManager::TimeWaitAction action,
quic::TimeWaitConnectionInfo info),
(override));
void QuicTimeWaitListManager_AddConnectionIdToTimeWait(
- QuicConnectionId connection_id,
QuicTimeWaitListManager::TimeWaitAction action,
quic::TimeWaitConnectionInfo info) {
- QuicTimeWaitListManager::AddConnectionIdToTimeWait(connection_id, action,
- std::move(info));
+ QuicTimeWaitListManager::AddConnectionIdToTimeWait(action, std::move(info));
}
MOCK_METHOD(void,
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/packet_dropping_test_writer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/packet_dropping_test_writer.cc
index 76dd778734c..079b2286d40 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/packet_dropping_test_writer.cc
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/packet_dropping_test_writer.cc
@@ -18,7 +18,7 @@ const int32_t kMinSuccesfulWritesAfterPacketLoss = 2;
// An alarm that is scheduled if a blocked socket is simulated to indicate
// it's writable again.
-class WriteUnblockedAlarm : public QuicAlarm::Delegate {
+class WriteUnblockedAlarm : public QuicAlarm::DelegateWithoutContext {
public:
explicit WriteUnblockedAlarm(PacketDroppingTestWriter* writer)
: writer_(writer) {}
@@ -34,7 +34,7 @@ class WriteUnblockedAlarm : public QuicAlarm::Delegate {
// An alarm that is scheduled every time a new packet is to be written at a
// later point.
-class DelayAlarm : public QuicAlarm::Delegate {
+class DelayAlarm : public QuicAlarm::DelegateWithoutContext {
public:
explicit DelayAlarm(PacketDroppingTestWriter* writer) : writer_(writer) {}
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_decoder_test_utils.cc b/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_decoder_test_utils.cc
index ab76c445d02..37f182a767e 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_decoder_test_utils.cc
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_decoder_test_utils.cc
@@ -37,7 +37,7 @@ void TestHeadersHandler::OnDecodingCompleted() {
}
void TestHeadersHandler::OnDecodingErrorDetected(
- absl::string_view error_message) {
+ QuicErrorCode /*error_code*/, absl::string_view error_message) {
ASSERT_FALSE(decoding_completed_);
ASSERT_FALSE(decoding_error_detected_);
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_decoder_test_utils.h b/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_decoder_test_utils.h
index 2220bd4e37a..b6bff7802c8 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_decoder_test_utils.h
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_decoder_test_utils.h
@@ -10,6 +10,7 @@
#include "absl/strings/string_view.h"
#include "quic/core/qpack/qpack_decoder.h"
#include "quic/core/qpack/qpack_progressive_decoder.h"
+#include "quic/core/quic_error_codes.h"
#include "quic/platform/api/quic_test.h"
#include "quic/test_tools/qpack/qpack_test_utils.h"
#include "spdy/core/spdy_header_block.h"
@@ -51,7 +52,8 @@ class TestHeadersHandler
void OnHeaderDecoded(absl::string_view name,
absl::string_view value) override;
void OnDecodingCompleted() override;
- void OnDecodingErrorDetected(absl::string_view error_message) override;
+ void OnDecodingErrorDetected(QuicErrorCode error_code,
+ absl::string_view error_message) override;
// Release decoded header list. Must only be called if decoding is complete
// and no errors have been detected.
@@ -81,9 +83,8 @@ class MockHeadersHandler
(absl::string_view name, absl::string_view value),
(override));
MOCK_METHOD(void, OnDecodingCompleted, (), (override));
- MOCK_METHOD(void,
- OnDecodingErrorDetected,
- (absl::string_view error_message),
+ MOCK_METHOD(void, OnDecodingErrorDetected,
+ (QuicErrorCode error_code, absl::string_view error_message),
(override));
};
@@ -95,7 +96,8 @@ class NoOpHeadersHandler
void OnHeaderDecoded(absl::string_view /*name*/,
absl::string_view /*value*/) override {}
void OnDecodingCompleted() override {}
- void OnDecodingErrorDetected(absl::string_view /*error_message*/) override {}
+ void OnDecodingErrorDetected(QuicErrorCode /*error_code*/,
+ absl::string_view /*error_message*/) override {}
};
void QpackDecode(
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.cc
index 43c345094ef..6125f67adce 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.cc
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.cc
@@ -528,5 +528,12 @@ QuicConnectionPeer::GetSelfIssuedConnectionIdManager(
return connection->self_issued_cid_manager_.get();
}
+// static
+std::unique_ptr<QuicSelfIssuedConnectionIdManager>
+QuicConnectionPeer::MakeSelfIssuedConnectionIdManager(
+ QuicConnection* connection) {
+ return connection->MakeSelfIssuedConnectionIdManager();
+}
+
} // namespace test
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h
index 99b8b94fd74..849ede6cf93 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h
@@ -216,6 +216,9 @@ class QuicConnectionPeer {
static QuicSelfIssuedConnectionIdManager* GetSelfIssuedConnectionIdManager(
QuicConnection* connection);
+
+ static std::unique_ptr<QuicSelfIssuedConnectionIdManager>
+ MakeSelfIssuedConnectionIdManager(QuicConnection* connection);
};
} // namespace test
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_dispatcher_peer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_dispatcher_peer.cc
index 8002170ad90..341d5acfc84 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_dispatcher_peer.cc
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_dispatcher_peer.cc
@@ -133,5 +133,11 @@ const QuicSession* QuicDispatcherPeer::FindSession(
: it->second.get();
}
+// static
+QuicAlarm* QuicDispatcherPeer::GetClearResetAddressesAlarm(
+ QuicDispatcher* dispatcher) {
+ return dispatcher->clear_stateless_reset_addresses_alarm_.get();
+}
+
} // namespace test
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_dispatcher_peer.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_dispatcher_peer.h
index fc8ab2014ae..ec83be4f9f2 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_dispatcher_peer.h
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_dispatcher_peer.h
@@ -76,6 +76,8 @@ class QuicDispatcherPeer {
// Find the corresponding session if exsits.
static const QuicSession* FindSession(const QuicDispatcher* dispatcher,
QuicConnectionId id);
+
+ static QuicAlarm* GetClearResetAddressesAlarm(QuicDispatcher* dispatcher);
};
} // namespace test
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_spdy_session_peer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_spdy_session_peer.cc
index a27f073e993..f0f99ee989e 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_spdy_session_peer.cc
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_spdy_session_peer.cc
@@ -40,18 +40,14 @@ spdy::SpdyFramer* QuicSpdySessionPeer::GetSpdyFramer(QuicSpdySession* session) {
}
void QuicSpdySessionPeer::SetMaxInboundHeaderListSize(
- QuicSpdySession* session,
- size_t max_inbound_header_size) {
+ QuicSpdySession* session, size_t max_inbound_header_size) {
session->set_max_inbound_header_list_size(max_inbound_header_size);
}
// static
size_t QuicSpdySessionPeer::WriteHeadersOnHeadersStream(
- QuicSpdySession* session,
- QuicStreamId id,
- spdy::SpdyHeaderBlock headers,
- bool fin,
- const spdy::SpdyStreamPrecedence& precedence,
+ QuicSpdySession* session, QuicStreamId id, spdy::SpdyHeaderBlock headers,
+ bool fin, const spdy::SpdyStreamPrecedence& precedence,
QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) {
return session->WriteHeadersOnHeadersStream(
id, std::move(headers), fin, precedence, std::move(ack_listener));
@@ -100,22 +96,22 @@ QpackReceiveStream* QuicSpdySessionPeer::GetQpackEncoderReceiveStream(
}
// static
-void QuicSpdySessionPeer::SetH3DatagramSupported(QuicSpdySession* session,
- bool h3_datagram_supported) {
- session->h3_datagram_supported_ = h3_datagram_supported;
+void QuicSpdySessionPeer::SetHttpDatagramSupport(
+ QuicSpdySession* session, HttpDatagramSupport http_datagram_support) {
+ session->http_datagram_support_ = http_datagram_support;
}
// static
-bool QuicSpdySessionPeer::ShouldNegotiateHttp3Datagram(
+HttpDatagramSupport QuicSpdySessionPeer::LocalHttpDatagramSupport(
QuicSpdySession* session) {
- return session->ShouldNegotiateHttp3Datagram();
+ return session->LocalHttpDatagramSupport();
}
// static
-void QuicSpdySessionPeer::EnableWebTransport(QuicSpdySession& session) {
- QUICHE_DCHECK(session.WillNegotiateWebTransport());
- session.h3_datagram_supported_ = true;
- session.peer_supports_webtransport_ = true;
+void QuicSpdySessionPeer::EnableWebTransport(QuicSpdySession* session) {
+ QUICHE_DCHECK(session->WillNegotiateWebTransport());
+ SetHttpDatagramSupport(session, HttpDatagramSupport::kDraft04);
+ session->peer_supports_webtransport_ = true;
}
} // namespace test
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_spdy_session_peer.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_spdy_session_peer.h
index 0d06c4ddfad..ba28e67c0ee 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_spdy_session_peer.h
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_spdy_session_peer.h
@@ -7,6 +7,7 @@
#include "quic/core/http/quic_receive_control_stream.h"
#include "quic/core/http/quic_send_control_stream.h"
+#include "quic/core/http/quic_spdy_session.h"
#include "quic/core/qpack/qpack_receive_stream.h"
#include "quic/core/qpack/qpack_send_stream.h"
#include "quic/core/quic_packets.h"
@@ -16,7 +17,6 @@
namespace quic {
class QuicHeadersStream;
-class QuicSpdySession;
namespace test {
@@ -32,11 +32,8 @@ class QuicSpdySessionPeer {
static void SetMaxInboundHeaderListSize(QuicSpdySession* session,
size_t max_inbound_header_size);
static size_t WriteHeadersOnHeadersStream(
- QuicSpdySession* session,
- QuicStreamId id,
- spdy::SpdyHeaderBlock headers,
- bool fin,
- const spdy::SpdyStreamPrecedence& precedence,
+ QuicSpdySession* session, QuicStreamId id, spdy::SpdyHeaderBlock headers,
+ bool fin, const spdy::SpdyStreamPrecedence& precedence,
QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener);
// |session| can't be nullptr.
static QuicStreamId GetNextOutgoingUnidirectionalStreamId(
@@ -50,10 +47,10 @@ class QuicSpdySessionPeer {
QuicSpdySession* session);
static QpackReceiveStream* GetQpackEncoderReceiveStream(
QuicSpdySession* session);
- static void SetH3DatagramSupported(QuicSpdySession* session,
- bool h3_datagram_supported);
- static bool ShouldNegotiateHttp3Datagram(QuicSpdySession* session);
- static void EnableWebTransport(QuicSpdySession& session);
+ static void SetHttpDatagramSupport(QuicSpdySession* session,
+ HttpDatagramSupport http_datagram_support);
+ static HttpDatagramSupport LocalHttpDatagramSupport(QuicSpdySession* session);
+ static void EnableWebTransport(QuicSpdySession* session);
};
} // namespace test
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_stream_sequencer_buffer_peer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_stream_sequencer_buffer_peer.cc
index 01ada82a741..a950f0ba323 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_stream_sequencer_buffer_peer.cc
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_stream_sequencer_buffer_peer.cc
@@ -46,8 +46,7 @@ bool QuicStreamSequencerBufferPeer::IsBlockArrayEmpty() {
return true;
}
- size_t count = buffer_->allocate_blocks_on_demand_ ? current_blocks_count()
- : max_blocks_count();
+ size_t count = current_blocks_count();
for (size_t i = 0; i < count; i++) {
if (buffer_->blocks_[i] != nullptr) {
return false;
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_backend.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_backend.cc
index eb419b607f5..3cfe9279a3a 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_backend.cc
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_backend.cc
@@ -7,16 +7,64 @@
#include <cstring>
#include <memory>
+#include "absl/strings/str_cat.h"
+#include "absl/strings/str_split.h"
#include "absl/strings/string_view.h"
#include "quic/core/quic_buffer_allocator.h"
#include "quic/core/quic_simple_buffer_allocator.h"
#include "quic/core/web_transport_interface.h"
#include "quic/platform/api/quic_mem_slice.h"
+#include "quic/test_tools/web_transport_resets_backend.h"
#include "quic/tools/web_transport_test_visitors.h"
namespace quic {
namespace test {
+namespace {
+
+// SessionCloseVisitor implements the "/session-close" endpoint. If the client
+// sends a unidirectional stream of format "code message" to this endpoint, it
+// will close the session with the corresponding error code and error message.
+// For instance, sending "42 test error" will cause it to be closed with code 42
+// and message "test error".
+class SessionCloseVisitor : public WebTransportVisitor {
+ public:
+ SessionCloseVisitor(WebTransportSession* session) : session_(session) {}
+
+ void OnSessionReady(const spdy::SpdyHeaderBlock& /*headers*/) override {}
+ void OnSessionClosed(WebTransportSessionError /*error_code*/,
+ const std::string& /*error_message*/) override {}
+
+ void OnIncomingBidirectionalStreamAvailable() override {}
+ void OnIncomingUnidirectionalStreamAvailable() override {
+ WebTransportStream* stream = session_->AcceptIncomingUnidirectionalStream();
+ if (stream == nullptr) {
+ return;
+ }
+ stream->SetVisitor(
+ std::make_unique<WebTransportUnidirectionalEchoReadVisitor>(
+ stream, [this](const std::string& data) {
+ std::pair<absl::string_view, absl::string_view> parsed =
+ absl::StrSplit(data, absl::MaxSplits(' ', 1));
+ WebTransportSessionError error_code = 0;
+ bool success = absl::SimpleAtoi(parsed.first, &error_code);
+ QUICHE_DCHECK(success) << data;
+ session_->CloseSession(error_code, parsed.second);
+ }));
+ stream->visitor()->OnCanRead();
+ }
+
+ void OnDatagramReceived(absl::string_view /*datagram*/) override {}
+
+ void OnCanCreateNewOutgoingBidirectionalStream() override {}
+ void OnCanCreateNewOutgoingUnidirectionalStream() override {}
+
+ private:
+ WebTransportSession* session_; // Not owned.
+};
+
+} // namespace
+
QuicSimpleServerBackend::WebTransportResponse
QuicTestBackend::ProcessWebTransportRequest(
const spdy::Http2HeaderBlock& request_headers,
@@ -33,13 +81,38 @@ QuicTestBackend::ProcessWebTransportRequest(
return response;
}
absl::string_view path = path_it->second;
- if (path == "/echo") {
+ // Match any "/echo.*" pass, e.g. "/echo_foobar"
+ if (absl::StartsWith(path, "/echo")) {
WebTransportResponse response;
response.response_headers[":status"] = "200";
+ // Add response headers if the paramer has "set-header=XXX:YYY" query.
+ GURL url = GURL(absl::StrCat("https://localhost", path));
+ const std::vector<std::string>& params = absl::StrSplit(url.query(), '&');
+ for (const auto& param : params) {
+ absl::string_view param_view = param;
+ if (absl::ConsumePrefix(&param_view, "set-header=")) {
+ const std::vector<absl::string_view> header_value =
+ absl::StrSplit(param_view, ':');
+ if (header_value.size() == 2 &&
+ !absl::StartsWith(header_value[0], ":")) {
+ response.response_headers[header_value[0]] = header_value[1];
+ }
+ }
+ }
+
response.visitor =
std::make_unique<EchoWebTransportSessionVisitor>(session);
return response;
}
+ if (path == "/resets") {
+ return WebTransportResetsBackend(request_headers, session);
+ }
+ if (path == "/session-close") {
+ WebTransportResponse response;
+ response.response_headers[":status"] = "200";
+ response.visitor = std::make_unique<SessionCloseVisitor>(session);
+ return response;
+ }
WebTransportResponse response;
response.response_headers[":status"] = "404";
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.cc
index 126b87e039c..9a7fd85b280 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.cc
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.cc
@@ -1312,20 +1312,6 @@ StreamType DetermineStreamType(QuicStreamId id,
: default_type;
}
-QuicMemSliceSpan MakeSpan(QuicBufferAllocator* allocator,
- absl::string_view message_data,
- QuicMemSliceStorage* storage) {
- if (message_data.length() == 0) {
- *storage =
- QuicMemSliceStorage(nullptr, 0, allocator, kMaxOutgoingPacketSize);
- return storage->ToSpan();
- }
- struct iovec iov = {const_cast<char*>(message_data.data()),
- message_data.length()};
- *storage = QuicMemSliceStorage(&iov, 1, allocator, kMaxOutgoingPacketSize);
- return storage->ToSpan();
-}
-
QuicMemSlice MemSliceFromString(absl::string_view data) {
if (data.empty()) {
return QuicMemSlice();
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.h
index 06f3eeca7c2..e746ddb33e1 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.h
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.h
@@ -24,6 +24,7 @@
#include "quic/core/http/quic_spdy_session.h"
#include "quic/core/quic_connection.h"
#include "quic/core/quic_connection_id.h"
+#include "quic/core/quic_error_codes.h"
#include "quic/core/quic_framer.h"
#include "quic/core/quic_packet_writer.h"
#include "quic/core/quic_path_validator.h"
@@ -103,26 +104,17 @@ void DisableQuicVersionsWithTls();
// constructed packet, the framer must be set to use NullDecrypter.
QuicEncryptedPacket* ConstructEncryptedPacket(
QuicConnectionId destination_connection_id,
- QuicConnectionId source_connection_id,
- bool version_flag,
- bool reset_flag,
- uint64_t packet_number,
- const std::string& data,
- bool full_padding,
+ QuicConnectionId source_connection_id, bool version_flag, bool reset_flag,
+ uint64_t packet_number, const std::string& data, bool full_padding,
QuicConnectionIdIncluded destination_connection_id_included,
QuicConnectionIdIncluded source_connection_id_included,
QuicPacketNumberLength packet_number_length,
- ParsedQuicVersionVector* versions,
- Perspective perspective);
+ ParsedQuicVersionVector* versions, Perspective perspective);
QuicEncryptedPacket* ConstructEncryptedPacket(
QuicConnectionId destination_connection_id,
- QuicConnectionId source_connection_id,
- bool version_flag,
- bool reset_flag,
- uint64_t packet_number,
- const std::string& data,
- bool full_padding,
+ QuicConnectionId source_connection_id, bool version_flag, bool reset_flag,
+ uint64_t packet_number, const std::string& data, bool full_padding,
QuicConnectionIdIncluded destination_connection_id_included,
QuicConnectionIdIncluded source_connection_id_included,
QuicPacketNumberLength packet_number_length,
@@ -134,11 +126,8 @@ QuicEncryptedPacket* ConstructEncryptedPacket(
// constructed packet, the framer must be set to use NullDecrypter.
QuicEncryptedPacket* ConstructEncryptedPacket(
QuicConnectionId destination_connection_id,
- QuicConnectionId source_connection_id,
- bool version_flag,
- bool reset_flag,
- uint64_t packet_number,
- const std::string& data,
+ QuicConnectionId source_connection_id, bool version_flag, bool reset_flag,
+ uint64_t packet_number, const std::string& data,
QuicConnectionIdIncluded destination_connection_id_included,
QuicConnectionIdIncluded source_connection_id_included,
QuicPacketNumberLength packet_number_length,
@@ -147,11 +136,8 @@ QuicEncryptedPacket* ConstructEncryptedPacket(
// This form assumes |versions| == nullptr.
QuicEncryptedPacket* ConstructEncryptedPacket(
QuicConnectionId destination_connection_id,
- QuicConnectionId source_connection_id,
- bool version_flag,
- bool reset_flag,
- uint64_t packet_number,
- const std::string& data,
+ QuicConnectionId source_connection_id, bool version_flag, bool reset_flag,
+ uint64_t packet_number, const std::string& data,
QuicConnectionIdIncluded destination_connection_id_included,
QuicConnectionIdIncluded source_connection_id_included,
QuicPacketNumberLength packet_number_length);
@@ -161,11 +147,8 @@ QuicEncryptedPacket* ConstructEncryptedPacket(
// |versions| == nullptr.
QuicEncryptedPacket* ConstructEncryptedPacket(
QuicConnectionId destination_connection_id,
- QuicConnectionId source_connection_id,
- bool version_flag,
- bool reset_flag,
- uint64_t packet_number,
- const std::string& data);
+ QuicConnectionId source_connection_id, bool version_flag, bool reset_flag,
+ uint64_t packet_number, const std::string& data);
// Creates a client-to-server ZERO-RTT packet that will fail to decrypt.
std::unique_ptr<QuicEncryptedPacket> GetUndecryptableEarlyPacket(
@@ -175,8 +158,7 @@ std::unique_ptr<QuicEncryptedPacket> GetUndecryptableEarlyPacket(
// Constructs a received packet for testing. The caller must take ownership
// of the returned pointer.
QuicReceivedPacket* ConstructReceivedPacket(
- const QuicEncryptedPacket& encrypted_packet,
- QuicTime receipt_time);
+ const QuicEncryptedPacket& encrypted_packet, QuicTime receipt_time);
// Create an encrypted packet for testing whose data portion erroneous.
// The specific way the data portion is erroneous is not specified, but
@@ -185,15 +167,11 @@ QuicReceivedPacket* ConstructReceivedPacket(
// constructed packet, the framer must be set to use NullDecrypter.
QuicEncryptedPacket* ConstructMisFramedEncryptedPacket(
QuicConnectionId destination_connection_id,
- QuicConnectionId source_connection_id,
- bool version_flag,
- bool reset_flag,
- uint64_t packet_number,
- const std::string& data,
+ QuicConnectionId source_connection_id, bool version_flag, bool reset_flag,
+ uint64_t packet_number, const std::string& data,
QuicConnectionIdIncluded destination_connection_id_included,
QuicConnectionIdIncluded source_connection_id_included,
- QuicPacketNumberLength packet_number_length,
- ParsedQuicVersion version,
+ QuicPacketNumberLength packet_number_length, ParsedQuicVersion version,
Perspective perspective);
// Returns QuicConfig set to default values.
@@ -228,8 +206,7 @@ QuicAckFrame MakeAckFrameWithAckBlocks(size_t num_ack_blocks,
// Testing convenice method to construct a QuicAckFrame with |largest_acked|,
// ack blocks of width 1 packet and |gap_size|.
-QuicAckFrame MakeAckFrameWithGaps(uint64_t gap_size,
- size_t max_num_gaps,
+QuicAckFrame MakeAckFrameWithGaps(uint64_t gap_size, size_t max_num_gaps,
uint64_t largest_acked);
// Returns the encryption level that corresponds to the header type in
@@ -241,15 +218,12 @@ EncryptionLevel HeaderToEncryptionLevel(const QuicPacketHeader& header);
// is populated with the fields in |header| and |frames|, or is nullptr if the
// packet could not be created.
std::unique_ptr<QuicPacket> BuildUnsizedDataPacket(
- QuicFramer* framer,
- const QuicPacketHeader& header,
+ QuicFramer* framer, const QuicPacketHeader& header,
const QuicFrames& frames);
// Returns a QuicPacket that is owned by the caller, and of size |packet_size|.
std::unique_ptr<QuicPacket> BuildUnsizedDataPacket(
- QuicFramer* framer,
- const QuicPacketHeader& header,
- const QuicFrames& frames,
- size_t packet_size);
+ QuicFramer* framer, const QuicPacketHeader& header,
+ const QuicFrames& frames, size_t packet_size);
// Compute SHA-1 hash of the supplied std::string.
std::string Sha1Hash(absl::string_view data);
@@ -297,21 +271,14 @@ class MockFramerVisitor : public QuicFramerVisitorInterface {
MOCK_METHOD(void, OnError, (QuicFramer*), (override));
// The constructor sets this up to return false by default.
- MOCK_METHOD(bool,
- OnProtocolVersionMismatch,
- (ParsedQuicVersion version),
+ MOCK_METHOD(bool, OnProtocolVersionMismatch, (ParsedQuicVersion version),
(override));
MOCK_METHOD(void, OnPacket, (), (override));
- MOCK_METHOD(void,
- OnPublicResetPacket,
- (const QuicPublicResetPacket& header),
- (override));
- MOCK_METHOD(void,
- OnVersionNegotiationPacket,
- (const QuicVersionNegotiationPacket& packet),
+ MOCK_METHOD(void, OnPublicResetPacket, (const QuicPublicResetPacket& header),
(override));
- MOCK_METHOD(void,
- OnRetryPacket,
+ MOCK_METHOD(void, OnVersionNegotiationPacket,
+ (const QuicVersionNegotiationPacket& packet), (override));
+ MOCK_METHOD(void, OnRetryPacket,
(QuicConnectionId original_connection_id,
QuicConnectionId new_connection_id,
absl::string_view retry_token,
@@ -319,133 +286,75 @@ class MockFramerVisitor : public QuicFramerVisitorInterface {
absl::string_view retry_without_tag),
(override));
// The constructor sets this up to return true by default.
- MOCK_METHOD(bool,
- OnUnauthenticatedHeader,
- (const QuicPacketHeader& header),
+ MOCK_METHOD(bool, OnUnauthenticatedHeader, (const QuicPacketHeader& header),
(override));
// The constructor sets this up to return true by default.
- MOCK_METHOD(bool,
- OnUnauthenticatedPublicHeader,
- (const QuicPacketHeader& header),
+ MOCK_METHOD(bool, OnUnauthenticatedPublicHeader,
+ (const QuicPacketHeader& header), (override));
+ MOCK_METHOD(void, OnDecryptedPacket, (size_t length, EncryptionLevel level),
(override));
- MOCK_METHOD(void,
- OnDecryptedPacket,
- (size_t length, EncryptionLevel level),
+ MOCK_METHOD(bool, OnPacketHeader, (const QuicPacketHeader& header),
(override));
- MOCK_METHOD(bool,
- OnPacketHeader,
- (const QuicPacketHeader& header),
+ MOCK_METHOD(void, OnCoalescedPacket, (const QuicEncryptedPacket& packet),
(override));
- MOCK_METHOD(void,
- OnCoalescedPacket,
- (const QuicEncryptedPacket& packet),
- (override));
- MOCK_METHOD(void,
- OnUndecryptablePacket,
+ MOCK_METHOD(void, OnUndecryptablePacket,
(const QuicEncryptedPacket& packet,
- EncryptionLevel decryption_level,
- bool has_decryption_key),
+ EncryptionLevel decryption_level, bool has_decryption_key),
(override));
MOCK_METHOD(bool, OnStreamFrame, (const QuicStreamFrame& frame), (override));
MOCK_METHOD(bool, OnCryptoFrame, (const QuicCryptoFrame& frame), (override));
- MOCK_METHOD(bool,
- OnAckFrameStart,
- (QuicPacketNumber, QuicTime::Delta),
+ MOCK_METHOD(bool, OnAckFrameStart, (QuicPacketNumber, QuicTime::Delta),
(override));
- MOCK_METHOD(bool,
- OnAckRange,
- (QuicPacketNumber, QuicPacketNumber),
+ MOCK_METHOD(bool, OnAckRange, (QuicPacketNumber, QuicPacketNumber),
(override));
MOCK_METHOD(bool, OnAckTimestamp, (QuicPacketNumber, QuicTime), (override));
MOCK_METHOD(bool, OnAckFrameEnd, (QuicPacketNumber), (override));
- MOCK_METHOD(bool,
- OnStopWaitingFrame,
- (const QuicStopWaitingFrame& frame),
+ MOCK_METHOD(bool, OnStopWaitingFrame, (const QuicStopWaitingFrame& frame),
(override));
- MOCK_METHOD(bool,
- OnPaddingFrame,
- (const QuicPaddingFrame& frame),
+ MOCK_METHOD(bool, OnPaddingFrame, (const QuicPaddingFrame& frame),
(override));
MOCK_METHOD(bool, OnPingFrame, (const QuicPingFrame& frame), (override));
- MOCK_METHOD(bool,
- OnRstStreamFrame,
- (const QuicRstStreamFrame& frame),
- (override));
- MOCK_METHOD(bool,
- OnConnectionCloseFrame,
- (const QuicConnectionCloseFrame& frame),
+ MOCK_METHOD(bool, OnRstStreamFrame, (const QuicRstStreamFrame& frame),
(override));
- MOCK_METHOD(bool,
- OnNewConnectionIdFrame,
- (const QuicNewConnectionIdFrame& frame),
+ MOCK_METHOD(bool, OnConnectionCloseFrame,
+ (const QuicConnectionCloseFrame& frame), (override));
+ MOCK_METHOD(bool, OnNewConnectionIdFrame,
+ (const QuicNewConnectionIdFrame& frame), (override));
+ MOCK_METHOD(bool, OnRetireConnectionIdFrame,
+ (const QuicRetireConnectionIdFrame& frame), (override));
+ MOCK_METHOD(bool, OnNewTokenFrame, (const QuicNewTokenFrame& frame),
(override));
- MOCK_METHOD(bool,
- OnRetireConnectionIdFrame,
- (const QuicRetireConnectionIdFrame& frame),
+ MOCK_METHOD(bool, OnStopSendingFrame, (const QuicStopSendingFrame& frame),
(override));
- MOCK_METHOD(bool,
- OnNewTokenFrame,
- (const QuicNewTokenFrame& frame),
+ MOCK_METHOD(bool, OnPathChallengeFrame, (const QuicPathChallengeFrame& frame),
(override));
- MOCK_METHOD(bool,
- OnStopSendingFrame,
- (const QuicStopSendingFrame& frame),
- (override));
- MOCK_METHOD(bool,
- OnPathChallengeFrame,
- (const QuicPathChallengeFrame& frame),
- (override));
- MOCK_METHOD(bool,
- OnPathResponseFrame,
- (const QuicPathResponseFrame& frame),
+ MOCK_METHOD(bool, OnPathResponseFrame, (const QuicPathResponseFrame& frame),
(override));
MOCK_METHOD(bool, OnGoAwayFrame, (const QuicGoAwayFrame& frame), (override));
- MOCK_METHOD(bool,
- OnMaxStreamsFrame,
- (const QuicMaxStreamsFrame& frame),
- (override));
- MOCK_METHOD(bool,
- OnStreamsBlockedFrame,
- (const QuicStreamsBlockedFrame& frame),
+ MOCK_METHOD(bool, OnMaxStreamsFrame, (const QuicMaxStreamsFrame& frame),
(override));
- MOCK_METHOD(bool,
- OnWindowUpdateFrame,
- (const QuicWindowUpdateFrame& frame),
+ MOCK_METHOD(bool, OnStreamsBlockedFrame,
+ (const QuicStreamsBlockedFrame& frame), (override));
+ MOCK_METHOD(bool, OnWindowUpdateFrame, (const QuicWindowUpdateFrame& frame),
(override));
- MOCK_METHOD(bool,
- OnBlockedFrame,
- (const QuicBlockedFrame& frame),
+ MOCK_METHOD(bool, OnBlockedFrame, (const QuicBlockedFrame& frame),
(override));
- MOCK_METHOD(bool,
- OnMessageFrame,
- (const QuicMessageFrame& frame),
+ MOCK_METHOD(bool, OnMessageFrame, (const QuicMessageFrame& frame),
(override));
- MOCK_METHOD(bool,
- OnHandshakeDoneFrame,
- (const QuicHandshakeDoneFrame& frame),
+ MOCK_METHOD(bool, OnHandshakeDoneFrame, (const QuicHandshakeDoneFrame& frame),
(override));
- MOCK_METHOD(bool,
- OnAckFrequencyFrame,
- (const QuicAckFrequencyFrame& frame),
+ MOCK_METHOD(bool, OnAckFrequencyFrame, (const QuicAckFrequencyFrame& frame),
(override));
MOCK_METHOD(void, OnPacketComplete, (), (override));
- MOCK_METHOD(bool,
- IsValidStatelessResetToken,
- (const StatelessResetToken&),
+ MOCK_METHOD(bool, IsValidStatelessResetToken, (const StatelessResetToken&),
(const, override));
- MOCK_METHOD(void,
- OnAuthenticatedIetfStatelessResetPacket,
- (const QuicIetfStatelessResetPacket&),
- (override));
+ MOCK_METHOD(void, OnAuthenticatedIetfStatelessResetPacket,
+ (const QuicIetfStatelessResetPacket&), (override));
MOCK_METHOD(void, OnKeyUpdate, (KeyUpdateReason), (override));
MOCK_METHOD(void, OnDecryptedFirstPacketInKeyPhase, (), (override));
MOCK_METHOD(std::unique_ptr<QuicDecrypter>,
- AdvanceKeysAndCreateCurrentOneRttDecrypter,
- (),
- (override));
- MOCK_METHOD(std::unique_ptr<QuicEncrypter>,
- CreateCurrentOneRttEncrypter,
- (),
+ AdvanceKeysAndCreateCurrentOneRttDecrypter, (), (override));
+ MOCK_METHOD(std::unique_ptr<QuicEncrypter>, CreateCurrentOneRttEncrypter, (),
(override));
};
@@ -529,97 +438,66 @@ class MockQuicConnectionVisitor : public QuicConnectionVisitorInterface {
MOCK_METHOD(void, OnStreamFrame, (const QuicStreamFrame& frame), (override));
MOCK_METHOD(void, OnCryptoFrame, (const QuicCryptoFrame& frame), (override));
- MOCK_METHOD(void,
- OnWindowUpdateFrame,
- (const QuicWindowUpdateFrame& frame),
+ MOCK_METHOD(void, OnWindowUpdateFrame, (const QuicWindowUpdateFrame& frame),
(override));
- MOCK_METHOD(void,
- OnBlockedFrame,
- (const QuicBlockedFrame& frame),
+ MOCK_METHOD(void, OnBlockedFrame, (const QuicBlockedFrame& frame),
(override));
MOCK_METHOD(void, OnRstStream, (const QuicRstStreamFrame& frame), (override));
MOCK_METHOD(void, OnGoAway, (const QuicGoAwayFrame& frame), (override));
MOCK_METHOD(void, OnMessageReceived, (absl::string_view message), (override));
MOCK_METHOD(void, OnHandshakeDoneReceived, (), (override));
MOCK_METHOD(void, OnNewTokenReceived, (absl::string_view token), (override));
- MOCK_METHOD(void,
- OnConnectionClosed,
+ MOCK_METHOD(void, OnConnectionClosed,
(const QuicConnectionCloseFrame& frame,
ConnectionCloseSource source),
(override));
MOCK_METHOD(void, OnWriteBlocked, (), (override));
MOCK_METHOD(void, OnCanWrite, (), (override));
MOCK_METHOD(bool, SendProbingData, (), (override));
- MOCK_METHOD(bool,
- ValidateStatelessReset,
+ MOCK_METHOD(bool, ValidateStatelessReset,
(const quic::QuicSocketAddress&, const quic::QuicSocketAddress&),
(override));
MOCK_METHOD(void, OnCongestionWindowChange, (QuicTime now), (override));
- MOCK_METHOD(void,
- OnConnectionMigration,
- (AddressChangeType type),
+ MOCK_METHOD(void, OnConnectionMigration, (AddressChangeType type),
(override));
MOCK_METHOD(void, OnPathDegrading, (), (override));
MOCK_METHOD(void, OnForwardProgressMadeAfterPathDegrading, (), (override));
MOCK_METHOD(bool, WillingAndAbleToWrite, (), (const, override));
MOCK_METHOD(bool, ShouldKeepConnectionAlive, (), (const, override));
MOCK_METHOD(std::string, GetStreamsInfoForLogging, (), (const, override));
- MOCK_METHOD(void,
- OnSuccessfulVersionNegotiation,
- (const ParsedQuicVersion& version),
- (override));
- MOCK_METHOD(void,
- OnPacketReceived,
+ MOCK_METHOD(void, OnSuccessfulVersionNegotiation,
+ (const ParsedQuicVersion& version), (override));
+ MOCK_METHOD(void, OnPacketReceived,
(const QuicSocketAddress& self_address,
const QuicSocketAddress& peer_address,
bool is_connectivity_probe),
(override));
MOCK_METHOD(void, OnAckNeedsRetransmittableFrame, (), (override));
- MOCK_METHOD(void,
- SendAckFrequency,
- (const QuicAckFrequencyFrame& frame),
- (override));
- MOCK_METHOD(void,
- SendNewConnectionId,
- (const QuicNewConnectionIdFrame& frame),
- (override));
- MOCK_METHOD(void,
- SendRetireConnectionId,
- (uint64_t sequence_number),
+ MOCK_METHOD(void, SendAckFrequency, (const QuicAckFrequencyFrame& frame),
(override));
- MOCK_METHOD(void,
- OnServerConnectionIdIssued,
- (const QuicConnectionId& server_connection_id),
- (override));
- MOCK_METHOD(void,
- OnServerConnectionIdRetired,
- (const QuicConnectionId& server_connection_id),
+ MOCK_METHOD(void, SendNewConnectionId,
+ (const QuicNewConnectionIdFrame& frame), (override));
+ MOCK_METHOD(void, SendRetireConnectionId, (uint64_t sequence_number),
(override));
+ MOCK_METHOD(void, OnServerConnectionIdIssued,
+ (const QuicConnectionId& server_connection_id), (override));
+ MOCK_METHOD(void, OnServerConnectionIdRetired,
+ (const QuicConnectionId& server_connection_id), (override));
MOCK_METHOD(bool, AllowSelfAddressChange, (), (const, override));
MOCK_METHOD(HandshakeState, GetHandshakeState, (), (const, override));
- MOCK_METHOD(bool,
- OnMaxStreamsFrame,
- (const QuicMaxStreamsFrame& frame),
- (override));
- MOCK_METHOD(bool,
- OnStreamsBlockedFrame,
- (const QuicStreamsBlockedFrame& frame),
+ MOCK_METHOD(bool, OnMaxStreamsFrame, (const QuicMaxStreamsFrame& frame),
(override));
- MOCK_METHOD(void,
- OnStopSendingFrame,
- (const QuicStopSendingFrame& frame),
+ MOCK_METHOD(bool, OnStreamsBlockedFrame,
+ (const QuicStreamsBlockedFrame& frame), (override));
+ MOCK_METHOD(void, OnStopSendingFrame, (const QuicStopSendingFrame& frame),
(override));
MOCK_METHOD(void, OnPacketDecrypted, (EncryptionLevel), (override));
MOCK_METHOD(void, OnOneRttPacketAcknowledged, (), (override));
MOCK_METHOD(void, OnHandshakePacketSent, (), (override));
MOCK_METHOD(void, OnKeyUpdate, (KeyUpdateReason), (override));
MOCK_METHOD(std::unique_ptr<QuicDecrypter>,
- AdvanceKeysAndCreateCurrentOneRttDecrypter,
- (),
- (override));
- MOCK_METHOD(std::unique_ptr<QuicEncrypter>,
- CreateCurrentOneRttEncrypter,
- (),
+ AdvanceKeysAndCreateCurrentOneRttDecrypter, (), (override));
+ MOCK_METHOD(std::unique_ptr<QuicEncrypter>, CreateCurrentOneRttEncrypter, (),
(override));
MOCK_METHOD(void, BeforeConnectionCloseSent, (), (override));
MOCK_METHOD(bool, ValidateToken, (absl::string_view), (const, override));
@@ -672,36 +550,57 @@ class MockAlarmFactory : public QuicAlarmFactory {
}
};
+class TestAlarmFactory : public QuicAlarmFactory {
+ public:
+ class TestAlarm : public QuicAlarm {
+ public:
+ explicit TestAlarm(QuicArenaScopedPtr<QuicAlarm::Delegate> delegate)
+ : QuicAlarm(std::move(delegate)) {}
+
+ void SetImpl() override {}
+ void CancelImpl() override {}
+ using QuicAlarm::Fire;
+ };
+
+ TestAlarmFactory() {}
+ TestAlarmFactory(const TestAlarmFactory&) = delete;
+ TestAlarmFactory& operator=(const TestAlarmFactory&) = delete;
+
+ QuicAlarm* CreateAlarm(QuicAlarm::Delegate* delegate) override {
+ return new TestAlarm(QuicArenaScopedPtr<QuicAlarm::Delegate>(delegate));
+ }
+
+ QuicArenaScopedPtr<QuicAlarm> CreateAlarm(
+ QuicArenaScopedPtr<QuicAlarm::Delegate> delegate,
+ QuicConnectionArena* arena) override {
+ return arena->New<TestAlarm>(std::move(delegate));
+ }
+};
+
class MockQuicConnection : public QuicConnection {
public:
// Uses a ConnectionId of 42 and 127.0.0.1:123.
MockQuicConnection(MockQuicConnectionHelper* helper,
- MockAlarmFactory* alarm_factory,
- Perspective perspective);
+ MockAlarmFactory* alarm_factory, Perspective perspective);
// Uses a ConnectionId of 42.
MockQuicConnection(QuicSocketAddress address,
MockQuicConnectionHelper* helper,
- MockAlarmFactory* alarm_factory,
- Perspective perspective);
+ MockAlarmFactory* alarm_factory, Perspective perspective);
// Uses 127.0.0.1:123.
MockQuicConnection(QuicConnectionId connection_id,
MockQuicConnectionHelper* helper,
- MockAlarmFactory* alarm_factory,
- Perspective perspective);
+ MockAlarmFactory* alarm_factory, Perspective perspective);
// Uses a ConnectionId of 42, and 127.0.0.1:123.
MockQuicConnection(MockQuicConnectionHelper* helper,
- MockAlarmFactory* alarm_factory,
- Perspective perspective,
+ MockAlarmFactory* alarm_factory, Perspective perspective,
const ParsedQuicVersionVector& supported_versions);
- MockQuicConnection(QuicConnectionId connection_id,
- QuicSocketAddress address,
+ MockQuicConnection(QuicConnectionId connection_id, QuicSocketAddress address,
MockQuicConnectionHelper* helper,
- MockAlarmFactory* alarm_factory,
- Perspective perspective,
+ MockAlarmFactory* alarm_factory, Perspective perspective,
const ParsedQuicVersionVector& supported_versions);
MockQuicConnection(const MockQuicConnection&) = delete;
MockQuicConnection& operator=(const MockQuicConnection&) = delete;
@@ -713,64 +612,45 @@ class MockQuicConnection : public QuicConnection {
// will advance the time of the MockClock.
void AdvanceTime(QuicTime::Delta delta);
- MOCK_METHOD(void,
- ProcessUdpPacket,
+ MOCK_METHOD(void, ProcessUdpPacket,
(const QuicSocketAddress& self_address,
const QuicSocketAddress& peer_address,
const QuicReceivedPacket& packet),
(override));
- MOCK_METHOD(void,
- CloseConnection,
- (QuicErrorCode error,
- const std::string& details,
+ MOCK_METHOD(void, CloseConnection,
+ (QuicErrorCode error, const std::string& details,
ConnectionCloseBehavior connection_close_behavior),
(override));
- MOCK_METHOD(void,
- CloseConnection,
- (QuicErrorCode error,
- QuicIetfTransportErrorCodes ietf_error,
+ MOCK_METHOD(void, CloseConnection,
+ (QuicErrorCode error, QuicIetfTransportErrorCodes ietf_error,
const std::string& details,
ConnectionCloseBehavior connection_close_behavior),
(override));
- MOCK_METHOD(void,
- SendConnectionClosePacket,
- (QuicErrorCode error,
- QuicIetfTransportErrorCodes ietf_error,
+ MOCK_METHOD(void, SendConnectionClosePacket,
+ (QuicErrorCode error, QuicIetfTransportErrorCodes ietf_error,
const std::string& details),
(override));
MOCK_METHOD(void, OnCanWrite, (), (override));
- MOCK_METHOD(void,
- SendConnectivityProbingResponsePacket,
- (const QuicSocketAddress& peer_address),
- (override));
- MOCK_METHOD(bool,
- SendConnectivityProbingPacket,
+ MOCK_METHOD(void, SendConnectivityProbingResponsePacket,
+ (const QuicSocketAddress& peer_address), (override));
+ MOCK_METHOD(bool, SendConnectivityProbingPacket,
(QuicPacketWriter*, const QuicSocketAddress& peer_address),
(override));
- MOCK_METHOD(void,
- OnSendConnectionState,
- (const CachedNetworkParameters&),
- (override));
- MOCK_METHOD(void,
- ResumeConnectionState,
- (const CachedNetworkParameters&, bool),
+ MOCK_METHOD(void, OnSendConnectionState, (const CachedNetworkParameters&),
(override));
+ MOCK_METHOD(void, ResumeConnectionState,
+ (const CachedNetworkParameters&, bool), (override));
MOCK_METHOD(void, SetMaxPacingRate, (QuicBandwidth), (override));
- MOCK_METHOD(void,
- OnStreamReset,
- (QuicStreamId, QuicRstStreamErrorCode),
+ MOCK_METHOD(void, OnStreamReset, (QuicStreamId, QuicRstStreamErrorCode),
(override));
MOCK_METHOD(bool, SendControlFrame, (const QuicFrame& frame), (override));
MOCK_METHOD(MessageStatus, SendMessage,
(QuicMessageId, absl::Span<QuicMemSlice>, bool), (override));
- MOCK_METHOD(bool,
- SendPathChallenge,
- (const QuicPathFrameBuffer&,
- const QuicSocketAddress&,
- const QuicSocketAddress&,
- const QuicSocketAddress&,
+ MOCK_METHOD(bool, SendPathChallenge,
+ (const QuicPathFrameBuffer&, const QuicSocketAddress&,
+ const QuicSocketAddress&, const QuicSocketAddress&,
QuicPacketWriter*),
(override));
@@ -782,8 +662,7 @@ class MockQuicConnection : public QuicConnection {
void ReallyOnCanWrite() { QuicConnection::OnCanWrite(); }
void ReallyCloseConnection(
- QuicErrorCode error,
- const std::string& details,
+ QuicErrorCode error, const std::string& details,
ConnectionCloseBehavior connection_close_behavior) {
// Call the 4-param method directly instead of the 3-param method, so that
// it doesn't invoke the virtual 4-param method causing the mock 4-param
@@ -793,8 +672,7 @@ class MockQuicConnection : public QuicConnection {
}
void ReallyCloseConnection4(
- QuicErrorCode error,
- QuicIetfTransportErrorCodes ietf_error,
+ QuicErrorCode error, QuicIetfTransportErrorCodes ietf_error,
const std::string& details,
ConnectionCloseBehavior connection_close_behavior) {
QuicConnection::CloseConnection(error, ietf_error, details,
@@ -820,8 +698,7 @@ class MockQuicConnection : public QuicConnection {
}
bool ReallySendConnectivityProbingPacket(
- QuicPacketWriter* probing_writer,
- const QuicSocketAddress& peer_address) {
+ QuicPacketWriter* probing_writer, const QuicSocketAddress& peer_address) {
return QuicConnection::SendConnectivityProbingPacket(probing_writer,
peer_address);
}
@@ -835,18 +712,12 @@ class MockQuicConnection : public QuicConnection {
return QuicConnection::OnPathResponseFrame(frame);
}
- MOCK_METHOD(bool,
- OnPathResponseFrame,
- (const QuicPathResponseFrame&),
+ MOCK_METHOD(bool, OnPathResponseFrame, (const QuicPathResponseFrame&),
(override));
- MOCK_METHOD(bool,
- OnStopSendingFrame,
- (const QuicStopSendingFrame& frame),
- (override));
- MOCK_METHOD(size_t,
- SendCryptoData,
- (EncryptionLevel, size_t, QuicStreamOffset),
+ MOCK_METHOD(bool, OnStopSendingFrame, (const QuicStopSendingFrame& frame),
(override));
+ MOCK_METHOD(size_t, SendCryptoData,
+ (EncryptionLevel, size_t, QuicStreamOffset), (override));
size_t QuicConnection_SendCryptoData(EncryptionLevel level,
size_t write_length,
QuicStreamOffset offset) {
@@ -892,59 +763,47 @@ class MockQuicSession : public QuicSession {
const QuicCryptoStream* GetCryptoStream() const override;
void SetCryptoStream(QuicCryptoStream* crypto_stream);
- MOCK_METHOD(void,
- OnConnectionClosed,
+ MOCK_METHOD(void, OnConnectionClosed,
(const QuicConnectionCloseFrame& frame,
ConnectionCloseSource source),
(override));
MOCK_METHOD(QuicStream*, CreateIncomingStream, (QuicStreamId id), (override));
- MOCK_METHOD(QuicSpdyStream*,
- CreateIncomingStream,
- (PendingStream*),
+ MOCK_METHOD(QuicSpdyStream*, CreateIncomingStream, (PendingStream*),
(override));
MOCK_METHOD(QuicConsumedData, WritevData,
(QuicStreamId id, size_t write_length, QuicStreamOffset offset,
StreamSendingState state, TransmissionType type,
EncryptionLevel level),
(override));
- MOCK_METHOD(bool,
- WriteControlFrame,
- (const QuicFrame& frame, TransmissionType type),
- (override));
- MOCK_METHOD(void,
- MaybeSendRstStreamFrame,
- (QuicStreamId stream_id,
- QuicRstStreamErrorCode error,
+ MOCK_METHOD(bool, WriteControlFrame,
+ (const QuicFrame& frame, TransmissionType type), (override));
+ MOCK_METHOD(void, MaybeSendRstStreamFrame,
+ (QuicStreamId stream_id, QuicResetStreamError error,
QuicStreamOffset bytes_written),
(override));
- MOCK_METHOD(void,
- MaybeSendStopSendingFrame,
- (QuicStreamId stream_id, QuicRstStreamErrorCode error),
- (override));
+ MOCK_METHOD(void, MaybeSendStopSendingFrame,
+ (QuicStreamId stream_id, QuicResetStreamError error), (override));
MOCK_METHOD(bool, ShouldKeepConnectionAlive, (), (const, override));
MOCK_METHOD(std::vector<std::string>, GetAlpnsToOffer, (), (const, override));
- MOCK_METHOD(std::vector<absl::string_view>::const_iterator,
- SelectAlpn,
- (const std::vector<absl::string_view>&),
- (const, override));
+ MOCK_METHOD(std::vector<absl::string_view>::const_iterator, SelectAlpn,
+ (const std::vector<absl::string_view>&), (const, override));
MOCK_METHOD(void, OnAlpnSelected, (absl::string_view), (override));
using QuicSession::ActivateStream;
// Returns a QuicConsumedData that indicates all of |write_length| (and |fin|
// if set) has been consumed.
- QuicConsumedData ConsumeData(QuicStreamId id,
- size_t write_length,
+ QuicConsumedData ConsumeData(QuicStreamId id, size_t write_length,
QuicStreamOffset offset,
- StreamSendingState state,
- TransmissionType type,
+ StreamSendingState state, TransmissionType type,
absl::optional<EncryptionLevel> level);
void ReallyMaybeSendRstStreamFrame(QuicStreamId id,
QuicRstStreamErrorCode error,
QuicStreamOffset bytes_written) {
- QuicSession::MaybeSendRstStreamFrame(id, error, bytes_written);
+ QuicSession::MaybeSendRstStreamFrame(
+ id, QuicResetStreamError::FromInternal(error), bytes_written);
}
private:
@@ -985,6 +844,13 @@ class MockQuicCryptoStream : public QuicCryptoStream {
std::unique_ptr<QuicEncrypter> CreateCurrentOneRttEncrypter() override {
return nullptr;
}
+ bool ExportKeyingMaterial(absl::string_view /*label*/,
+ absl::string_view /*context*/,
+ size_t /*result_len*/,
+ std::string* /*result*/) override {
+ return false;
+ }
+ SSL* GetSsl() const override { return nullptr; }
private:
QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params_;
@@ -1012,26 +878,17 @@ class MockQuicSpdySession : public QuicSpdySession {
}
// From QuicSession.
- MOCK_METHOD(void,
- OnConnectionClosed,
+ MOCK_METHOD(void, OnConnectionClosed,
(const QuicConnectionCloseFrame& frame,
ConnectionCloseSource source),
(override));
- MOCK_METHOD(QuicSpdyStream*,
- CreateIncomingStream,
- (QuicStreamId id),
+ MOCK_METHOD(QuicSpdyStream*, CreateIncomingStream, (QuicStreamId id),
(override));
- MOCK_METHOD(QuicSpdyStream*,
- CreateIncomingStream,
- (PendingStream*),
+ MOCK_METHOD(QuicSpdyStream*, CreateIncomingStream, (PendingStream*),
(override));
- MOCK_METHOD(QuicSpdyStream*,
- CreateOutgoingBidirectionalStream,
- (),
+ MOCK_METHOD(QuicSpdyStream*, CreateOutgoingBidirectionalStream, (),
(override));
- MOCK_METHOD(QuicSpdyStream*,
- CreateOutgoingUnidirectionalStream,
- (),
+ MOCK_METHOD(QuicSpdyStream*, CreateOutgoingUnidirectionalStream, (),
(override));
MOCK_METHOD(bool, ShouldCreateIncomingStream, (QuicStreamId id), (override));
MOCK_METHOD(bool, ShouldCreateOutgoingBidirectionalStream, (), (override));
@@ -1041,53 +898,37 @@ class MockQuicSpdySession : public QuicSpdySession {
StreamSendingState state, TransmissionType type,
EncryptionLevel level),
(override));
- MOCK_METHOD(void,
- MaybeSendRstStreamFrame,
- (QuicStreamId stream_id,
- QuicRstStreamErrorCode error,
+ MOCK_METHOD(void, MaybeSendRstStreamFrame,
+ (QuicStreamId stream_id, QuicResetStreamError error,
QuicStreamOffset bytes_written),
(override));
- MOCK_METHOD(void,
- MaybeSendStopSendingFrame,
- (QuicStreamId stream_id, QuicRstStreamErrorCode error),
- (override));
- MOCK_METHOD(void,
- SendWindowUpdate,
- (QuicStreamId id, QuicStreamOffset byte_offset),
- (override));
+ MOCK_METHOD(void, MaybeSendStopSendingFrame,
+ (QuicStreamId stream_id, QuicResetStreamError error), (override));
+ MOCK_METHOD(void, SendWindowUpdate,
+ (QuicStreamId id, QuicStreamOffset byte_offset), (override));
MOCK_METHOD(void, SendBlocked, (QuicStreamId id), (override));
- MOCK_METHOD(void,
- OnStreamHeadersPriority,
+ MOCK_METHOD(void, OnStreamHeadersPriority,
(QuicStreamId stream_id,
const spdy::SpdyStreamPrecedence& precedence),
(override));
- MOCK_METHOD(void,
- OnStreamHeaderList,
- (QuicStreamId stream_id,
- bool fin,
- size_t frame_len,
+ MOCK_METHOD(void, OnStreamHeaderList,
+ (QuicStreamId stream_id, bool fin, size_t frame_len,
const QuicHeaderList& header_list),
(override));
- MOCK_METHOD(void,
- OnPromiseHeaderList,
- (QuicStreamId stream_id,
- QuicStreamId promised_stream_id,
- size_t frame_len,
- const QuicHeaderList& header_list),
+ MOCK_METHOD(void, OnPromiseHeaderList,
+ (QuicStreamId stream_id, QuicStreamId promised_stream_id,
+ size_t frame_len, const QuicHeaderList& header_list),
(override));
- MOCK_METHOD(void,
- OnPriorityFrame,
+ MOCK_METHOD(void, OnPriorityFrame,
(QuicStreamId id, const spdy::SpdyStreamPrecedence& precedence),
(override));
MOCK_METHOD(void, OnCongestionWindowChange, (QuicTime now), (override));
// Returns a QuicConsumedData that indicates all of |write_length| (and |fin|
// if set) has been consumed.
- QuicConsumedData ConsumeData(QuicStreamId id,
- size_t write_length,
+ QuicConsumedData ConsumeData(QuicStreamId id, size_t write_length,
QuicStreamOffset offset,
- StreamSendingState state,
- TransmissionType type,
+ StreamSendingState state, TransmissionType type,
absl::optional<EncryptionLevel> level);
using QuicSession::ActivateStream;
@@ -1102,73 +943,45 @@ class MockHttp3DebugVisitor : public Http3DebugVisitor {
MOCK_METHOD(void, OnQpackEncoderStreamCreated, (QuicStreamId), (override));
MOCK_METHOD(void, OnQpackDecoderStreamCreated, (QuicStreamId), (override));
MOCK_METHOD(void, OnPeerControlStreamCreated, (QuicStreamId), (override));
- MOCK_METHOD(void,
- OnPeerQpackEncoderStreamCreated,
- (QuicStreamId),
+ MOCK_METHOD(void, OnPeerQpackEncoderStreamCreated, (QuicStreamId),
(override));
- MOCK_METHOD(void,
- OnPeerQpackDecoderStreamCreated,
- (QuicStreamId),
+ MOCK_METHOD(void, OnPeerQpackDecoderStreamCreated, (QuicStreamId),
(override));
- MOCK_METHOD(void,
- OnSettingsFrameReceivedViaAlps,
- (const SettingsFrame&),
+ MOCK_METHOD(void, OnSettingsFrameReceivedViaAlps, (const SettingsFrame&),
(override));
- MOCK_METHOD(void,
- OnAcceptChFrameReceivedViaAlps,
- (const AcceptChFrame&),
+ MOCK_METHOD(void, OnAcceptChFrameReceivedViaAlps, (const AcceptChFrame&),
(override));
- MOCK_METHOD(void,
- OnSettingsFrameReceived,
- (const SettingsFrame&),
+ MOCK_METHOD(void, OnSettingsFrameReceived, (const SettingsFrame&),
(override));
MOCK_METHOD(void, OnGoAwayFrameReceived, (const GoAwayFrame&), (override));
- MOCK_METHOD(void,
- OnMaxPushIdFrameReceived,
- (const MaxPushIdFrame&),
+ MOCK_METHOD(void, OnMaxPushIdFrameReceived, (const MaxPushIdFrame&),
(override));
- MOCK_METHOD(void,
- OnPriorityUpdateFrameReceived,
- (const PriorityUpdateFrame&),
+ MOCK_METHOD(void, OnPriorityUpdateFrameReceived, (const PriorityUpdateFrame&),
(override));
- MOCK_METHOD(void,
- OnAcceptChFrameReceived,
- (const AcceptChFrame&),
+ MOCK_METHOD(void, OnAcceptChFrameReceived, (const AcceptChFrame&),
(override));
- MOCK_METHOD(void,
- OnDataFrameReceived,
- (QuicStreamId, QuicByteCount),
- (override));
- MOCK_METHOD(void,
- OnHeadersFrameReceived,
- (QuicStreamId, QuicByteCount),
+ MOCK_METHOD(void, OnDataFrameReceived, (QuicStreamId, QuicByteCount),
(override));
- MOCK_METHOD(void,
- OnHeadersDecoded,
- (QuicStreamId, QuicHeaderList),
+ MOCK_METHOD(void, OnHeadersFrameReceived, (QuicStreamId, QuicByteCount),
(override));
- MOCK_METHOD(void,
- OnUnknownFrameReceived,
- (QuicStreamId, uint64_t, QuicByteCount),
+ MOCK_METHOD(void, OnHeadersDecoded, (QuicStreamId, QuicHeaderList),
(override));
+ MOCK_METHOD(void, OnUnknownFrameReceived,
+ (QuicStreamId, uint64_t, QuicByteCount), (override));
MOCK_METHOD(void, OnSettingsFrameSent, (const SettingsFrame&), (override));
MOCK_METHOD(void, OnGoAwayFrameSent, (QuicStreamId), (override));
MOCK_METHOD(void, OnMaxPushIdFrameSent, (const MaxPushIdFrame&), (override));
- MOCK_METHOD(void,
- OnPriorityUpdateFrameSent,
- (const PriorityUpdateFrame&),
+ MOCK_METHOD(void, OnPriorityUpdateFrameSent, (const PriorityUpdateFrame&),
(override));
MOCK_METHOD(void, OnDataFrameSent, (QuicStreamId, QuicByteCount), (override));
- MOCK_METHOD(void,
- OnHeadersFrameSent,
- (QuicStreamId, const spdy::SpdyHeaderBlock&),
- (override));
+ MOCK_METHOD(void, OnHeadersFrameSent,
+ (QuicStreamId, const spdy::SpdyHeaderBlock&), (override));
};
class TestQuicSpdyServerSession : public QuicServerSessionBase {
@@ -1184,26 +997,16 @@ class TestQuicSpdyServerSession : public QuicServerSessionBase {
delete;
~TestQuicSpdyServerSession() override;
- MOCK_METHOD(QuicSpdyStream*,
- CreateIncomingStream,
- (QuicStreamId id),
+ MOCK_METHOD(QuicSpdyStream*, CreateIncomingStream, (QuicStreamId id),
(override));
- MOCK_METHOD(QuicSpdyStream*,
- CreateIncomingStream,
- (PendingStream*),
+ MOCK_METHOD(QuicSpdyStream*, CreateIncomingStream, (PendingStream*),
(override));
- MOCK_METHOD(QuicSpdyStream*,
- CreateOutgoingBidirectionalStream,
- (),
+ MOCK_METHOD(QuicSpdyStream*, CreateOutgoingBidirectionalStream, (),
(override));
- MOCK_METHOD(QuicSpdyStream*,
- CreateOutgoingUnidirectionalStream,
- (),
+ MOCK_METHOD(QuicSpdyStream*, CreateOutgoingUnidirectionalStream, (),
(override));
- MOCK_METHOD(std::vector<absl::string_view>::const_iterator,
- SelectAlpn,
- (const std::vector<absl::string_view>&),
- (const, override));
+ MOCK_METHOD(std::vector<absl::string_view>::const_iterator, SelectAlpn,
+ (const std::vector<absl::string_view>&), (const, override));
MOCK_METHOD(void, OnAlpnSelected, (absl::string_view), (override));
std::unique_ptr<QuicCryptoServerStreamBase> CreateQuicCryptoServerStream(
const QuicCryptoServerConfig* crypto_config,
@@ -1215,14 +1018,22 @@ class TestQuicSpdyServerSession : public QuicServerSessionBase {
MockQuicCryptoServerStreamHelper* helper() { return &helper_; }
- QuicSSLConfig GetSSLConfig() const override { return ssl_config_; }
+ QuicSSLConfig GetSSLConfig() const override {
+ QuicSSLConfig ssl_config = QuicServerSessionBase::GetSSLConfig();
+ if (early_data_enabled_.has_value()) {
+ ssl_config.early_data_enabled = *early_data_enabled_;
+ }
+ return ssl_config;
+ }
- QuicSSLConfig* ssl_config() { return &ssl_config_; }
+ void set_early_data_enabled(bool enabled) { early_data_enabled_ = enabled; }
private:
MockQuicSessionVisitor visitor_;
MockQuicCryptoServerStreamHelper helper_;
- QuicSSLConfig ssl_config_;
+ // If not nullopt, override the early_data_enabled value from base class'
+ // ssl_config.
+ absl::optional<bool> early_data_enabled_;
};
// A test implementation of QuicClientPushPromiseIndex::Delegate.
@@ -1262,31 +1073,19 @@ class TestQuicSpdyClientSession : public QuicSpdyClientSessionBase {
bool IsAuthorized(const std::string& authority) override;
// QuicSpdyClientSessionBase
- MOCK_METHOD(void,
- OnProofValid,
- (const QuicCryptoClientConfig::CachedState& cached),
- (override));
- MOCK_METHOD(void,
- OnProofVerifyDetailsAvailable,
- (const ProofVerifyDetails& verify_details),
- (override));
+ MOCK_METHOD(void, OnProofValid,
+ (const QuicCryptoClientConfig::CachedState& cached), (override));
+ MOCK_METHOD(void, OnProofVerifyDetailsAvailable,
+ (const ProofVerifyDetails& verify_details), (override));
// TestQuicSpdyClientSession
- MOCK_METHOD(QuicSpdyStream*,
- CreateIncomingStream,
- (QuicStreamId id),
+ MOCK_METHOD(QuicSpdyStream*, CreateIncomingStream, (QuicStreamId id),
(override));
- MOCK_METHOD(QuicSpdyStream*,
- CreateIncomingStream,
- (PendingStream*),
+ MOCK_METHOD(QuicSpdyStream*, CreateIncomingStream, (PendingStream*),
(override));
- MOCK_METHOD(QuicSpdyStream*,
- CreateOutgoingBidirectionalStream,
- (),
+ MOCK_METHOD(QuicSpdyStream*, CreateOutgoingBidirectionalStream, (),
(override));
- MOCK_METHOD(QuicSpdyStream*,
- CreateOutgoingUnidirectionalStream,
- (),
+ MOCK_METHOD(QuicSpdyStream*, CreateOutgoingUnidirectionalStream, (),
(override));
MOCK_METHOD(bool, ShouldCreateIncomingStream, (QuicStreamId id), (override));
MOCK_METHOD(bool, ShouldCreateOutgoingBidirectionalStream, (), (override));
@@ -1326,24 +1125,17 @@ class MockPacketWriter : public QuicPacketWriter {
MockPacketWriter& operator=(const MockPacketWriter&) = delete;
~MockPacketWriter() override;
- MOCK_METHOD(WriteResult,
- WritePacket,
- (const char*,
- size_t buf_len,
- const QuicIpAddress& self_address,
- const QuicSocketAddress& peer_address,
- PerPacketOptions*),
+ MOCK_METHOD(WriteResult, WritePacket,
+ (const char*, size_t buf_len, const QuicIpAddress& self_address,
+ const QuicSocketAddress& peer_address, PerPacketOptions*),
(override));
MOCK_METHOD(bool, IsWriteBlocked, (), (const, override));
MOCK_METHOD(void, SetWritable, (), (override));
- MOCK_METHOD(QuicByteCount,
- GetMaxPacketSize,
- (const QuicSocketAddress& peer_address),
- (const, override));
+ MOCK_METHOD(QuicByteCount, GetMaxPacketSize,
+ (const QuicSocketAddress& peer_address), (const, override));
MOCK_METHOD(bool, SupportsReleaseTime, (), (const, override));
MOCK_METHOD(bool, IsBatchMode, (), (const, override));
- MOCK_METHOD(QuicPacketBuffer,
- GetNextWriteLocation,
+ MOCK_METHOD(QuicPacketBuffer, GetNextWriteLocation,
(const QuicIpAddress& self_address,
const QuicSocketAddress& peer_address),
(override));
@@ -1357,32 +1149,19 @@ class MockSendAlgorithm : public SendAlgorithmInterface {
MockSendAlgorithm& operator=(const MockSendAlgorithm&) = delete;
~MockSendAlgorithm() override;
- MOCK_METHOD(void,
- SetFromConfig,
- (const QuicConfig& config, Perspective perspective),
- (override));
- MOCK_METHOD(void,
- ApplyConnectionOptions,
- (const QuicTagVector& connection_options),
- (override));
- MOCK_METHOD(void,
- SetInitialCongestionWindowInPackets,
- (QuicPacketCount packets),
- (override));
- MOCK_METHOD(void,
- OnCongestionEvent,
- (bool rtt_updated,
- QuicByteCount bytes_in_flight,
- QuicTime event_time,
- const AckedPacketVector& acked_packets,
+ MOCK_METHOD(void, SetFromConfig,
+ (const QuicConfig& config, Perspective perspective), (override));
+ MOCK_METHOD(void, ApplyConnectionOptions,
+ (const QuicTagVector& connection_options), (override));
+ MOCK_METHOD(void, SetInitialCongestionWindowInPackets,
+ (QuicPacketCount packets), (override));
+ MOCK_METHOD(void, OnCongestionEvent,
+ (bool rtt_updated, QuicByteCount bytes_in_flight,
+ QuicTime event_time, const AckedPacketVector& acked_packets,
const LostPacketVector& lost_packets),
(override));
- MOCK_METHOD(void,
- OnPacketSent,
- (QuicTime,
- QuicByteCount,
- QuicPacketNumber,
- QuicByteCount,
+ MOCK_METHOD(void, OnPacketSent,
+ (QuicTime, QuicByteCount, QuicPacketNumber, QuicByteCount,
HasRetransmittableData),
(override));
MOCK_METHOD(void, OnPacketNeutered, (QuicPacketNumber), (override));
@@ -1397,18 +1176,12 @@ class MockSendAlgorithm : public SendAlgorithmInterface {
MOCK_METHOD(bool, InRecovery, (), (const, override));
MOCK_METHOD(bool, ShouldSendProbingPacket, (), (const, override));
MOCK_METHOD(QuicByteCount, GetSlowStartThreshold, (), (const, override));
- MOCK_METHOD(CongestionControlType,
- GetCongestionControlType,
- (),
+ MOCK_METHOD(CongestionControlType, GetCongestionControlType, (),
(const, override));
- MOCK_METHOD(void,
- AdjustNetworkParameters,
- (const NetworkParams&),
+ MOCK_METHOD(void, AdjustNetworkParameters, (const NetworkParams&),
(override));
MOCK_METHOD(void, OnApplicationLimited, (QuicByteCount), (override));
- MOCK_METHOD(void,
- PopulateConnectionStats,
- (QuicConnectionStats*),
+ MOCK_METHOD(void, PopulateConnectionStats, (QuicConnectionStats*),
(const, override));
};
@@ -1419,28 +1192,19 @@ class MockLossAlgorithm : public LossDetectionInterface {
MockLossAlgorithm& operator=(const MockLossAlgorithm&) = delete;
~MockLossAlgorithm() override;
- MOCK_METHOD(void,
- SetFromConfig,
- (const QuicConfig& config, Perspective perspective),
- (override));
+ MOCK_METHOD(void, SetFromConfig,
+ (const QuicConfig& config, Perspective perspective), (override));
- MOCK_METHOD(DetectionStats,
- DetectLosses,
- (const QuicUnackedPacketMap& unacked_packets,
- QuicTime time,
+ MOCK_METHOD(DetectionStats, DetectLosses,
+ (const QuicUnackedPacketMap& unacked_packets, QuicTime time,
const RttStats& rtt_stats,
QuicPacketNumber largest_recently_acked,
- const AckedPacketVector& packets_acked,
- LostPacketVector*),
+ const AckedPacketVector& packets_acked, LostPacketVector*),
(override));
MOCK_METHOD(QuicTime, GetLossTimeout, (), (const, override));
- MOCK_METHOD(void,
- SpuriousLossDetected,
- (const QuicUnackedPacketMap&,
- const RttStats&,
- QuicTime,
- QuicPacketNumber,
- QuicPacketNumber),
+ MOCK_METHOD(void, SpuriousLossDetected,
+ (const QuicUnackedPacketMap&, const RttStats&, QuicTime,
+ QuicPacketNumber, QuicPacketNumber),
(override));
MOCK_METHOD(void, OnConfigNegotiated, (), (override));
@@ -1456,14 +1220,10 @@ class MockAckListener : public QuicAckListenerInterface {
MockAckListener(const MockAckListener&) = delete;
MockAckListener& operator=(const MockAckListener&) = delete;
- MOCK_METHOD(void,
- OnPacketAcked,
- (int acked_bytes, QuicTime::Delta ack_delay_time),
- (override));
+ MOCK_METHOD(void, OnPacketAcked,
+ (int acked_bytes, QuicTime::Delta ack_delay_time), (override));
- MOCK_METHOD(void,
- OnPacketRetransmitted,
- (int retransmitted_bytes),
+ MOCK_METHOD(void, OnPacketRetransmitted, (int retransmitted_bytes),
(override));
protected:
@@ -1488,29 +1248,18 @@ class MockQuicConnectionDebugVisitor : public QuicConnectionDebugVisitor {
MockQuicConnectionDebugVisitor();
~MockQuicConnectionDebugVisitor() override;
- MOCK_METHOD(void,
- OnPacketSent,
- (QuicPacketNumber,
- QuicPacketLength,
- bool,
- TransmissionType,
- EncryptionLevel,
- const QuicFrames&,
- const QuicFrames&,
- QuicTime),
+ MOCK_METHOD(void, OnPacketSent,
+ (QuicPacketNumber, QuicPacketLength, bool, TransmissionType,
+ EncryptionLevel, const QuicFrames&, const QuicFrames&, QuicTime),
(override));
- MOCK_METHOD(void,
- OnCoalescedPacketSent,
- (const QuicCoalescedPacket&, size_t),
+ MOCK_METHOD(void, OnCoalescedPacketSent, (const QuicCoalescedPacket&, size_t),
(override));
MOCK_METHOD(void, OnPingSent, (), (override));
- MOCK_METHOD(void,
- OnPacketReceived,
- (const QuicSocketAddress&,
- const QuicSocketAddress&,
+ MOCK_METHOD(void, OnPacketReceived,
+ (const QuicSocketAddress&, const QuicSocketAddress&,
const QuicEncryptedPacket&),
(override));
@@ -1518,83 +1267,57 @@ class MockQuicConnectionDebugVisitor : public QuicConnectionDebugVisitor {
MOCK_METHOD(void, OnProtocolVersionMismatch, (ParsedQuicVersion), (override));
- MOCK_METHOD(void,
- OnPacketHeader,
- (const QuicPacketHeader& header,
- QuicTime receive_time,
+ MOCK_METHOD(void, OnPacketHeader,
+ (const QuicPacketHeader& header, QuicTime receive_time,
EncryptionLevel level),
(override));
- MOCK_METHOD(void,
- OnSuccessfulVersionNegotiation,
- (const ParsedQuicVersion&),
+ MOCK_METHOD(void, OnSuccessfulVersionNegotiation, (const ParsedQuicVersion&),
(override));
MOCK_METHOD(void, OnStreamFrame, (const QuicStreamFrame&), (override));
MOCK_METHOD(void, OnCryptoFrame, (const QuicCryptoFrame&), (override));
- MOCK_METHOD(void,
- OnStopWaitingFrame,
- (const QuicStopWaitingFrame&),
+ MOCK_METHOD(void, OnStopWaitingFrame, (const QuicStopWaitingFrame&),
(override));
MOCK_METHOD(void, OnRstStreamFrame, (const QuicRstStreamFrame&), (override));
- MOCK_METHOD(void,
- OnConnectionCloseFrame,
- (const QuicConnectionCloseFrame&),
+ MOCK_METHOD(void, OnConnectionCloseFrame, (const QuicConnectionCloseFrame&),
(override));
MOCK_METHOD(void, OnBlockedFrame, (const QuicBlockedFrame&), (override));
- MOCK_METHOD(void,
- OnNewConnectionIdFrame,
- (const QuicNewConnectionIdFrame&),
+ MOCK_METHOD(void, OnNewConnectionIdFrame, (const QuicNewConnectionIdFrame&),
(override));
- MOCK_METHOD(void,
- OnRetireConnectionIdFrame,
- (const QuicRetireConnectionIdFrame&),
- (override));
+ MOCK_METHOD(void, OnRetireConnectionIdFrame,
+ (const QuicRetireConnectionIdFrame&), (override));
MOCK_METHOD(void, OnNewTokenFrame, (const QuicNewTokenFrame&), (override));
MOCK_METHOD(void, OnMessageFrame, (const QuicMessageFrame&), (override));
- MOCK_METHOD(void,
- OnStopSendingFrame,
- (const QuicStopSendingFrame&),
+ MOCK_METHOD(void, OnStopSendingFrame, (const QuicStopSendingFrame&),
(override));
- MOCK_METHOD(void,
- OnPathChallengeFrame,
- (const QuicPathChallengeFrame&),
+ MOCK_METHOD(void, OnPathChallengeFrame, (const QuicPathChallengeFrame&),
(override));
- MOCK_METHOD(void,
- OnPathResponseFrame,
- (const QuicPathResponseFrame&),
+ MOCK_METHOD(void, OnPathResponseFrame, (const QuicPathResponseFrame&),
(override));
- MOCK_METHOD(void,
- OnPublicResetPacket,
- (const QuicPublicResetPacket&),
+ MOCK_METHOD(void, OnPublicResetPacket, (const QuicPublicResetPacket&),
(override));
- MOCK_METHOD(void,
- OnVersionNegotiationPacket,
- (const QuicVersionNegotiationPacket&),
- (override));
+ MOCK_METHOD(void, OnVersionNegotiationPacket,
+ (const QuicVersionNegotiationPacket&), (override));
- MOCK_METHOD(void,
- OnTransportParametersSent,
- (const TransportParameters&),
+ MOCK_METHOD(void, OnTransportParametersSent, (const TransportParameters&),
(override));
- MOCK_METHOD(void,
- OnTransportParametersReceived,
- (const TransportParameters&),
+ MOCK_METHOD(void, OnTransportParametersReceived, (const TransportParameters&),
(override));
MOCK_METHOD(void, OnZeroRttRejected, (int), (override));
@@ -1606,14 +1329,11 @@ class MockReceivedPacketManager : public QuicReceivedPacketManager {
explicit MockReceivedPacketManager(QuicConnectionStats* stats);
~MockReceivedPacketManager() override;
- MOCK_METHOD(void,
- RecordPacketReceived,
+ MOCK_METHOD(void, RecordPacketReceived,
(const QuicPacketHeader& header, QuicTime receipt_time),
(override));
MOCK_METHOD(bool, IsMissing, (QuicPacketNumber packet_number), (override));
- MOCK_METHOD(bool,
- IsAwaitingPacket,
- (QuicPacketNumber packet_number),
+ MOCK_METHOD(bool, IsAwaitingPacket, (QuicPacketNumber packet_number),
(const, override));
MOCK_METHOD(bool, HasNewMissingPackets, (), (const, override));
MOCK_METHOD(bool, ack_frame_updated, (), (const, override));
@@ -1629,22 +1349,15 @@ class MockPacketCreatorDelegate : public QuicPacketCreator::DelegateInterface {
MOCK_METHOD(QuicPacketBuffer, GetPacketBuffer, (), (override));
MOCK_METHOD(void, OnSerializedPacket, (SerializedPacket), (override));
- MOCK_METHOD(void,
- OnUnrecoverableError,
- (QuicErrorCode, const std::string&),
+ MOCK_METHOD(void, OnUnrecoverableError, (QuicErrorCode, const std::string&),
(override));
- MOCK_METHOD(bool,
- ShouldGeneratePacket,
+ MOCK_METHOD(bool, ShouldGeneratePacket,
(HasRetransmittableData retransmittable, IsHandshake handshake),
(override));
- MOCK_METHOD(const QuicFrames,
- MaybeBundleAckOpportunistically,
- (),
- (override));
- MOCK_METHOD(SerializedPacketFate,
- GetSerializedPacketFate,
- (bool, EncryptionLevel),
+ MOCK_METHOD(const QuicFrames, MaybeBundleAckOpportunistically, (),
(override));
+ MOCK_METHOD(SerializedPacketFate, GetSerializedPacketFate,
+ (bool, EncryptionLevel), (override));
};
class MockSessionNotifier : public SessionNotifierInterface {
@@ -1652,19 +1365,13 @@ class MockSessionNotifier : public SessionNotifierInterface {
MockSessionNotifier();
~MockSessionNotifier() override;
- MOCK_METHOD(bool,
- OnFrameAcked,
- (const QuicFrame&, QuicTime::Delta, QuicTime),
+ MOCK_METHOD(bool, OnFrameAcked, (const QuicFrame&, QuicTime::Delta, QuicTime),
(override));
- MOCK_METHOD(void,
- OnStreamFrameRetransmitted,
- (const QuicStreamFrame&),
+ MOCK_METHOD(void, OnStreamFrameRetransmitted, (const QuicStreamFrame&),
(override));
MOCK_METHOD(void, OnFrameLost, (const QuicFrame&), (override));
- MOCK_METHOD(void,
- RetransmitFrames,
- (const QuicFrames&, TransmissionType type),
- (override));
+ MOCK_METHOD(void, RetransmitFrames,
+ (const QuicFrames&, TransmissionType type), (override));
MOCK_METHOD(bool, IsFrameOutstanding, (const QuicFrame&), (const, override));
MOCK_METHOD(bool, HasUnackedCryptoData, (), (const, override));
MOCK_METHOD(bool, HasUnackedStreamData, (), (const, override));
@@ -1676,8 +1383,7 @@ class MockQuicPathValidationContext : public QuicPathValidationContext {
const QuicSocketAddress& peer_address,
const QuicSocketAddress& effective_peer_address,
QuicPacketWriter* writer)
- : QuicPathValidationContext(self_address,
- peer_address,
+ : QuicPathValidationContext(self_address, peer_address,
effective_peer_address),
writer_(writer) {}
QuicPacketWriter* WriterToUse() override { return writer_; }
@@ -1689,15 +1395,11 @@ class MockQuicPathValidationContext : public QuicPathValidationContext {
class MockQuicPathValidationResultDelegate
: public QuicPathValidator::ResultDelegate {
public:
- MOCK_METHOD(void,
- OnPathValidationSuccess,
- (std::unique_ptr<QuicPathValidationContext>),
- (override));
+ MOCK_METHOD(void, OnPathValidationSuccess,
+ (std::unique_ptr<QuicPathValidationContext>), (override));
- MOCK_METHOD(void,
- OnPathValidationFailure,
- (std::unique_ptr<QuicPathValidationContext>),
- (override));
+ MOCK_METHOD(void, OnPathValidationFailure,
+ (std::unique_ptr<QuicPathValidationContext>), (override));
};
class QuicCryptoClientStreamPeer {
@@ -1724,11 +1426,9 @@ class QuicCryptoClientStreamPeer {
// client_session: Pointer reference for the newly created client
// session. The new object will be owned by the caller.
void CreateClientSessionForTest(
- QuicServerId server_id,
- QuicTime::Delta connection_start_time,
+ QuicServerId server_id, QuicTime::Delta connection_start_time,
const ParsedQuicVersionVector& supported_versions,
- MockQuicConnectionHelper* helper,
- MockAlarmFactory* alarm_factory,
+ MockQuicConnectionHelper* helper, MockAlarmFactory* alarm_factory,
QuicCryptoClientConfig* crypto_client_config,
PacketSavingConnection** client_connection,
TestQuicSpdyClientSession** client_session);
@@ -1749,11 +1449,9 @@ void CreateClientSessionForTest(
// server_session: Pointer reference for the newly created server
// session. The new object will be owned by the caller.
void CreateServerSessionForTest(
- QuicServerId server_id,
- QuicTime::Delta connection_start_time,
+ QuicServerId server_id, QuicTime::Delta connection_start_time,
ParsedQuicVersionVector supported_versions,
- MockQuicConnectionHelper* helper,
- MockAlarmFactory* alarm_factory,
+ MockQuicConnectionHelper* helper, MockAlarmFactory* alarm_factory,
QuicCryptoServerConfig* crypto_server_config,
QuicCompressedCertsCache* compressed_certs_cache,
PacketSavingConnection** server_connection,
@@ -1805,30 +1503,18 @@ inline void MakeIOVector(absl::string_view str, struct iovec* iov) {
// HTTP stream numbering scheme (i.e. whether one or two QUIC streams are used
// per HTTP transaction).
QuicStreamId GetNthClientInitiatedBidirectionalStreamId(
- QuicTransportVersion version,
- int n);
+ QuicTransportVersion version, int n);
QuicStreamId GetNthServerInitiatedBidirectionalStreamId(
- QuicTransportVersion version,
- int n);
+ QuicTransportVersion version, int n);
QuicStreamId GetNthServerInitiatedUnidirectionalStreamId(
- QuicTransportVersion version,
- int n);
+ QuicTransportVersion version, int n);
QuicStreamId GetNthClientInitiatedUnidirectionalStreamId(
- QuicTransportVersion version,
- int n);
+ QuicTransportVersion version, int n);
-StreamType DetermineStreamType(QuicStreamId id,
- ParsedQuicVersion version,
- Perspective perspective,
- bool is_incoming,
+StreamType DetermineStreamType(QuicStreamId id, ParsedQuicVersion version,
+ Perspective perspective, bool is_incoming,
StreamType default_type);
-// Utility function that stores message_data in |storage| and returns a
-// QuicMemSliceSpan.
-QuicMemSliceSpan MakeSpan(QuicBufferAllocator* allocator,
- absl::string_view message_data,
- QuicMemSliceStorage* storage);
-
// Creates a MemSlice using a singleton trivial buffer allocator. Performs a
// copy.
QuicMemSlice MemSliceFromString(absl::string_view data);
@@ -1842,15 +1528,12 @@ MATCHER_P(ReceivedPacketInfoConnectionIdEquals, destination_connection_id, "") {
return arg.destination_connection_id == destination_connection_id;
}
-MATCHER_P2(InRange, min, max, "") {
- return arg >= min && arg <= max;
-}
+MATCHER_P2(InRange, min, max, "") { return arg >= min && arg <= max; }
// A GMock matcher that prints expected and actual QuicErrorCode strings
// upon failure. Example usage:
// EXPECT_THAT(stream_->connection_error(), IsError(QUIC_INTERNAL_ERROR));
-MATCHER_P(IsError,
- expected,
+MATCHER_P(IsError, expected,
absl::StrCat(negation ? "isn't equal to " : "is equal to ",
QuicErrorCodeToString(expected))) {
*result_listener << QuicErrorCodeToString(static_cast<QuicErrorCode>(arg));
@@ -1869,8 +1552,7 @@ MATCHER(IsQuicNoError,
// A GMock matcher that prints expected and actual QuicRstStreamErrorCode
// strings upon failure. Example usage:
// EXPECT_THAT(stream_->stream_error(), IsStreamError(QUIC_INTERNAL_ERROR));
-MATCHER_P(IsStreamError,
- expected,
+MATCHER_P(IsStreamError, expected,
absl::StrCat(negation ? "isn't equal to " : "is equal to ",
QuicRstStreamErrorCodeToString(expected))) {
*result_listener << QuicRstStreamErrorCodeToString(arg);
@@ -1908,12 +1590,9 @@ class TaggingEncrypter : public QuicEncrypter {
return true;
}
- bool EncryptPacket(uint64_t packet_number,
- absl::string_view associated_data,
- absl::string_view plaintext,
- char* output,
- size_t* output_length,
- size_t max_output_length) override;
+ bool EncryptPacket(uint64_t packet_number, absl::string_view associated_data,
+ absl::string_view plaintext, char* output,
+ size_t* output_length, size_t max_output_length) override;
std::string GenerateHeaderProtectionMask(
absl::string_view /*sample*/) override {
@@ -1978,12 +1657,9 @@ class TaggingDecrypter : public QuicDecrypter {
return true;
}
- bool DecryptPacket(uint64_t packet_number,
- absl::string_view associated_data,
- absl::string_view ciphertext,
- char* output,
- size_t* output_length,
- size_t max_output_length) override;
+ bool DecryptPacket(uint64_t packet_number, absl::string_view associated_data,
+ absl::string_view ciphertext, char* output,
+ size_t* output_length, size_t max_output_length) override;
std::string GenerateHeaderProtectionMask(
QuicDataReader* /*sample_reader*/) override {
@@ -2040,8 +1716,7 @@ class TestPacketWriter : public QuicPacketWriter {
};
public:
- TestPacketWriter(ParsedQuicVersion version,
- MockClock* clock,
+ TestPacketWriter(ParsedQuicVersion version, MockClock* clock,
Perspective perspective);
TestPacketWriter(const TestPacketWriter&) = delete;
@@ -2050,8 +1725,7 @@ class TestPacketWriter : public QuicPacketWriter {
~TestPacketWriter() override;
// QuicPacketWriter interface
- WriteResult WritePacket(const char* buffer,
- size_t buf_len,
+ WriteResult WritePacket(const char* buffer, size_t buf_len,
const QuicIpAddress& self_address,
const QuicSocketAddress& peer_address,
PerPacketOptions* options) override;
@@ -2277,8 +1951,7 @@ class TestPacketWriter : public QuicPacketWriter {
// contents of the destination connection ID passed in to
// WriteClientVersionNegotiationProbePacket.
bool ParseClientVersionNegotiationProbePacket(
- const char* packet_bytes,
- size_t packet_length,
+ const char* packet_bytes, size_t packet_length,
char* destination_connection_id_bytes,
uint8_t* destination_connection_id_length_out);
@@ -2291,8 +1964,7 @@ bool ParseClientVersionNegotiationProbePacket(
// the source connection ID, and must point to |source_connection_id_length|
// bytes of memory.
bool WriteServerVersionNegotiationProbeResponse(
- char* packet_bytes,
- size_t* packet_length_out,
+ char* packet_bytes, size_t* packet_length_out,
const char* source_connection_id_bytes,
uint8_t source_connection_id_length);
@@ -2330,13 +2002,14 @@ class MockHttp3DatagramRegistrationVisitor
MOCK_METHOD(void, OnContextReceived,
(QuicStreamId stream_id,
absl::optional<QuicDatagramContextId> context_id,
- const Http3DatagramContextExtensions& extensions),
+ DatagramFormatType format_type,
+ absl::string_view format_additional_data),
(override));
MOCK_METHOD(void, OnContextClosed,
(QuicStreamId stream_id,
absl::optional<QuicDatagramContextId> context_id,
- const Http3DatagramContextExtensions& extensions),
+ ContextCloseCode close_code, absl::string_view close_details),
(override));
};
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_time_wait_list_manager_peer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_time_wait_list_manager_peer.cc
index 8f614e8d89d..cbcd36e1550 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_time_wait_list_manager_peer.cc
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_time_wait_list_manager_peer.cc
@@ -36,5 +36,11 @@ bool QuicTimeWaitListManagerPeer::SendOrQueuePacket(
return manager->SendOrQueuePacket(std::move(packet), packet_context);
}
+// static
+size_t QuicTimeWaitListManagerPeer::PendingPacketsQueueSize(
+ QuicTimeWaitListManager* manager) {
+ return manager->pending_packets_queue_.size();
+}
+
} // namespace test
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_time_wait_list_manager_peer.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_time_wait_list_manager_peer.h
index 4e0a4a707ad..a314e039591 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_time_wait_list_manager_peer.h
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_time_wait_list_manager_peer.h
@@ -26,6 +26,8 @@ class QuicTimeWaitListManagerPeer {
QuicTimeWaitListManager* manager,
std::unique_ptr<QuicTimeWaitListManager::QueuedPacket> packet,
const QuicPerPacketContext* packet_context);
+
+ static size_t PendingPacketsQueueSize(QuicTimeWaitListManager* manager);
};
} // namespace test
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_transport_test_tools.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_transport_test_tools.h
index df52093e05a..5babfd280cb 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_transport_test_tools.h
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_transport_test_tools.h
@@ -14,7 +14,9 @@ namespace test {
class MockClientVisitor : public WebTransportVisitor {
public:
- MOCK_METHOD(void, OnSessionReady, (), (override));
+ MOCK_METHOD(void, OnSessionReady, (const spdy::SpdyHeaderBlock&), (override));
+ MOCK_METHOD(void, OnSessionClosed,
+ (WebTransportSessionError, const std::string&), (override));
MOCK_METHOD(void, OnIncomingBidirectionalStreamAvailable, (), (override));
MOCK_METHOD(void, OnIncomingUnidirectionalStreamAvailable, (), (override));
MOCK_METHOD(void, OnDatagramReceived, (absl::string_view), (override));
@@ -32,6 +34,12 @@ class MockStreamVisitor : public WebTransportStreamVisitor {
public:
MOCK_METHOD(void, OnCanRead, (), (override));
MOCK_METHOD(void, OnCanWrite, (), (override));
+
+ MOCK_METHOD(void, OnResetStreamReceived, (WebTransportStreamError error),
+ (override));
+ MOCK_METHOD(void, OnStopSendingReceived, (WebTransportStreamError error),
+ (override));
+ MOCK_METHOD(void, OnWriteSideInDataRecvdState, (), (override));
};
} // namespace test
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier.cc b/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier.cc
index a1383b0e41d..ce498ca2d95 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier.cc
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier.cc
@@ -111,6 +111,21 @@ void SimpleSessionNotifier::WriteOrBufferRstStream(
WriteBufferedControlFrames();
}
+void SimpleSessionNotifier::WriteOrBufferWindowUpate(
+ QuicStreamId id, QuicStreamOffset byte_offset) {
+ QUIC_DVLOG(1) << "Writing WINDOW_UPDATE";
+ const bool had_buffered_data =
+ HasBufferedStreamData() || HasBufferedControlFrames();
+ QuicControlFrameId control_frame_id = ++last_control_frame_id_;
+ control_frames_.emplace_back((
+ QuicFrame(new QuicWindowUpdateFrame(control_frame_id, id, byte_offset))));
+ if (had_buffered_data) {
+ QUIC_DLOG(WARNING) << "Connection is write blocked";
+ return;
+ }
+ WriteBufferedControlFrames();
+}
+
void SimpleSessionNotifier::WriteOrBufferPing() {
QUIC_DVLOG(1) << "Writing PING_FRAME";
const bool had_buffered_data =
@@ -175,8 +190,7 @@ void SimpleSessionNotifier::OnCanWrite() {
!RetransmitLostStreamData()) {
return;
}
- // Write buffered control frames.
- if (!WriteBufferedControlFrames()) {
+ if (!WriteBufferedCryptoData() || !WriteBufferedControlFrames()) {
return;
}
// Write new data.
@@ -666,6 +680,26 @@ bool SimpleSessionNotifier::RetransmitLostStreamData() {
return !HasLostStreamData();
}
+bool SimpleSessionNotifier::WriteBufferedCryptoData() {
+ for (size_t i = 0; i < NUM_ENCRYPTION_LEVELS; ++i) {
+ const StreamState& state = crypto_state_[i];
+ QuicIntervalSet<QuicStreamOffset> buffered_crypto_data(0,
+ state.bytes_total);
+ buffered_crypto_data.Difference(crypto_bytes_transferred_[i]);
+ for (const auto& interval : buffered_crypto_data) {
+ size_t bytes_written = connection_->SendCryptoData(
+ static_cast<EncryptionLevel>(i), interval.Length(), interval.min());
+ crypto_state_[i].bytes_sent += bytes_written;
+ crypto_bytes_transferred_[i].Add(interval.min(),
+ interval.min() + bytes_written);
+ if (bytes_written < interval.Length()) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
bool SimpleSessionNotifier::WriteBufferedControlFrames() {
while (HasBufferedControlFrames()) {
QuicFrame frame_to_send =
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier.h b/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier.h
index 8bdadb2f45d..5712884fcd2 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier.h
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier.h
@@ -34,6 +34,10 @@ class SimpleSessionNotifier : public SessionNotifierInterface {
void WriteOrBufferRstStream(QuicStreamId id,
QuicRstStreamErrorCode error,
QuicStreamOffset bytes_written);
+
+ // Tries to write WINDOW_UPDATE.
+ void WriteOrBufferWindowUpate(QuicStreamId id, QuicStreamOffset byte_offset);
+
// Tries to write PING.
void WriteOrBufferPing();
@@ -127,6 +131,8 @@ class SimpleSessionNotifier : public SessionNotifierInterface {
bool WriteBufferedControlFrames();
+ bool WriteBufferedCryptoData();
+
bool IsControlFrameOutstanding(const QuicFrame& frame) const;
bool HasBufferedControlFrames() const;
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/queue.h b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/queue.h
index 7e4be833690..dd810e7e2f5 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/queue.h
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/queue.h
@@ -73,7 +73,7 @@ class Queue : public Actor, public UnconstrainedPortInterface {
};
// Alarm handler for aggregation timeout.
- class AggregationAlarmDelegate : public QuicAlarm::Delegate {
+ class AggregationAlarmDelegate : public QuicAlarm::DelegateWithoutContext {
public:
explicit AggregationAlarmDelegate(Queue* queue);
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/simulator.h b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/simulator.h
index 8f31717e712..b4298f53e50 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/simulator.h
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/simulator.h
@@ -88,7 +88,7 @@ class Simulator : public QuicConnectionHelperInterface {
};
// The delegate used for RunFor().
- class RunForDelegate : public QuicAlarm::Delegate {
+ class RunForDelegate : public QuicAlarm::DelegateWithoutContext {
public:
explicit RunForDelegate(bool* run_for_should_stop);
void OnAlarm() override;
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/simulator_test.cc b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/simulator_test.cc
index a71649eb4b5..fe841703cf4 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/simulator_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/simulator_test.cc
@@ -475,7 +475,7 @@ class AlarmToggler : public Actor {
};
// Counts the number of times an alarm has fired.
-class CounterDelegate : public QuicAlarm::Delegate {
+class CounterDelegate : public QuicAlarm::DelegateWithoutContext {
public:
explicit CounterDelegate(size_t* counter) : counter_(counter) {}
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/web_transport_resets_backend.cc b/chromium/net/third_party/quiche/src/quic/test_tools/web_transport_resets_backend.cc
new file mode 100644
index 00000000000..512619fee0a
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/web_transport_resets_backend.cc
@@ -0,0 +1,113 @@
+// Copyright (c) 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "quic/test_tools/web_transport_resets_backend.h"
+
+#include <memory>
+
+#include "quic/core/web_transport_interface.h"
+#include "quic/tools/web_transport_test_visitors.h"
+#include "common/quiche_circular_deque.h"
+
+namespace quic {
+namespace test {
+
+namespace {
+
+class ResetsVisitor;
+
+class BidirectionalEchoVisitorWithLogging
+ : public WebTransportBidirectionalEchoVisitor {
+ public:
+ BidirectionalEchoVisitorWithLogging(WebTransportStream* stream,
+ ResetsVisitor* session_visitor)
+ : WebTransportBidirectionalEchoVisitor(stream),
+ session_visitor_(session_visitor) {}
+
+ void OnResetStreamReceived(WebTransportStreamError error) override;
+ void OnStopSendingReceived(WebTransportStreamError error) override;
+
+ private:
+ ResetsVisitor* session_visitor_; // Not owned.
+};
+
+class ResetsVisitor : public WebTransportVisitor {
+ public:
+ ResetsVisitor(WebTransportSession* session) : session_(session) {}
+
+ void OnSessionReady(const spdy::SpdyHeaderBlock& /*headers*/) override {}
+ void OnSessionClosed(WebTransportSessionError /*error_code*/,
+ const std::string& /*error_message*/) override {}
+
+ void OnIncomingBidirectionalStreamAvailable() override {
+ while (true) {
+ WebTransportStream* stream =
+ session_->AcceptIncomingBidirectionalStream();
+ if (stream == nullptr) {
+ return;
+ }
+ stream->SetVisitor(
+ std::make_unique<BidirectionalEchoVisitorWithLogging>(stream, this));
+ stream->visitor()->OnCanRead();
+ }
+ }
+ void OnIncomingUnidirectionalStreamAvailable() override {}
+
+ void OnDatagramReceived(absl::string_view /*datagram*/) override {}
+
+ void OnCanCreateNewOutgoingBidirectionalStream() override {}
+ void OnCanCreateNewOutgoingUnidirectionalStream() override {
+ MaybeSendLogsBack();
+ }
+
+ void Log(std::string line) {
+ log_.push_back(std::move(line));
+ MaybeSendLogsBack();
+ }
+
+ private:
+ void MaybeSendLogsBack() {
+ while (!log_.empty() &&
+ session_->CanOpenNextOutgoingUnidirectionalStream()) {
+ WebTransportStream* stream = session_->OpenOutgoingUnidirectionalStream();
+ stream->SetVisitor(
+ std::make_unique<WebTransportUnidirectionalEchoWriteVisitor>(
+ stream, log_.front()));
+ log_.pop_front();
+ stream->visitor()->OnCanWrite();
+ }
+ }
+
+ WebTransportSession* session_; // Not owned.
+ quiche::QuicheCircularDeque<std::string> log_;
+};
+
+void BidirectionalEchoVisitorWithLogging::OnResetStreamReceived(
+ WebTransportStreamError error) {
+ session_visitor_->Log(absl::StrCat("Received reset for stream ",
+ stream()->GetStreamId(),
+ " with error code ", error));
+ WebTransportBidirectionalEchoVisitor::OnResetStreamReceived(error);
+}
+void BidirectionalEchoVisitorWithLogging::OnStopSendingReceived(
+ WebTransportStreamError error) {
+ session_visitor_->Log(absl::StrCat("Received stop sending for stream ",
+ stream()->GetStreamId(),
+ " with error code ", error));
+ WebTransportBidirectionalEchoVisitor::OnStopSendingReceived(error);
+}
+
+} // namespace
+
+QuicSimpleServerBackend::WebTransportResponse WebTransportResetsBackend(
+ const spdy::Http2HeaderBlock& /*request_headers*/,
+ WebTransportSession* session) {
+ QuicSimpleServerBackend::WebTransportResponse response;
+ response.response_headers[":status"] = "200";
+ response.visitor = std::make_unique<ResetsVisitor>(session);
+ return response;
+}
+
+} // namespace test
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/web_transport_resets_backend.h b/chromium/net/third_party/quiche/src/quic/test_tools/web_transport_resets_backend.h
new file mode 100644
index 00000000000..dda06be521f
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/web_transport_resets_backend.h
@@ -0,0 +1,23 @@
+// Copyright (c) 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_WEB_TRANSPORT_RESETS_BACKEND_H_
+#define QUICHE_QUIC_TEST_TOOLS_WEB_TRANSPORT_RESETS_BACKEND_H_
+
+#include "quic/test_tools/quic_test_backend.h"
+
+namespace quic {
+namespace test {
+
+// A backend for testing RESET_STREAM/STOP_SENDING behavior. Provides
+// bidirectional echo streams; whenever one of those receives RESET_STREAM or
+// STOP_SENDING, a log message is sent as a unidirectional stream.
+QuicSimpleServerBackend::WebTransportResponse WebTransportResetsBackend(
+ const spdy::Http2HeaderBlock& request_headers,
+ WebTransportSession* session);
+
+} // namespace test
+} // namespace quic
+
+#endif // QUICHE_QUIC_TEST_TOOLS_WEB_TRANSPORT_RESETS_BACKEND_H_
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend_test.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend_test.cc
index 71f5dc5bbb4..79dac6bf539 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend_test.cc
@@ -77,7 +77,13 @@ TEST_F(QuicMemoryCacheBackendTest, AddResponse) {
EXPECT_EQ(response->trailers(), response_trailers);
}
-TEST_F(QuicMemoryCacheBackendTest, ReadsCacheDir) {
+// TODO(crbug.com/1249712) This test is failing on iOS.
+#if defined(OS_IOS)
+#define MAYBE_ReadsCacheDir DISABLED_ReadsCacheDir
+#else
+#define MAYBE_ReadsCacheDir ReadsCacheDir
+#endif
+TEST_F(QuicMemoryCacheBackendTest, MAYBE_ReadsCacheDir) {
cache_.InitializeBackend(CacheDirectory());
const Response* response =
cache_.GetResponse("test.example.com", "/index.html");
@@ -89,21 +95,43 @@ TEST_F(QuicMemoryCacheBackendTest, ReadsCacheDir) {
EXPECT_LT(0U, response->body().length());
}
-TEST_F(QuicMemoryCacheBackendTest, ReadsCacheDirWithServerPushResource) {
+// TODO(crbug.com/1249712) This test is failing on iOS.
+#if defined(OS_IOS)
+#define MAYBE_ReadsCacheDirWithServerPushResource \
+ DISABLED_ReadsCacheDirWithServerPushResource
+#else
+#define MAYBE_ReadsCacheDirWithServerPushResource \
+ ReadsCacheDirWithServerPushResource
+#endif
+TEST_F(QuicMemoryCacheBackendTest, MAYBE_ReadsCacheDirWithServerPushResource) {
cache_.InitializeBackend(CacheDirectory() + "_with_push");
std::list<ServerPushInfo> resources =
cache_.GetServerPushResources("test.example.com/");
ASSERT_EQ(1UL, resources.size());
}
-TEST_F(QuicMemoryCacheBackendTest, ReadsCacheDirWithServerPushResources) {
+// TODO(crbug.com/1249712) This test is failing on iOS.
+#if defined(OS_IOS)
+#define MAYBE_ReadsCacheDirWithServerPushResources \
+ DISABLED_ReadsCacheDirWithServerPushResources
+#else
+#define MAYBE_ReadsCacheDirWithServerPushResources \
+ ReadsCacheDirWithServerPushResources
+#endif
+TEST_F(QuicMemoryCacheBackendTest, MAYBE_ReadsCacheDirWithServerPushResources) {
cache_.InitializeBackend(CacheDirectory() + "_with_push");
std::list<ServerPushInfo> resources =
cache_.GetServerPushResources("test.example.com/index2.html");
ASSERT_EQ(2UL, resources.size());
}
-TEST_F(QuicMemoryCacheBackendTest, UsesOriginalUrl) {
+// TODO(crbug.com/1249712) This test is failing on iOS.
+#if defined(OS_IOS)
+#define MAYBE_UsesOriginalUrl DISABLED_UsesOriginalUrl
+#else
+#define MAYBE_UsesOriginalUrl UsesOriginalUrl
+#endif
+TEST_F(QuicMemoryCacheBackendTest, MAYBE_UsesOriginalUrl) {
cache_.InitializeBackend(CacheDirectory());
const Response* response =
cache_.GetResponse("test.example.com", "/site_map.html");
@@ -115,7 +143,13 @@ TEST_F(QuicMemoryCacheBackendTest, UsesOriginalUrl) {
EXPECT_LT(0U, response->body().length());
}
-TEST_F(QuicMemoryCacheBackendTest, UsesOriginalUrlOnly) {
+// TODO(crbug.com/1249712) This test is failing on iOS.
+#if defined(OS_IOS)
+#define MAYBE_UsesOriginalUrlOnly DISABLED_UsesOriginalUrlOnly
+#else
+#define MAYBE_UsesOriginalUrlOnly UsesOriginalUrlOnly
+#endif
+TEST_F(QuicMemoryCacheBackendTest, MAYBE_UsesOriginalUrlOnly) {
// Tests that if the URL cannot be inferred correctly from the path
// because the directory does not include the hostname, that the
// X-Original-Url header's value will be used.
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_client_session.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_client_session.cc
index 07c46289da8..47c521bf5b5 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_client_session.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_client_session.cc
@@ -54,8 +54,9 @@ bool QuicSimpleClientSession::ShouldNegotiateWebTransport() {
return enable_web_transport_;
}
-bool QuicSimpleClientSession::ShouldNegotiateHttp3Datagram() {
- return enable_web_transport_;
+HttpDatagramSupport QuicSimpleClientSession::LocalHttpDatagramSupport() {
+ return enable_web_transport_ ? HttpDatagramSupport::kDraft04
+ : HttpDatagramSupport::kNone;
}
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_client_session.h b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_client_session.h
index 124e56f8bf1..1a6e694287a 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_client_session.h
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_client_session.h
@@ -30,7 +30,7 @@ class QuicSimpleClientSession : public QuicSpdyClientSession {
std::unique_ptr<QuicSpdyClientStream> CreateClientStream() override;
bool ShouldNegotiateWebTransport() override;
- bool ShouldNegotiateHttp3Datagram() override;
+ HttpDatagramSupport LocalHttpDatagramSupport() override;
private:
const bool drop_response_body_;
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session.cc
index 688ca9ff24b..d1e9a73e635 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session.cc
@@ -10,6 +10,7 @@
#include "quic/core/http/quic_server_initiated_spdy_stream.h"
#include "quic/core/http/quic_spdy_session.h"
#include "quic/core/quic_connection.h"
+#include "quic/core/quic_types.h"
#include "quic/core/quic_utils.h"
#include "quic/platform/api/quic_flags.h"
#include "quic/platform/api/quic_logging.h"
@@ -18,30 +19,21 @@
namespace quic {
QuicSimpleServerSession::QuicSimpleServerSession(
- const QuicConfig& config,
- const ParsedQuicVersionVector& supported_versions,
- QuicConnection* connection,
- QuicSession::Visitor* visitor,
+ const QuicConfig& config, const ParsedQuicVersionVector& supported_versions,
+ QuicConnection* connection, QuicSession::Visitor* visitor,
QuicCryptoServerStreamBase::Helper* helper,
const QuicCryptoServerConfig* crypto_config,
QuicCompressedCertsCache* compressed_certs_cache,
QuicSimpleServerBackend* quic_simple_server_backend)
- : QuicServerSessionBase(config,
- supported_versions,
- connection,
- visitor,
- helper,
- crypto_config,
- compressed_certs_cache),
+ : QuicServerSessionBase(config, supported_versions, connection, visitor,
+ helper, crypto_config, compressed_certs_cache),
highest_promised_stream_id_(
QuicUtils::GetInvalidStreamId(connection->transport_version())),
quic_simple_server_backend_(quic_simple_server_backend) {
QUICHE_DCHECK(quic_simple_server_backend_);
}
-QuicSimpleServerSession::~QuicSimpleServerSession() {
- DeleteConnection();
-}
+QuicSimpleServerSession::~QuicSimpleServerSession() { DeleteConnection(); }
std::unique_ptr<QuicCryptoServerStreamBase>
QuicSimpleServerSession::CreateQuicCryptoServerStream(
@@ -75,8 +67,8 @@ QuicSpdyStream* QuicSimpleServerSession::CreateIncomingStream(QuicStreamId id) {
QuicSpdyStream* QuicSimpleServerSession::CreateIncomingStream(
PendingStream* pending) {
- QuicSpdyStream* stream = new QuicSimpleServerStream(
- pending, this, BIDIRECTIONAL, quic_simple_server_backend_);
+ QuicSpdyStream* stream =
+ new QuicSimpleServerStream(pending, this, quic_simple_server_backend_);
ActivateStream(absl::WrapUnique(stream));
return stream;
}
@@ -144,15 +136,15 @@ void QuicSimpleServerSession::HandleRstOnValidNonexistentStream(
promised_streams_[index].is_cancelled = true;
}
}
- control_frame_manager().WriteOrBufferRstStream(frame.stream_id,
- QUIC_RST_ACKNOWLEDGEMENT, 0);
+ control_frame_manager().WriteOrBufferRstStream(
+ frame.stream_id,
+ QuicResetStreamError::FromInternal(QUIC_RST_ACKNOWLEDGEMENT), 0);
connection()->OnStreamReset(frame.stream_id, QUIC_RST_ACKNOWLEDGEMENT);
}
}
spdy::Http2HeaderBlock QuicSimpleServerSession::SynthesizePushRequestHeaders(
- std::string request_url,
- QuicBackendResponse::ServerPushInfo resource,
+ std::string request_url, QuicBackendResponse::ServerPushInfo resource,
const spdy::Http2HeaderBlock& original_request_headers) {
QuicUrl push_request_url = resource.request_url;
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session.h b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session.h
index 2cc3dcf524f..9746f2697cc 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session.h
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session.h
@@ -96,9 +96,11 @@ class QuicSimpleServerSession : public QuicServerSessionBase {
bool ShouldNegotiateWebTransport() override {
return quic_simple_server_backend_->SupportsWebTransport();
}
- bool ShouldNegotiateHttp3Datagram() override {
- return QuicServerSessionBase::ShouldNegotiateHttp3Datagram() ||
- ShouldNegotiateWebTransport();
+ HttpDatagramSupport LocalHttpDatagramSupport() override {
+ if (ShouldNegotiateWebTransport()) {
+ return HttpDatagramSupport::kDraft00And04;
+ }
+ return QuicServerSessionBase::LocalHttpDatagramSupport();
}
private:
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream.cc
index 5cd365298f3..d7e2a70eb46 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream.cc
@@ -38,11 +38,9 @@ QuicSimpleServerStream::QuicSimpleServerStream(
}
QuicSimpleServerStream::QuicSimpleServerStream(
- PendingStream* pending,
- QuicSpdySession* session,
- StreamType type,
+ PendingStream* pending, QuicSpdySession* session,
QuicSimpleServerBackend* quic_simple_server_backend)
- : QuicSpdyServerStreamBase(pending, session, type),
+ : QuicSpdyServerStreamBase(pending, session),
content_length_(-1),
generate_bytes_length_(0),
quic_simple_server_backend_(quic_simple_server_backend) {
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream.h b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream.h
index 6395345518b..d138492a2ce 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream.h
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream.h
@@ -25,7 +25,6 @@ class QuicSimpleServerStream : public QuicSpdyServerStreamBase,
QuicSimpleServerBackend* quic_simple_server_backend);
QuicSimpleServerStream(PendingStream* pending,
QuicSpdySession* session,
- StreamType type,
QuicSimpleServerBackend* quic_simple_server_backend);
QuicSimpleServerStream(const QuicSimpleServerStream&) = delete;
QuicSimpleServerStream& operator=(const QuicSimpleServerStream&) = delete;
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream_test.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream_test.cc
index 5c9cd2274d9..aa0770399f9 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream_test.cc
@@ -48,13 +48,9 @@ const size_t kDataFrameHeaderLength = 2;
class TestStream : public QuicSimpleServerStream {
public:
- TestStream(QuicStreamId stream_id,
- QuicSpdySession* session,
- StreamType type,
+ TestStream(QuicStreamId stream_id, QuicSpdySession* session, StreamType type,
QuicSimpleServerBackend* quic_simple_server_backend)
- : QuicSimpleServerStream(stream_id,
- session,
- type,
+ : QuicSimpleServerStream(stream_id, session, type,
quic_simple_server_backend) {}
~TestStream() override = default;
@@ -62,8 +58,7 @@ class TestStream : public QuicSimpleServerStream {
MOCK_METHOD(void, WriteHeadersMock, (bool fin), ());
MOCK_METHOD(void, WriteEarlyHintsHeadersMock, (bool fin), ());
- size_t WriteHeaders(spdy::Http2HeaderBlock header_block,
- bool fin,
+ size_t WriteHeaders(spdy::Http2HeaderBlock header_block, bool fin,
QuicReferenceCountedPointer<QuicAckListenerInterface>
/*ack_listener*/) override {
if (header_block[":status"] == "103") {
@@ -116,18 +111,13 @@ class MockQuicSimpleServerSession : public QuicSimpleServerSession {
const size_t kMaxStreamsForTest = 100;
MockQuicSimpleServerSession(
- QuicConnection* connection,
- MockQuicSessionVisitor* owner,
+ QuicConnection* connection, MockQuicSessionVisitor* owner,
MockQuicCryptoServerStreamHelper* helper,
QuicCryptoServerConfig* crypto_config,
QuicCompressedCertsCache* compressed_certs_cache,
QuicSimpleServerBackend* quic_simple_server_backend)
- : QuicSimpleServerSession(DefaultQuicConfig(),
- CurrentSupportedVersions(),
- connection,
- owner,
- helper,
- crypto_config,
+ : QuicSimpleServerSession(DefaultQuicConfig(), CurrentSupportedVersions(),
+ connection, owner, helper, crypto_config,
compressed_certs_cache,
quic_simple_server_backend) {
if (VersionHasIetfQuicFrames(connection->transport_version())) {
@@ -148,47 +138,35 @@ class MockQuicSimpleServerSession : public QuicSimpleServerSession {
delete;
~MockQuicSimpleServerSession() override = default;
- MOCK_METHOD(void,
- OnConnectionClosed,
+ MOCK_METHOD(void, OnConnectionClosed,
(const QuicConnectionCloseFrame& frame,
ConnectionCloseSource source),
(override));
- MOCK_METHOD(QuicSpdyStream*,
- CreateIncomingStream,
- (QuicStreamId id),
+ MOCK_METHOD(QuicSpdyStream*, CreateIncomingStream, (QuicStreamId id),
(override));
MOCK_METHOD(QuicConsumedData, WritevData,
(QuicStreamId id, size_t write_length, QuicStreamOffset offset,
StreamSendingState state, TransmissionType type,
EncryptionLevel level),
(override));
- MOCK_METHOD(void,
- OnStreamHeaderList,
- (QuicStreamId stream_id,
- bool fin,
- size_t frame_len,
+ MOCK_METHOD(void, OnStreamHeaderList,
+ (QuicStreamId stream_id, bool fin, size_t frame_len,
const QuicHeaderList& header_list),
(override));
- MOCK_METHOD(void,
- OnStreamHeadersPriority,
+ MOCK_METHOD(void, OnStreamHeadersPriority,
(QuicStreamId stream_id,
const spdy::SpdyStreamPrecedence& precedence),
(override));
- MOCK_METHOD(void,
- MaybeSendRstStreamFrame,
- (QuicStreamId stream_id,
- QuicRstStreamErrorCode error,
+ MOCK_METHOD(void, MaybeSendRstStreamFrame,
+ (QuicStreamId stream_id, QuicResetStreamError error,
QuicStreamOffset bytes_written),
(override));
- MOCK_METHOD(void,
- MaybeSendStopSendingFrame,
- (QuicStreamId stream_id, QuicRstStreamErrorCode error),
- (override));
+ MOCK_METHOD(void, MaybeSendStopSendingFrame,
+ (QuicStreamId stream_id, QuicResetStreamError error), (override));
using QuicSession::ActivateStream;
- QuicConsumedData ConsumeData(QuicStreamId id,
- size_t write_length,
+ QuicConsumedData ConsumeData(QuicStreamId id, size_t write_length,
QuicStreamOffset offset,
StreamSendingState state,
TransmissionType /*type*/,
@@ -211,23 +189,17 @@ class MockQuicSimpleServerSession : public QuicSimpleServerSession {
class QuicSimpleServerStreamTest : public QuicTestWithParam<ParsedQuicVersion> {
public:
QuicSimpleServerStreamTest()
- : connection_(
- new StrictMock<MockQuicConnection>(&helper_,
- &alarm_factory_,
- Perspective::IS_SERVER,
- SupportedVersions(GetParam()))),
+ : connection_(new StrictMock<MockQuicConnection>(
+ &helper_, &alarm_factory_, Perspective::IS_SERVER,
+ SupportedVersions(GetParam()))),
crypto_config_(new QuicCryptoServerConfig(
- QuicCryptoServerConfig::TESTING,
- QuicRandom::GetInstance(),
+ QuicCryptoServerConfig::TESTING, QuicRandom::GetInstance(),
crypto_test_utils::ProofSourceForTesting(),
KeyExchangeSource::Default())),
compressed_certs_cache_(
QuicCompressedCertsCache::kQuicCompressedCertsCacheSize),
- session_(connection_,
- &session_owner_,
- &session_helper_,
- crypto_config_.get(),
- &compressed_certs_cache_,
+ session_(connection_, &session_owner_, &session_helper_,
+ crypto_config_.get(), &compressed_certs_cache_,
&memory_cache_backend_),
quic_response_(new QuicBackendResponse),
body_("hello world") {
@@ -298,8 +270,7 @@ class QuicSimpleServerStreamTest : public QuicTestWithParam<ParsedQuicVersion> {
QuicHeaderList header_list_;
};
-INSTANTIATE_TEST_SUITE_P(Tests,
- QuicSimpleServerStreamTest,
+INSTANTIATE_TEST_SUITE_P(Tests, QuicSimpleServerStreamTest,
::testing::ValuesIn(AllSupportedVersions()),
::testing::PrintToStringParamName());
@@ -350,10 +321,15 @@ TEST_P(QuicSimpleServerStreamTest, SendQuicRstStreamNoErrorInStopReading) {
stream_->CloseWriteSide();
if (session_.version().UsesHttp3()) {
- EXPECT_CALL(session_, MaybeSendStopSendingFrame(_, QUIC_STREAM_NO_ERROR))
+ EXPECT_CALL(session_,
+ MaybeSendStopSendingFrame(_, QuicResetStreamError::FromInternal(
+ QUIC_STREAM_NO_ERROR)))
.Times(1);
} else {
- EXPECT_CALL(session_, MaybeSendRstStreamFrame(_, QUIC_STREAM_NO_ERROR, _))
+ EXPECT_CALL(
+ session_,
+ MaybeSendRstStreamFrame(
+ _, QuicResetStreamError::FromInternal(QUIC_STREAM_NO_ERROR), _))
.Times(1);
}
stream_->StopReading();
@@ -480,11 +456,16 @@ TEST_P(QuicSimpleServerStreamTest, SendPushResponseWith404Response) {
InSequence s;
if (session_.version().UsesHttp3()) {
- EXPECT_CALL(session_, MaybeSendStopSendingFrame(promised_stream->id(),
- QUIC_STREAM_CANCELLED));
+ EXPECT_CALL(session_,
+ MaybeSendStopSendingFrame(
+ promised_stream->id(),
+ QuicResetStreamError::FromInternal(QUIC_STREAM_CANCELLED)));
}
- EXPECT_CALL(session_, MaybeSendRstStreamFrame(promised_stream->id(),
- QUIC_STREAM_CANCELLED, 0));
+ EXPECT_CALL(
+ session_,
+ MaybeSendRstStreamFrame(
+ promised_stream->id(),
+ QuicResetStreamError::FromInternal(QUIC_STREAM_CANCELLED), 0));
promised_stream->DoSendResponse();
}
@@ -695,11 +676,14 @@ TEST_P(QuicSimpleServerStreamTest,
.Times(AnyNumber());
}
- EXPECT_CALL(session_, MaybeSendRstStreamFrame(_,
- session_.version().UsesHttp3()
- ? QUIC_STREAM_CANCELLED
- : QUIC_RST_ACKNOWLEDGEMENT,
- _))
+ EXPECT_CALL(
+ session_,
+ MaybeSendRstStreamFrame(
+ _,
+ session_.version().UsesHttp3()
+ ? QuicResetStreamError::FromInternal(QUIC_STREAM_CANCELLED)
+ : QuicResetStreamError::FromInternal(QUIC_RST_ACKNOWLEDGEMENT),
+ _))
.Times(1);
QuicRstStreamFrame rst_frame(kInvalidControlFrameId, stream_->id(),
QUIC_STREAM_CANCELLED, 1234);
diff --git a/chromium/net/third_party/quiche/src/quic/tools/web_transport_test_visitors.h b/chromium/net/third_party/quiche/src/quic/tools/web_transport_test_visitors.h
index e348750a474..b1f22469e12 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/web_transport_test_visitors.h
+++ b/chromium/net/third_party/quiche/src/quic/tools/web_transport_test_visitors.h
@@ -29,6 +29,10 @@ class WebTransportDiscardVisitor : public WebTransportStreamVisitor {
void OnCanWrite() override {}
+ void OnResetStreamReceived(WebTransportStreamError /*error*/) override {}
+ void OnStopSendingReceived(WebTransportStreamError /*error*/) override {}
+ void OnWriteSideInDataRecvdState() override {}
+
private:
WebTransportStream* stream_;
};
@@ -51,6 +55,10 @@ class WebTransportBidirectionalEchoVisitor : public WebTransportStreamVisitor {
}
void OnCanWrite() override {
+ if (stop_sending_received_) {
+ return;
+ }
+
if (!buffer_.empty()) {
bool success = stream_->Write(buffer_);
QUIC_DVLOG(1) << "Attempted writing on WebTransport bidirectional stream "
@@ -69,10 +77,26 @@ class WebTransportBidirectionalEchoVisitor : public WebTransportStreamVisitor {
}
}
+ void OnResetStreamReceived(WebTransportStreamError /*error*/) override {
+ // Send FIN in response to a stream reset. We want to test that we can
+ // operate one side of the stream cleanly while the other is reset, thus
+ // replying with a FIN rather than a RESET_STREAM is more appropriate here.
+ send_fin_ = true;
+ OnCanWrite();
+ }
+ void OnStopSendingReceived(WebTransportStreamError /*error*/) override {
+ stop_sending_received_ = true;
+ }
+ void OnWriteSideInDataRecvdState() override {}
+
+ protected:
+ WebTransportStream* stream() { return stream_; }
+
private:
WebTransportStream* stream_;
std::string buffer_;
bool send_fin_ = false;
+ bool stop_sending_received_ = false;
};
// Buffers all of the data and calls |callback| with the entirety of the stream
@@ -100,6 +124,10 @@ class WebTransportUnidirectionalEchoReadVisitor
void OnCanWrite() override { QUIC_NOTREACHED(); }
+ void OnResetStreamReceived(WebTransportStreamError /*error*/) override {}
+ void OnStopSendingReceived(WebTransportStreamError /*error*/) override {}
+ void OnWriteSideInDataRecvdState() override {}
+
private:
WebTransportStream* stream_;
std::string buffer_;
@@ -129,6 +157,10 @@ class WebTransportUnidirectionalEchoWriteVisitor
QUICHE_DCHECK(fin_sent);
}
+ void OnResetStreamReceived(WebTransportStreamError /*error*/) override {}
+ void OnStopSendingReceived(WebTransportStreamError /*error*/) override {}
+ void OnWriteSideInDataRecvdState() override {}
+
private:
WebTransportStream* stream_;
std::string data_;
@@ -141,12 +173,15 @@ class EchoWebTransportSessionVisitor : public WebTransportVisitor {
EchoWebTransportSessionVisitor(WebTransportSession* session)
: session_(session) {}
- void OnSessionReady() override {
+ void OnSessionReady(const spdy::SpdyHeaderBlock&) override {
if (session_->CanOpenNextOutgoingBidirectionalStream()) {
OnCanCreateNewOutgoingBidirectionalStream();
}
}
+ void OnSessionClosed(WebTransportSessionError /*error_code*/,
+ const std::string& /*error_message*/) override {}
+
void OnIncomingBidirectionalStreamAvailable() override {
while (true) {
WebTransportStream* stream =
diff --git a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_decoder_adapter.cc b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_decoder_adapter.cc
index 03db87d2e51..aaee6009740 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_decoder_adapter.cc
+++ b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_decoder_adapter.cc
@@ -29,6 +29,10 @@ void HpackDecoderAdapter::ApplyHeaderTableSizeSetting(size_t size_setting) {
hpack_decoder_.ApplyHeaderTableSizeSetting(size_setting);
}
+size_t HpackDecoderAdapter::GetCurrentHeaderTableSizeSetting() const {
+ return hpack_decoder_.GetCurrentHeaderTableSizeSetting();
+}
+
void HpackDecoderAdapter::HandleControlFrameHeadersStart(
SpdyHeadersHandlerInterface* handler) {
QUICHE_DVLOG(2) << "HpackDecoderAdapter::HandleControlFrameHeadersStart";
@@ -85,12 +89,8 @@ bool HpackDecoderAdapter::HandleControlFrameHeadersData(
return true;
}
-bool HpackDecoderAdapter::HandleControlFrameHeadersComplete(
- size_t* compressed_len) {
+bool HpackDecoderAdapter::HandleControlFrameHeadersComplete() {
QUICHE_DVLOG(2) << "HpackDecoderAdapter::HandleControlFrameHeadersComplete";
- if (compressed_len != nullptr) {
- *compressed_len = listener_adapter_.total_hpack_bytes();
- }
if (!hpack_decoder_.EndDecodingBlock()) {
QUICHE_DVLOG(3) << "EndDecodingBlock returned false";
error_ = hpack_decoder_.error();
diff --git a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_decoder_adapter.h b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_decoder_adapter.h
index 43a762bb757..c4bc99154fe 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_decoder_adapter.h
+++ b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_decoder_adapter.h
@@ -39,6 +39,9 @@ class QUICHE_EXPORT_PRIVATE HpackDecoderAdapter {
// Called upon acknowledgement of SETTINGS_HEADER_TABLE_SIZE.
void ApplyHeaderTableSizeSetting(size_t size_setting);
+ // Returns the most recently applied value of SETTINGS_HEADER_TABLE_SIZE.
+ size_t GetCurrentHeaderTableSizeSetting() const;
+
// If a SpdyHeadersHandlerInterface is provided, the decoder will emit
// headers to it rather than accumulating them in a SpdyHeaderBlock.
// Does not take ownership of the handler, but does use the pointer until
@@ -56,10 +59,7 @@ class QUICHE_EXPORT_PRIVATE HpackDecoderAdapter {
// buffered block that was accumulated in HandleControlFrameHeadersData(),
// to support subsequent calculation of compression percentage.
// Discards the handler supplied at the start of decoding the block.
- // TODO(jamessynge): Determine if compressed_len is needed; it is used to
- // produce UUMA stat Net.SpdyHpackDecompressionPercentage, but only for
- // deprecated SPDY3.
- bool HandleControlFrameHeadersComplete(size_t* compressed_len);
+ bool HandleControlFrameHeadersComplete();
// Accessor for the most recently decoded headers block. Valid until the next
// call to HandleControlFrameHeadersData().
diff --git a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_decoder_adapter_test.cc b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_decoder_adapter_test.cc
index bab6c481e78..f1f64e6a8c2 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_decoder_adapter_test.cc
+++ b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_decoder_adapter_test.cc
@@ -141,11 +141,8 @@ class HpackDecoderAdapterTest
return decoder_.HandleControlFrameHeadersData(str.data(), str.size());
}
- bool HandleControlFrameHeadersComplete(size_t* size) {
- bool rc = decoder_.HandleControlFrameHeadersComplete(size);
- if (size != nullptr) {
- EXPECT_EQ(*size, bytes_passed_in_);
- }
+ bool HandleControlFrameHeadersComplete() {
+ bool rc = decoder_.HandleControlFrameHeadersComplete();
return rc;
}
@@ -172,22 +169,18 @@ class HpackDecoderAdapterTest
decode_has_failed_ = true;
return false;
}
- // Want to get out the number of compressed bytes that were decoded,
- // so pass in a pointer if no handler.
- size_t total_hpack_bytes = 0;
if (start_choice_ == START_WITH_HANDLER) {
- if (!HandleControlFrameHeadersComplete(nullptr)) {
+ if (!HandleControlFrameHeadersComplete()) {
decode_has_failed_ = true;
return false;
}
- total_hpack_bytes = handler_.compressed_header_bytes();
+ EXPECT_EQ(handler_.compressed_header_bytes(), bytes_passed_in_);
} else {
- if (!HandleControlFrameHeadersComplete(&total_hpack_bytes)) {
+ if (!HandleControlFrameHeadersComplete()) {
decode_has_failed_ = true;
return false;
}
}
- EXPECT_EQ(total_hpack_bytes, bytes_passed_in_);
if (check_decoded_size && start_choice_ == START_WITH_HANDLER) {
EXPECT_EQ(handler_.uncompressed_header_bytes(),
SizeOfHeaders(decoded_block()));
@@ -274,6 +267,12 @@ INSTANTIATE_TEST_SUITE_P(
::testing::Combine(::testing::Values(START_WITH_HANDLER),
::testing::Bool()));
+TEST_P(HpackDecoderAdapterTest, ApplyHeaderTableSizeSetting) {
+ EXPECT_EQ(4096u, decoder_.GetCurrentHeaderTableSizeSetting());
+ decoder_.ApplyHeaderTableSizeSetting(12 * 1024);
+ EXPECT_EQ(12288u, decoder_.GetCurrentHeaderTableSizeSetting());
+}
+
TEST_P(HpackDecoderAdapterTest,
AddHeaderDataWithHandleControlFrameHeadersData) {
// The hpack decode buffer size is limited in size. This test verifies that
@@ -352,8 +351,7 @@ TEST_P(HpackDecoderAdapterTest, HeaderBlockTooLong) {
// entire block successfully.
HandleControlFrameHeadersStart();
EXPECT_TRUE(HandleControlFrameHeadersData(hbb.buffer()));
- size_t total_bytes;
- EXPECT_TRUE(HandleControlFrameHeadersComplete(&total_bytes));
+ EXPECT_TRUE(HandleControlFrameHeadersComplete());
// When a total byte limit is imposed, the decoder bails before the end of the
// block.
@@ -387,9 +385,7 @@ TEST_P(HpackDecoderAdapterTest, DecodeWithIncompleteData) {
// Add the needed data.
EXPECT_TRUE(HandleControlFrameHeadersData("\x04gggs"));
- size_t size = 0;
- EXPECT_TRUE(HandleControlFrameHeadersComplete(&size));
- EXPECT_EQ(24u, size);
+ EXPECT_TRUE(HandleControlFrameHeadersComplete());
expected_headers.push_back({"spam", "gggs"});
@@ -429,7 +425,7 @@ TEST_P(HpackDecoderAdapterTest, HandleHeaderRepresentation) {
decoder_peer_.HandleHeaderRepresentation("cookie", " fin!");
// Finish and emit all headers.
- decoder_.HandleControlFrameHeadersComplete(nullptr);
+ decoder_.HandleControlFrameHeadersComplete();
// Resulting decoded headers are in the same order as the inputs.
EXPECT_THAT(
@@ -503,8 +499,8 @@ TEST_P(HpackDecoderAdapterTest, ContextUpdateMaximumSize) {
output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode);
output_stream.AppendUint32(126);
- output_stream.TakeString(&input);
- EXPECT_TRUE(DecodeHeaderBlock(absl::string_view(input)));
+ input = output_stream.TakeString();
+ EXPECT_TRUE(DecodeHeaderBlock(input));
EXPECT_EQ(126u, decoder_peer_.header_table_size_limit());
}
{
@@ -513,8 +509,8 @@ TEST_P(HpackDecoderAdapterTest, ContextUpdateMaximumSize) {
output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode);
output_stream.AppendUint32(kDefaultHeaderTableSizeSetting);
- output_stream.TakeString(&input);
- EXPECT_TRUE(DecodeHeaderBlock(absl::string_view(input)));
+ input = output_stream.TakeString();
+ EXPECT_TRUE(DecodeHeaderBlock(input));
EXPECT_EQ(kDefaultHeaderTableSizeSetting,
decoder_peer_.header_table_size_limit());
}
@@ -524,8 +520,8 @@ TEST_P(HpackDecoderAdapterTest, ContextUpdateMaximumSize) {
output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode);
output_stream.AppendUint32(kDefaultHeaderTableSizeSetting + 1);
- output_stream.TakeString(&input);
- EXPECT_FALSE(DecodeHeaderBlock(absl::string_view(input)));
+ input = output_stream.TakeString();
+ EXPECT_FALSE(DecodeHeaderBlock(input));
EXPECT_EQ(kDefaultHeaderTableSizeSetting,
decoder_peer_.header_table_size_limit());
}
@@ -542,8 +538,8 @@ TEST_P(HpackDecoderAdapterTest, TwoTableSizeUpdates) {
output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode);
output_stream.AppendUint32(122);
- output_stream.TakeString(&input);
- EXPECT_TRUE(DecodeHeaderBlock(absl::string_view(input)));
+ input = output_stream.TakeString();
+ EXPECT_TRUE(DecodeHeaderBlock(input));
EXPECT_EQ(122u, decoder_peer_.header_table_size_limit());
}
}
@@ -561,9 +557,9 @@ TEST_P(HpackDecoderAdapterTest, ThreeTableSizeUpdatesError) {
output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode);
output_stream.AppendUint32(15);
- output_stream.TakeString(&input);
+ input = output_stream.TakeString();
- EXPECT_FALSE(DecodeHeaderBlock(absl::string_view(input)));
+ EXPECT_FALSE(DecodeHeaderBlock(input));
EXPECT_EQ(10u, decoder_peer_.header_table_size_limit());
}
}
@@ -580,9 +576,9 @@ TEST_P(HpackDecoderAdapterTest, TableSizeUpdateSecondError) {
output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode);
output_stream.AppendUint32(123);
- output_stream.TakeString(&input);
+ input = output_stream.TakeString();
- EXPECT_FALSE(DecodeHeaderBlock(absl::string_view(input)));
+ EXPECT_FALSE(DecodeHeaderBlock(input));
EXPECT_EQ(kDefaultHeaderTableSizeSetting,
decoder_peer_.header_table_size_limit());
}
@@ -603,9 +599,9 @@ TEST_P(HpackDecoderAdapterTest, TableSizeUpdateFirstThirdError) {
output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode);
output_stream.AppendUint32(125);
- output_stream.TakeString(&input);
+ input = output_stream.TakeString();
- EXPECT_FALSE(DecodeHeaderBlock(absl::string_view(input)));
+ EXPECT_FALSE(DecodeHeaderBlock(input));
EXPECT_EQ(60u, decoder_peer_.header_table_size_limit());
}
}
@@ -719,9 +715,8 @@ TEST_P(HpackDecoderAdapterTest, BasicC31) {
expected_header_set[":path"] = "/";
expected_header_set[":authority"] = "www.example.com";
- std::string encoded_header_set;
- EXPECT_TRUE(
- encoder.EncodeHeaderSet(expected_header_set, &encoded_header_set));
+ std::string encoded_header_set =
+ encoder.EncodeHeaderBlock(expected_header_set);
EXPECT_TRUE(DecodeHeaderBlock(encoded_header_set));
EXPECT_EQ(expected_header_set, decoded_block());
diff --git a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_encoder.cc b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_encoder.cc
index ccf17da20b2..1821d7cfbfc 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_encoder.cc
+++ b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_encoder.cc
@@ -84,8 +84,7 @@ HpackEncoder::HpackEncoder()
HpackEncoder::~HpackEncoder() = default;
-bool HpackEncoder::EncodeHeaderSet(const SpdyHeaderBlock& header_set,
- std::string* output) {
+std::string HpackEncoder::EncodeHeaderBlock(const SpdyHeaderBlock& header_set) {
// Separate header set into pseudo-headers and regular headers.
Representations pseudo_headers;
Representations regular_headers;
@@ -104,11 +103,8 @@ bool HpackEncoder::EncodeHeaderSet(const SpdyHeaderBlock& header_set,
}
}
- {
- RepresentationIterator iter(pseudo_headers, regular_headers);
- EncodeRepresentations(&iter, output);
- }
- return true;
+ RepresentationIterator iter(pseudo_headers, regular_headers);
+ return EncodeRepresentations(&iter);
}
void HpackEncoder::ApplyHeaderTableSizeSetting(size_t size_setting) {
@@ -123,8 +119,7 @@ void HpackEncoder::ApplyHeaderTableSizeSetting(size_t size_setting) {
should_emit_table_size_ = true;
}
-void HpackEncoder::EncodeRepresentations(RepresentationIterator* iter,
- std::string* output) {
+std::string HpackEncoder::EncodeRepresentations(RepresentationIterator* iter) {
MaybeEmitTableSize();
while (iter->HasNext()) {
const auto header = iter->Next();
@@ -144,7 +139,7 @@ void HpackEncoder::EncodeRepresentations(RepresentationIterator* iter,
}
}
- output_stream_.TakeString(output);
+ return output_stream_.TakeString();
}
void HpackEncoder::EmitIndex(size_t index) {
@@ -283,9 +278,8 @@ class HpackEncoder::Encoderator : public ProgressiveEncoder {
// Returns true iff more remains to encode.
bool HasNext() const override { return has_next_; }
- // Encodes up to max_encoded_bytes of the current header block into the
- // given output string.
- void Next(size_t max_encoded_bytes, std::string* output) override;
+ // Encodes and returns up to max_encoded_bytes of the current header block.
+ std::string Next(size_t max_encoded_bytes) override;
private:
HpackEncoder* encoder_;
@@ -338,8 +332,7 @@ HpackEncoder::Encoderator::Encoderator(const Representations& representations,
encoder_->MaybeEmitTableSize();
}
-void HpackEncoder::Encoderator::Next(size_t max_encoded_bytes,
- std::string* output) {
+std::string HpackEncoder::Encoderator::Next(size_t max_encoded_bytes) {
QUICHE_BUG_IF(spdy_bug_61_1, !has_next_)
<< "Encoderator::Next called with nothing left to encode.";
const bool enable_compression = encoder_->enable_compression_;
@@ -365,7 +358,7 @@ void HpackEncoder::Encoderator::Next(size_t max_encoded_bytes,
}
has_next_ = encoder_->output_stream_.size() > max_encoded_bytes;
- encoder_->output_stream_.BoundedTakeString(max_encoded_bytes, output);
+ return encoder_->output_stream_.BoundedTakeString(max_encoded_bytes);
}
std::unique_ptr<HpackEncoder::ProgressiveEncoder> HpackEncoder::EncodeHeaderSet(
diff --git a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_encoder.h b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_encoder.h
index 5e2ea03980c..05292976b64 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_encoder.h
+++ b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_encoder.h
@@ -49,9 +49,8 @@ class QUICHE_EXPORT_PRIVATE HpackEncoder {
HpackEncoder& operator=(const HpackEncoder&) = delete;
~HpackEncoder();
- // Encodes the given header set into the given string. Returns
- // whether or not the encoding was successful.
- bool EncodeHeaderSet(const SpdyHeaderBlock& header_set, std::string* output);
+ // Encodes and returns the given header set as a string.
+ std::string EncodeHeaderBlock(const SpdyHeaderBlock& header_set);
class QUICHE_EXPORT_PRIVATE ProgressiveEncoder {
public:
@@ -60,9 +59,8 @@ class QUICHE_EXPORT_PRIVATE HpackEncoder {
// Returns true iff more remains to encode.
virtual bool HasNext() const = 0;
- // Encodes up to max_encoded_bytes of the current header block into the
- // given output string.
- virtual void Next(size_t max_encoded_bytes, std::string* output) = 0;
+ // Encodes and returns up to max_encoded_bytes of the current header block.
+ virtual std::string Next(size_t max_encoded_bytes) = 0;
};
// Returns a ProgressiveEncoder which must be outlived by both the given
@@ -106,7 +104,7 @@ class QUICHE_EXPORT_PRIVATE HpackEncoder {
class Encoderator;
// Encodes a sequence of header name-value pairs as a single header block.
- void EncodeRepresentations(RepresentationIterator* iter, std::string* output);
+ std::string EncodeRepresentations(RepresentationIterator* iter);
// Emits a static/dynamic indexed representation (Section 7.1).
void EmitIndex(size_t index);
diff --git a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_encoder_test.cc b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_encoder_test.cc
index dfd8d8fea2c..c47bf979499 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_encoder_test.cc
+++ b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_encoder_test.cc
@@ -45,7 +45,7 @@ class HpackEncoderPeer {
HpackHeaderTablePeer table_peer() { return HpackHeaderTablePeer(table()); }
void EmitString(absl::string_view str) { encoder_->EmitString(str); }
void TakeString(std::string* out) {
- encoder_->output_stream_.TakeString(out);
+ *out = encoder_->output_stream_.TakeString();
}
static void CookieToCrumbs(absl::string_view cookie,
std::vector<absl::string_view>* out) {
@@ -71,10 +71,9 @@ class HpackEncoderPeer {
// TODO(dahollings): Remove or clean up these methods when deprecating
// non-incremental encoding path.
- static bool EncodeHeaderSet(HpackEncoder* encoder,
- const SpdyHeaderBlock& header_set,
- std::string* output) {
- return encoder->EncodeHeaderSet(header_set, output);
+ static std::string EncodeHeaderBlock(HpackEncoder* encoder,
+ const SpdyHeaderBlock& header_set) {
+ return encoder->EncodeHeaderBlock(header_set);
}
static bool EncodeIncremental(HpackEncoder* encoder,
@@ -82,12 +81,11 @@ class HpackEncoderPeer {
std::string* output) {
std::unique_ptr<HpackEncoder::ProgressiveEncoder> encoderator =
encoder->EncodeHeaderSet(header_set);
- std::string output_buffer;
http2::test::Http2Random random;
- encoderator->Next(random.UniformInRange(0, 16), &output_buffer);
+ std::string output_buffer = encoderator->Next(random.UniformInRange(0, 16));
while (encoderator->HasNext()) {
- std::string second_buffer;
- encoderator->Next(random.UniformInRange(0, 16), &second_buffer);
+ std::string second_buffer =
+ encoderator->Next(random.UniformInRange(0, 16));
output_buffer.append(second_buffer);
}
*output = std::move(output_buffer);
@@ -99,12 +97,11 @@ class HpackEncoderPeer {
std::string* output) {
std::unique_ptr<HpackEncoder::ProgressiveEncoder> encoderator =
encoder->EncodeRepresentations(representations);
- std::string output_buffer;
http2::test::Http2Random random;
- encoderator->Next(random.UniformInRange(0, 16), &output_buffer);
+ std::string output_buffer = encoderator->Next(random.UniformInRange(0, 16));
while (encoderator->HasNext()) {
- std::string second_buffer;
- encoderator->Next(random.UniformInRange(0, 16), &second_buffer);
+ std::string second_buffer =
+ encoderator->Next(random.UniformInRange(0, 16));
output_buffer.append(second_buffer);
}
*output = std::move(output_buffer);
@@ -219,12 +216,12 @@ class HpackEncoderTest : public QuicheTestWithParam<EncodeStrategy> {
return r;
}
void CompareWithExpectedEncoding(const SpdyHeaderBlock& header_set) {
- std::string expected_out, actual_out;
- expected_.TakeString(&expected_out);
+ std::string actual_out;
+ std::string expected_out = expected_.TakeString();
switch (strategy_) {
case kDefault:
- EXPECT_TRUE(test::HpackEncoderPeer::EncodeHeaderSet(
- &encoder_, header_set, &actual_out));
+ actual_out =
+ test::HpackEncoderPeer::EncodeHeaderBlock(&encoder_, header_set);
break;
case kIncremental:
EXPECT_TRUE(test::HpackEncoderPeer::EncodeIncremental(
@@ -238,8 +235,8 @@ class HpackEncoderTest : public QuicheTestWithParam<EncodeStrategy> {
EXPECT_EQ(expected_out, actual_out);
}
void CompareWithExpectedEncoding(const Representations& representations) {
- std::string expected_out, actual_out;
- expected_.TakeString(&expected_out);
+ std::string actual_out;
+ std::string expected_out = expected_.TakeString();
EXPECT_TRUE(test::HpackEncoderPeer::EncodeRepresentations(
&encoder_, representations, &actual_out));
EXPECT_EQ(expected_out, actual_out);
@@ -460,8 +457,8 @@ TEST_P(HpackEncoderTest, StringsDynamicallySelectHuffmanCoding) {
expected_.AppendUint32(6);
expected_.AppendBytes("@@@@@@");
- std::string expected_out, actual_out;
- expected_.TakeString(&expected_out);
+ std::string actual_out;
+ std::string expected_out = expected_.TakeString();
peer_.TakeString(&actual_out);
EXPECT_EQ(expected_out, actual_out);
}
diff --git a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_output_stream.cc b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_output_stream.cc
index bce24fa610d..291ad3d6d67 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_output_stream.cc
+++ b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_output_stream.cc
@@ -68,31 +68,32 @@ std::string* HpackOutputStream::MutableString() {
return &buffer_;
}
-void HpackOutputStream::TakeString(std::string* output) {
+std::string HpackOutputStream::TakeString() {
// This must hold, since all public functions cause the buffer to
// end on a byte boundary.
QUICHE_DCHECK_EQ(bit_offset_, 0u);
- buffer_.swap(*output);
- buffer_.clear();
+ std::string out = std::move(buffer_);
+ buffer_ = {};
bit_offset_ = 0;
+ return out;
}
-void HpackOutputStream::BoundedTakeString(size_t max_size,
- std::string* output) {
+std::string HpackOutputStream::BoundedTakeString(size_t max_size) {
if (buffer_.size() > max_size) {
// Save off overflow bytes to temporary string (causes a copy).
- std::string overflow(buffer_.data() + max_size, buffer_.size() - max_size);
+ std::string overflow = buffer_.substr(max_size);
// Resize buffer down to the given limit.
buffer_.resize(max_size);
// Give buffer to output string.
- *output = std::move(buffer_);
+ std::string out = std::move(buffer_);
// Reset to contain overflow.
buffer_ = std::move(overflow);
+ return out;
} else {
- TakeString(output);
+ return TakeString();
}
}
diff --git a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_output_stream.h b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_output_stream.h
index ec657b54064..ade1cd1ae68 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_output_stream.h
+++ b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_output_stream.h
@@ -51,12 +51,12 @@ class QUICHE_EXPORT_PRIVATE HpackOutputStream {
// Return pointer to internal buffer. |bit_offset_| needs to be zero.
std::string* MutableString();
- // Swaps the internal buffer with |output|, then resets state.
- void TakeString(std::string* output);
+ // Returns the internal buffer as a string, then resets state.
+ std::string TakeString();
- // Gives up to |max_size| bytes of the internal buffer to |output|. Resets
+ // Returns up to |max_size| bytes of the internal buffer. Resets
// internal state with the overflow.
- void BoundedTakeString(size_t max_size, std::string* output);
+ std::string BoundedTakeString(size_t max_size);
// Size in bytes of stream's internal buffer.
size_t size() const { return buffer_.size(); }
diff --git a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_output_stream_test.cc b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_output_stream_test.cc
index ea05ecedf5d..3d8c35db344 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_output_stream_test.cc
+++ b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_output_stream_test.cc
@@ -37,8 +37,7 @@ TEST(HpackOutputStreamTest, AppendBits) {
output_stream.AppendBits(0x0, 7);
- std::string str;
- output_stream.TakeString(&str);
+ std::string str = output_stream.TakeString();
EXPECT_EQ(expected_str, str);
}
@@ -50,8 +49,7 @@ std::string EncodeUint32(uint8_t N, uint32_t I) {
output_stream.AppendBits(0x00, 8 - N);
}
output_stream.AppendUint32(I);
- std::string str;
- output_stream.TakeString(&str);
+ std::string str = output_stream.TakeString();
return str;
}
@@ -236,8 +234,7 @@ TEST(HpackOutputStreamTest, AppendUint32PreservesUpperBits) {
HpackOutputStream output_stream;
output_stream.AppendBits(0x7f, 7);
output_stream.AppendUint32(0x01);
- std::string str;
- output_stream.TakeString(&str);
+ std::string str = output_stream.TakeString();
EXPECT_EQ(std::string("\xff\x00", 2), str);
}
@@ -247,8 +244,7 @@ TEST(HpackOutputStreamTest, AppendBytes) {
output_stream.AppendBytes("buffer1");
output_stream.AppendBytes("buffer2");
- std::string str;
- output_stream.TakeString(&str);
+ std::string str = output_stream.TakeString();
EXPECT_EQ("buffer1buffer2", str);
}
@@ -258,16 +254,15 @@ TEST(HpackOutputStreamTest, BoundedTakeString) {
output_stream.AppendBytes("buffer12");
output_stream.AppendBytes("buffer456");
- std::string str;
- output_stream.BoundedTakeString(9, &str);
+ std::string str = output_stream.BoundedTakeString(9);
EXPECT_EQ("buffer12b", str);
output_stream.AppendBits(0x7f, 7);
output_stream.AppendUint32(0x11);
- output_stream.BoundedTakeString(9, &str);
+ str = output_stream.BoundedTakeString(9);
EXPECT_EQ("uffer456\xff", str);
- output_stream.BoundedTakeString(9, &str);
+ str = output_stream.BoundedTakeString(9);
EXPECT_EQ("\x10", str);
}
@@ -280,8 +275,7 @@ TEST(HpackOutputStreamTest, MutableString) {
output_stream.AppendBytes("foo");
output_stream.MutableString()->append("bar");
- std::string str;
- output_stream.TakeString(&str);
+ std::string str = output_stream.TakeString();
EXPECT_EQ("12foobar", str);
}
diff --git a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_round_trip_test.cc b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_round_trip_test.cc
index 047ae7292e6..42a4f2ea44d 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_round_trip_test.cc
+++ b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_round_trip_test.cc
@@ -31,8 +31,7 @@ class HpackRoundTripTest : public QuicheTestWithParam<InputSizeParam> {
}
bool RoundTrip(const SpdyHeaderBlock& header_set) {
- std::string encoded;
- encoder_.EncodeHeaderSet(header_set, &encoded);
+ std::string encoded = encoder_.EncodeHeaderBlock(header_set);
bool success = true;
if (GetParam() == ALL_INPUT) {
@@ -58,7 +57,7 @@ class HpackRoundTripTest : public QuicheTestWithParam<InputSizeParam> {
}
if (success) {
- success = decoder_.HandleControlFrameHeadersComplete(nullptr);
+ success = decoder_.HandleControlFrameHeadersComplete();
}
EXPECT_EQ(header_set, decoder_.decoded_block());
diff --git a/chromium/net/third_party/quiche/src/spdy/core/http2_frame_decoder_adapter.cc b/chromium/net/third_party/quiche/src/spdy/core/http2_frame_decoder_adapter.cc
index e2e311dda07..0691f6b7bb9 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/http2_frame_decoder_adapter.cc
+++ b/chromium/net/third_party/quiche/src/spdy/core/http2_frame_decoder_adapter.cc
@@ -1104,7 +1104,7 @@ void Http2DecoderAdapter::CommonHpackFragmentEnd() {
<< frame_header();
has_expected_frame_type_ = false;
auto* decoder = GetHpackDecoder();
- if (decoder->HandleControlFrameHeadersComplete(nullptr)) {
+ if (decoder->HandleControlFrameHeadersComplete()) {
visitor()->OnHeaderFrameEnd(stream_id());
} else {
SetSpdyErrorAndNotify(
diff --git a/chromium/net/third_party/quiche/src/spdy/core/metadata_extension.cc b/chromium/net/third_party/quiche/src/spdy/core/metadata_extension.cc
index 12f6af14843..1683dcc4ff2 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/metadata_extension.cc
+++ b/chromium/net/third_party/quiche/src/spdy/core/metadata_extension.cc
@@ -55,9 +55,9 @@ std::unique_ptr<spdy::SpdyFrameIR> MetadataFrameSequence::Next() {
if (!progressive_encoder_->HasNext()) {
return nullptr;
}
- std::string payload;
// METADATA frames obey the HTTP/2 maximum frame size.
- progressive_encoder_->Next(spdy::kHttp2DefaultFramePayloadLimit, &payload);
+ std::string payload =
+ progressive_encoder_->Next(spdy::kHttp2DefaultFramePayloadLimit);
const bool end_metadata = (!progressive_encoder_->HasNext());
const uint8_t flags = end_metadata ? MetadataVisitor::kEndMetadataFlag : 0;
return absl::make_unique<spdy::SpdyUnknownIR>(
diff --git a/chromium/net/third_party/quiche/src/spdy/core/metadata_extension_test.cc b/chromium/net/third_party/quiche/src/spdy/core/metadata_extension_test.cc
index 07a5ee1113f..7538c317274 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/metadata_extension_test.cc
+++ b/chromium/net/third_party/quiche/src/spdy/core/metadata_extension_test.cc
@@ -106,7 +106,7 @@ TEST_F(MetadataExtensionTest, MetadataIgnoredWithoutExtension) {
ASSERT_TRUE(frame != nullptr);
while (frame != nullptr) {
const size_t frame_size = framer.SerializeFrame(*frame, &test_buffer_);
- ASSERT_GT(frame_size, 0);
+ ASSERT_GT(frame_size, 0u);
ASSERT_FALSE(deframer.HasError());
ASSERT_EQ(frame_size, test_buffer_.Size());
EXPECT_EQ(frame_size, deframer.ProcessInput(kBuffer, frame_size));
@@ -151,14 +151,14 @@ TEST_F(MetadataExtensionTest, MetadataPayloadEndToEnd) {
ASSERT_TRUE(frame != nullptr);
while (frame != nullptr) {
const size_t frame_size = framer.SerializeFrame(*frame, &test_buffer_);
- ASSERT_GT(frame_size, 0);
+ ASSERT_GT(frame_size, 0u);
ASSERT_FALSE(deframer.HasError());
ASSERT_EQ(frame_size, test_buffer_.Size());
EXPECT_EQ(frame_size, deframer.ProcessInput(kBuffer, frame_size));
test_buffer_.Reset();
frame = sequence->Next();
}
- EXPECT_EQ(1, received_count_);
+ EXPECT_EQ(1u, received_count_);
auto it = received_payload_map_.find(3);
ASSERT_TRUE(it != received_payload_map_.end());
EXPECT_EQ(payload_block, it->second);
@@ -201,7 +201,7 @@ TEST_F(MetadataExtensionTest, MetadataPayloadInterleaved) {
for (auto frame : {frame1.get(), frame2.get()}) {
if (frame != nullptr) {
const size_t frame_size = framer.SerializeFrame(*frame, &test_buffer_);
- ASSERT_GT(frame_size, 0);
+ ASSERT_GT(frame_size, 0u);
ASSERT_FALSE(deframer.HasError());
ASSERT_EQ(frame_size, test_buffer_.Size());
EXPECT_EQ(frame_size, deframer.ProcessInput(kBuffer, frame_size));
@@ -211,7 +211,7 @@ TEST_F(MetadataExtensionTest, MetadataPayloadInterleaved) {
frame1 = sequence1->Next();
frame2 = sequence2->Next();
}
- EXPECT_EQ(2, received_count_);
+ EXPECT_EQ(2u, received_count_);
auto it = received_payload_map_.find(3);
ASSERT_TRUE(it != received_payload_map_.end());
EXPECT_EQ(payload1, it->second);
diff --git a/chromium/net/third_party/quiche/src/spdy/core/spdy_alt_svc_wire_format.cc b/chromium/net/third_party/quiche/src/spdy/core/spdy_alt_svc_wire_format.cc
index f1cca0da3b1..de37a1208b7 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/spdy_alt_svc_wire_format.cc
+++ b/chromium/net/third_party/quiche/src/spdy/core/spdy_alt_svc_wire_format.cc
@@ -39,15 +39,12 @@ bool ParsePositiveIntegerImpl(absl::string_view::const_iterator c,
SpdyAltSvcWireFormat::AlternativeService::AlternativeService() = default;
SpdyAltSvcWireFormat::AlternativeService::AlternativeService(
- const std::string& protocol_id,
- const std::string& host,
- uint16_t port,
- uint32_t max_age,
- VersionVector version)
+ const std::string& protocol_id, const std::string& host, uint16_t port,
+ uint32_t max_age_seconds, VersionVector version)
: protocol_id(protocol_id),
host(host),
port(port),
- max_age(max_age),
+ max_age_seconds(max_age_seconds),
version(std::move(version)) {}
SpdyAltSvcWireFormat::AlternativeService::~AlternativeService() = default;
@@ -113,7 +110,7 @@ bool SpdyAltSvcWireFormat::ParseHeaderFieldValue(
}
++c;
// Parse parameters.
- uint32_t max_age = 86400;
+ uint32_t max_age_seconds = 86400;
VersionVector version;
absl::string_view::const_iterator parameters_end =
std::find(c, value.end(), ',');
@@ -147,7 +144,8 @@ bool SpdyAltSvcWireFormat::ParseHeaderFieldValue(
return false;
}
if (parameter_name == "ma") {
- if (!ParsePositiveInteger32(parameter_value_begin, c, &max_age)) {
+ if (!ParsePositiveInteger32(parameter_value_begin, c,
+ &max_age_seconds)) {
return false;
}
} else if (!is_ietf_format_quic && parameter_name == "v") {
@@ -204,7 +202,8 @@ bool SpdyAltSvcWireFormat::ParseHeaderFieldValue(
version.push_back(quic_version);
}
}
- altsvc_vector->emplace_back(protocol_id, host, port, max_age, version);
+ altsvc_vector->emplace_back(protocol_id, host, port, max_age_seconds,
+ version);
for (; c != value.end() && (*c == ' ' || *c == '\t' || *c == ','); ++c) {
}
}
@@ -266,8 +265,8 @@ std::string SpdyAltSvcWireFormat::SerializeHeaderFieldValue(
value.push_back(c);
}
absl::StrAppend(&value, ":", altsvc.port, "\"");
- if (altsvc.max_age != 86400) {
- absl::StrAppend(&value, "; ma=", altsvc.max_age);
+ if (altsvc.max_age_seconds != 86400) {
+ absl::StrAppend(&value, "; ma=", altsvc.max_age_seconds);
}
if (!altsvc.version.empty()) {
if (is_ietf_format_quic) {
diff --git a/chromium/net/third_party/quiche/src/spdy/core/spdy_alt_svc_wire_format.h b/chromium/net/third_party/quiche/src/spdy/core/spdy_alt_svc_wire_format.h
index a8e10948a8c..664dc1c15cf 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/spdy_alt_svc_wire_format.h
+++ b/chromium/net/third_party/quiche/src/spdy/core/spdy_alt_svc_wire_format.h
@@ -35,15 +35,13 @@ class QUICHE_EXPORT_PRIVATE SpdyAltSvcWireFormat {
// Default is 0: invalid port.
uint16_t port = 0;
// Default is one day.
- uint32_t max_age = 86400;
+ uint32_t max_age_seconds = 86400;
// Default is empty: unspecified version.
VersionVector version;
AlternativeService();
- AlternativeService(const std::string& protocol_id,
- const std::string& host,
- uint16_t port,
- uint32_t max_age,
+ AlternativeService(const std::string& protocol_id, const std::string& host,
+ uint16_t port, uint32_t max_age_seconds,
VersionVector version);
AlternativeService(const AlternativeService& other);
~AlternativeService();
@@ -51,7 +49,7 @@ class QUICHE_EXPORT_PRIVATE SpdyAltSvcWireFormat {
bool operator==(const AlternativeService& other) const {
return protocol_id == other.protocol_id && host == other.host &&
port == other.port && version == other.version &&
- max_age == other.max_age;
+ max_age_seconds == other.max_age_seconds;
}
};
// An empty vector means alternative services should be cleared for given
diff --git a/chromium/net/third_party/quiche/src/spdy/core/spdy_alt_svc_wire_format_test.cc b/chromium/net/third_party/quiche/src/spdy/core/spdy_alt_svc_wire_format_test.cc
index 497f19dad86..70e708b20cf 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/spdy_alt_svc_wire_format_test.cc
+++ b/chromium/net/third_party/quiche/src/spdy/core/spdy_alt_svc_wire_format_test.cc
@@ -30,13 +30,15 @@ class SpdyAltSvcWireFormatPeer {
}
static bool ParsePositiveInteger16(absl::string_view::const_iterator c,
absl::string_view::const_iterator end,
- uint16_t* max_age) {
- return SpdyAltSvcWireFormat::ParsePositiveInteger16(c, end, max_age);
+ uint16_t* max_age_seconds) {
+ return SpdyAltSvcWireFormat::ParsePositiveInteger16(c, end,
+ max_age_seconds);
}
static bool ParsePositiveInteger32(absl::string_view::const_iterator c,
absl::string_view::const_iterator end,
- uint32_t* max_age) {
- return SpdyAltSvcWireFormat::ParsePositiveInteger32(c, end, max_age);
+ uint32_t* max_age_seconds) {
+ return SpdyAltSvcWireFormat::ParsePositiveInteger32(c, end,
+ max_age_seconds);
}
static char HexDigitToInt(char c) {
return SpdyAltSvcWireFormat::HexDigitToInt(c);
@@ -79,7 +81,7 @@ void FuzzHeaderFieldValue(
header_field_value->append(" ");
}
if (i & 3 << 3) {
- expected_altsvc->max_age = 1111;
+ expected_altsvc->max_age_seconds = 1111;
header_field_value->append(";");
if (i & 1 << 3) {
header_field_value->append(" ");
@@ -114,7 +116,7 @@ void FuzzHeaderFieldValue(
}
}
if (i & 1 << 8) {
- expected_altsvc->max_age = 999999999;
+ expected_altsvc->max_age_seconds = 999999999;
header_field_value->append("; Ma=999999999");
}
if (i & 1 << 9) {
@@ -148,7 +150,7 @@ void FuzzAlternativeService(int i,
}
expected_header_field_value->append(":42\"");
if (i & 1 << 1) {
- altsvc->max_age = 1111;
+ altsvc->max_age_seconds = 1111;
expected_header_field_value->append("; ma=1111");
}
if (i & 1 << 2) {
@@ -165,7 +167,7 @@ TEST(SpdyAltSvcWireFormatTest, DefaultValues) {
EXPECT_EQ("", altsvc.protocol_id);
EXPECT_EQ("", altsvc.host);
EXPECT_EQ(0u, altsvc.port);
- EXPECT_EQ(86400u, altsvc.max_age);
+ EXPECT_EQ(86400u, altsvc.max_age_seconds);
EXPECT_TRUE(altsvc.version.empty());
}
@@ -196,7 +198,8 @@ TEST(SpdyAltSvcWireFormatTest, ParseHeaderFieldValue) {
EXPECT_EQ(expected_altsvc.protocol_id, altsvc_vector[0].protocol_id);
EXPECT_EQ(expected_altsvc.host, altsvc_vector[0].host);
EXPECT_EQ(expected_altsvc.port, altsvc_vector[0].port);
- EXPECT_EQ(expected_altsvc.max_age, altsvc_vector[0].max_age);
+ EXPECT_EQ(expected_altsvc.max_age_seconds,
+ altsvc_vector[0].max_age_seconds);
EXPECT_EQ(expected_altsvc.version, altsvc_vector[0].version);
// Roundtrip test starting with |altsvc_vector|.
@@ -210,7 +213,8 @@ TEST(SpdyAltSvcWireFormatTest, ParseHeaderFieldValue) {
roundtrip_altsvc_vector[0].protocol_id);
EXPECT_EQ(expected_altsvc.host, roundtrip_altsvc_vector[0].host);
EXPECT_EQ(expected_altsvc.port, roundtrip_altsvc_vector[0].port);
- EXPECT_EQ(expected_altsvc.max_age, roundtrip_altsvc_vector[0].max_age);
+ EXPECT_EQ(expected_altsvc.max_age_seconds,
+ roundtrip_altsvc_vector[0].max_age_seconds);
EXPECT_EQ(expected_altsvc.version, roundtrip_altsvc_vector[0].version);
}
}
@@ -240,7 +244,8 @@ TEST(SpdyAltSvcWireFormatTest, ParseHeaderFieldValueMultiple) {
altsvc_vector[j].protocol_id);
EXPECT_EQ(expected_altsvc_vector[j].host, altsvc_vector[j].host);
EXPECT_EQ(expected_altsvc_vector[j].port, altsvc_vector[j].port);
- EXPECT_EQ(expected_altsvc_vector[j].max_age, altsvc_vector[j].max_age);
+ EXPECT_EQ(expected_altsvc_vector[j].max_age_seconds,
+ altsvc_vector[j].max_age_seconds);
EXPECT_EQ(expected_altsvc_vector[j].version, altsvc_vector[j].version);
}
@@ -258,8 +263,8 @@ TEST(SpdyAltSvcWireFormatTest, ParseHeaderFieldValueMultiple) {
roundtrip_altsvc_vector[j].host);
EXPECT_EQ(expected_altsvc_vector[j].port,
roundtrip_altsvc_vector[j].port);
- EXPECT_EQ(expected_altsvc_vector[j].max_age,
- roundtrip_altsvc_vector[j].max_age);
+ EXPECT_EQ(expected_altsvc_vector[j].max_age_seconds,
+ roundtrip_altsvc_vector[j].max_age_seconds);
EXPECT_EQ(expected_altsvc_vector[j].version,
roundtrip_altsvc_vector[j].version);
}
@@ -290,7 +295,7 @@ TEST(SpdyAltSvcWireFormatTest, RoundTrip) {
EXPECT_EQ(altsvc.protocol_id, parsed_altsvc_vector[0].protocol_id);
EXPECT_EQ(altsvc.host, parsed_altsvc_vector[0].host);
EXPECT_EQ(altsvc.port, parsed_altsvc_vector[0].port);
- EXPECT_EQ(altsvc.max_age, parsed_altsvc_vector[0].max_age);
+ EXPECT_EQ(altsvc.max_age_seconds, parsed_altsvc_vector[0].max_age_seconds);
EXPECT_EQ(altsvc.version, parsed_altsvc_vector[0].version);
// Test SerializeHeaderFieldValue().
@@ -325,7 +330,7 @@ TEST(SpdyAltSvcWireFormatTest, RoundTripMultiple) {
EXPECT_EQ(expected_it->protocol_id, parsed_it->protocol_id);
EXPECT_EQ(expected_it->host, parsed_it->host);
EXPECT_EQ(expected_it->port, parsed_it->port);
- EXPECT_EQ(expected_it->max_age, parsed_it->max_age);
+ EXPECT_EQ(expected_it->max_age_seconds, parsed_it->max_age_seconds);
EXPECT_EQ(expected_it->version, parsed_it->version);
}
@@ -566,7 +571,7 @@ TEST(SpdyAltSvcWireFormatTest, ParseIPLiteral) {
EXPECT_EQ("quic", altsvc_vector[0].protocol_id);
EXPECT_EQ("[2003:8:0:16::509d:9615]", altsvc_vector[0].host);
EXPECT_EQ(443u, altsvc_vector[0].port);
- EXPECT_EQ(60u, altsvc_vector[0].max_age);
+ EXPECT_EQ(60u, altsvc_vector[0].max_age_seconds);
EXPECT_THAT(altsvc_vector[0].version, ::testing::ElementsAre(36, 35));
}
diff --git a/chromium/net/third_party/quiche/src/spdy/core/spdy_framer.cc b/chromium/net/third_party/quiche/src/spdy/core/spdy_framer.cc
index 1b6eb8a6a9f..d1d0102b364 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/spdy_framer.cc
+++ b/chromium/net/third_party/quiche/src/spdy/core/spdy_framer.cc
@@ -301,8 +301,8 @@ size_t SpdyFramer::SpdyFrameIterator::NextFrame(ZeroCopyOutputBuffer* output) {
const size_t size_without_block =
is_first_frame_ ? GetFrameSizeSansBlock() : kContinuationFrameMinimumSize;
- std::string encoding;
- encoder_->Next(kHttp2MaxControlFrameSendSize - size_without_block, &encoding);
+ std::string encoding =
+ encoder_->Next(kHttp2MaxControlFrameSendSize - size_without_block);
has_next_frame_ = encoder_->HasNext();
if (framer_->debug_visitor_ != nullptr) {
@@ -577,7 +577,8 @@ void SpdyFramer::SerializeHeadersBuilderHelper(const SpdyHeadersIR& headers,
*size = *size + 5;
}
- GetHpackEncoder()->EncodeHeaderSet(headers.header_block(), hpack_encoding);
+ *hpack_encoding =
+ GetHpackEncoder()->EncodeHeaderBlock(headers.header_block());
*size = *size + hpack_encoding->size();
if (*size > kHttp2MaxControlFrameSendSize) {
*size = *size + GetNumberRequiredContinuationFrames(*size) *
@@ -670,8 +671,8 @@ void SpdyFramer::SerializePushPromiseBuilderHelper(
*size = *size + push_promise.padding_payload_len();
}
- GetHpackEncoder()->EncodeHeaderSet(push_promise.header_block(),
- hpack_encoding);
+ *hpack_encoding =
+ GetHpackEncoder()->EncodeHeaderBlock(push_promise.header_block());
*size = *size + hpack_encoding->size();
if (*size > kHttp2MaxControlFrameSendSize) {
*size = *size + GetNumberRequiredContinuationFrames(*size) *
diff --git a/chromium/net/third_party/quiche/src/spdy/core/spdy_framer_test.cc b/chromium/net/third_party/quiche/src/spdy/core/spdy_framer_test.cc
index 138c4873b79..058c26fa246 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/spdy_framer_test.cc
+++ b/chromium/net/third_party/quiche/src/spdy/core/spdy_framer_test.cc
@@ -1112,10 +1112,9 @@ TEST_P(SpdyFramerTest, MultiValueHeader) {
// TODO(jgraettinger): If this pattern appears again, move to test class.
Http2HeaderBlock header_set;
header_set["name"] = value;
- std::string buffer;
HpackEncoder encoder;
encoder.DisableCompression();
- encoder.EncodeHeaderSet(header_set, &buffer);
+ std::string buffer = encoder.EncodeHeaderBlock(header_set);
// Frame builder with plentiful buffer size.
SpdyFrameBuilder frame(1024);
frame.BeginNewFrame(SpdyFrameType::HEADERS,
@@ -2401,10 +2400,9 @@ TEST_P(SpdyFramerTest, CreateContinuationUncompressed) {
Http2HeaderBlock header_block;
header_block["bar"] = "foo";
header_block["foo"] = "bar";
- std::string buffer;
HpackEncoder encoder;
encoder.DisableCompression();
- encoder.EncodeHeaderSet(header_block, &buffer);
+ std::string buffer = encoder.EncodeHeaderBlock(header_block);
SpdyContinuationIR continuation(/* stream_id = */ 42);
continuation.take_encoding(std::move(buffer));