summaryrefslogtreecommitdiff
path: root/chromium/net/third_party
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2020-01-20 13:40:20 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2020-01-22 12:41:23 +0000
commit7961cea6d1041e3e454dae6a1da660b453efd238 (patch)
treec0eeb4a9ff9ba32986289c1653d9608e53ccb444 /chromium/net/third_party
parentb7034d0803538058e5c9d904ef03cf5eab34f6ef (diff)
downloadqtwebengine-chromium-7961cea6d1041e3e454dae6a1da660b453efd238.tar.gz
BASELINE: Update Chromium to 78.0.3904.130
Change-Id: If185e0c0061b3437531c97c9c8c78f239352a68b Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/net/third_party')
-rw-r--r--chromium/net/third_party/quiche/src/http2/decoder/decode_http2_structures_test.cc7
-rw-r--r--chromium/net/third_party/quiche/src/http2/decoder/http2_frame_decoder_test.cc8
-rw-r--r--chromium/net/third_party/quiche/src/http2/decoder/http2_structure_decoder_test.cc4
-rw-r--r--chromium/net/third_party/quiche/src/http2/decoder/payload_decoders/altsvc_payload_decoder_test.cc7
-rw-r--r--chromium/net/third_party/quiche/src/http2/decoder/payload_decoders/continuation_payload_decoder_test.cc4
-rw-r--r--chromium/net/third_party/quiche/src/http2/decoder/payload_decoders/data_payload_decoder_test.cc5
-rw-r--r--chromium/net/third_party/quiche/src/http2/decoder/payload_decoders/goaway_payload_decoder_test.cc5
-rw-r--r--chromium/net/third_party/quiche/src/http2/decoder/payload_decoders/headers_payload_decoder_test.cc5
-rw-r--r--chromium/net/third_party/quiche/src/http2/decoder/payload_decoders/payload_decoder_base_test_util.h5
-rw-r--r--chromium/net/third_party/quiche/src/http2/decoder/payload_decoders/push_promise_payload_decoder_test.cc5
-rw-r--r--chromium/net/third_party/quiche/src/http2/decoder/payload_decoders/unknown_payload_decoder_test.cc4
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_block_collector.cc6
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_block_collector.h8
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_block_decoder.cc2
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_block_decoder.h5
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_block_decoder_test.cc9
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_string_buffer.cc7
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_string_buffer.h6
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_string_buffer_test.cc19
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_tables_test.cc18
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_test.cc16
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_entry_collector.cc10
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_entry_collector.h10
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_entry_decoder.cc2
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_entry_decoder.h5
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_entry_decoder_test.cc6
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_entry_type_decoder.cc2
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_entry_type_decoder.h4
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_string_collector.cc4
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_string_collector.h8
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_string_decoder.cc4
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_string_decoder.h6
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_string_decoder_test.cc8
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/hpack_string.cc6
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/hpack_string.h10
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/hpack_string_test.cc8
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/http2_hpack_constants.cc2
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/http2_hpack_constants.h4
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_decoder.cc6
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_decoder.h8
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_decoder_test.cc24
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_encoder.cc2
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_encoder.h4
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_encoder_test.cc28
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_transcoder_test.cc23
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/tools/hpack_block_builder.h6
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/tools/hpack_block_builder_test.cc4
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/tools/hpack_example.cc6
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/tools/hpack_example.h5
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/varint/hpack_varint_decoder.cc2
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/varint/hpack_varint_decoder.h4
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/varint/hpack_varint_decoder_test.cc4
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/varint/hpack_varint_encoder.cc2
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/varint/hpack_varint_encoder.h4
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/varint/hpack_varint_encoder_test.cc10
-rw-r--r--chromium/net/third_party/quiche/src/http2/hpack/varint/hpack_varint_round_trip_test.cc6
-rw-r--r--chromium/net/third_party/quiche/src/http2/http2_constants.cc20
-rw-r--r--chromium/net/third_party/quiche/src/http2/http2_constants.h22
-rw-r--r--chromium/net/third_party/quiche/src/http2/http2_structures.cc6
-rw-r--r--chromium/net/third_party/quiche/src/http2/http2_structures.h8
-rw-r--r--chromium/net/third_party/quiche/src/http2/http2_structures_test.cc11
-rw-r--r--chromium/net/third_party/quiche/src/http2/http2_structures_test_util.h5
-rw-r--r--chromium/net/third_party/quiche/src/http2/platform/api/http2_string.h16
-rw-r--r--chromium/net/third_party/quiche/src/http2/platform/api/http2_string_utils.h18
-rw-r--r--chromium/net/third_party/quiche/src/http2/platform/api/http2_string_utils_test.cc10
-rw-r--r--chromium/net/third_party/quiche/src/http2/test_tools/frame_parts.cc2
-rw-r--r--chromium/net/third_party/quiche/src/http2/test_tools/frame_parts.h12
-rw-r--r--chromium/net/third_party/quiche/src/http2/test_tools/http2_random.cc12
-rw-r--r--chromium/net/third_party/quiche/src/http2/test_tools/http2_random.h8
-rw-r--r--chromium/net/third_party/quiche/src/http2/test_tools/http2_random_test.cc6
-rw-r--r--chromium/net/third_party/quiche/src/http2/tools/http2_frame_builder.h6
-rw-r--r--chromium/net/third_party/quiche/src/http2/tools/random_decoder_test.h1
-rw-r--r--chromium/net/third_party/quiche/src/http2/tools/random_util.cc6
-rw-r--r--chromium/net/third_party/quiche/src/http2/tools/random_util.h9
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/chlo_extractor.cc10
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.cc83
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.h71
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler_test.cc4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.cc38
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.h50
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_sender.cc5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_sender.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_simulator_test.cc4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.cc34
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.cc6
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm_test.cc5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/rtt_stats.h6
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/rtt_stats_test.cc44
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm_test.cc12
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.cc1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h19
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/crypto_secret_boxer.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/crypto_server_test.cc12
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.cc28
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h17
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/tls_connection.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.cc36
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.h6
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters_test.cc57
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_connection_close_frame.cc47
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_connection_close_frame.h17
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/frames/quic_frames_test.cc25
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/end_to_end_test.cc783
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/http_constants.h25
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/http_decoder.cc151
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/http_decoder.h45
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/http_decoder_test.cc265
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_headers_stream_test.cc51
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream.cc49
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream.h5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream_test.cc68
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.cc27
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.h20
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream_test.cc82
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base_test.cc32
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.cc23
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.h5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_test.cc127
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.cc475
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.h119
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session_test.cc531
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.cc250
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.h37
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_buffer.cc132
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_buffer.h78
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_buffer_test.cc163
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_manager.cc139
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_manager.h94
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_manager_test.cc282
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_test.cc342
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/offline/qpack_offline_decoder.cc12
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/offline/qpack_offline_decoder.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.cc144
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.h100
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager_test.cc293
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator_test.cc30
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder.cc52
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h39
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender.cc6
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender.h10
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender_test.cc4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test.cc83
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.cc7
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.cc327
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h82
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.cc6
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.h10
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender_test.cc4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test.cc325
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.cc48
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.h22
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table_test.cc89
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_index_conversions.cc62
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_index_conversions.h59
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_index_conversions_test.cc99
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.cc52
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.h31
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_receive_stream.cc17
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_receive_stream.h13
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_receive_stream_test.cc19
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_round_trip_test.cc15
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_send_stream.cc6
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_send_stream.h4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_send_stream_test.cc11
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_buffered_packet_store_test.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_config.cc69
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_config.h27
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_config_test.cc18
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_connection.cc367
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_connection.h55
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_connection_id.cc82
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_connection_id.h27
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_connection_id_test.cc6
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.h1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_connection_test.cc735
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_constants.h8
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager.cc37
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager.h3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager_test.cc22
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.cc9
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.h1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.cc5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_handshaker.cc4
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_handshaker.h1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_handshaker.cc5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_handshaker.h1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.cc5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h11
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_test.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.cc60
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.h10
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream_test.cc62
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_data_reader.cc20
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_data_reader.h8
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_data_writer_test.cc48
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.cc142
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.h15
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_dispatcher_test.cc392
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_error_codes.cc1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_error_codes.h5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_framer.cc933
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_framer.h105
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_framer_test.cc3588
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_ietf_framer_test.cc6
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.cc37
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.h1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_packet_creator_test.cc14
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_packet_generator.cc5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_packet_generator.h1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_packet_generator_test.cc112
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_packets.cc37
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_packets.h14
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_packets_test.cc41
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_received_packet_manager.cc9
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_received_packet_manager.h11
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_received_packet_manager_test.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.cc199
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h90
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager_test.cc232
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_session.cc182
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_session.h126
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_session_test.cc166
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_stream.cc32
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_stream.h12
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager.cc103
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager.h50
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager_test.cc135
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer.cc24
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer.h10
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_buffer.cc22
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_buffer.h14
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_buffer_test.cc118
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_test.cc11
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_stream_test.cc6
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.cc13
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.h1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager_test.cc53
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_types.cc428
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_types.h38
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_types_test.cc40
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map_test.cc10
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_utils.cc94
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_utils.h19
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_utils_test.cc45
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_version_manager.cc9
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_version_manager.h6
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_version_manager_test.cc29
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_versions.cc98
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_versions.h61
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_versions_test.cc119
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list.cc11
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list.h117
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list_test.cc261
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.cc123
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.h10
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_handshaker.cc5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_handshaker.h5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_handshaker_test.cc129
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.cc80
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.h6
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.cc33
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.h25
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager_test.cc32
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager.cc35
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager.h7
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager_test.cc29
-rw-r--r--chromium/net/third_party/quiche/src/quic/platform/api/quic_default_proof_providers.h11
-rw-r--r--chromium/net/third_party/quiche/src/quic/platform/api/quic_logging.h1
-rw-r--r--chromium/net/third_party/quiche/src/quic/platform/api/quic_mutex.h36
-rw-r--r--chromium/net/third_party/quiche/src/quic/platform/api/quic_pcc_sender.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/platform/api/quic_port_utils.h9
-rw-r--r--chromium/net/third_party/quiche/src/quic/platform/api/quic_text_utils.h5
-rw-r--r--chromium/net/third_party/quiche/src/quic/platform/api/quic_text_utils_test.cc5
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/bonnet/icmp_reachable.cc212
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/bonnet/icmp_reachable.h140
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/bonnet/icmp_reachable_interface.h28
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/bonnet/icmp_reachable_test.cc266
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/bonnet/mock_icmp_reachable.h20
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/bonnet/mock_tun_device.h26
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device.cc201
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device.h82
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_interface.h33
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger.cc82
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger.h72
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger_test.cc128
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_test.cc208
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/mock_qbone_client.h20
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/mock_qbone_server_session.h36
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/platform/icmp_packet.cc84
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/platform/icmp_packet.h29
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/platform/icmp_packet_test.cc127
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/platform/internet_checksum.cc32
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/platform/internet_checksum.h32
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/platform/internet_checksum_test.cc67
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/platform/ip_range.cc101
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/platform/ip_range.h60
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/platform/ip_range_test.cc65
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/platform/kernel_interface.h169
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/platform/mock_kernel.h46
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/platform/mock_netlink.h46
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/platform/netlink.cc828
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/platform/netlink.h142
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/platform/netlink_interface.h146
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/platform/netlink_test.cc763
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/platform/rtnetlink_message.cc177
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/platform/rtnetlink_message.h126
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/platform/rtnetlink_message_test.cc228
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/platform/tcp_packet.cc125
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/platform/tcp_packet.h25
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/platform/tcp_packet_test.cc116
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/qbone_client.cc98
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/qbone_client.h74
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/qbone_client_interface.h25
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/qbone_client_session.cc87
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/qbone_client_session.h76
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/qbone_client_test.cc259
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/qbone_constants.cc36
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/qbone_constants.h32
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/qbone_control.proto13
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/qbone_control_placeholder.proto20
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/qbone_control_stream.cc67
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/qbone_control_stream.h75
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_exchanger.cc70
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_exchanger.h80
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_exchanger_test.cc253
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_processor.cc269
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_processor.h198
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_processor_test.cc283
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_processor_test_tools.cc28
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_processor_test_tools.h37
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_writer.h24
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/qbone_server_session.cc94
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/qbone_server_session.h92
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/qbone_session_base.cc150
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/qbone_session_base.h93
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/qbone_session_test.cc520
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/qbone_stream.cc61
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/qbone_stream.h55
-rw-r--r--chromium/net/third_party/quiche/src/quic/qbone/qbone_stream_test.cc249
-rw-r--r--chromium/net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.cc8
-rw-r--r--chromium/net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.h4
-rw-r--r--chromium/net/third_party/quiche/src/quic/quartc/quartc_dispatcher.h3
-rw-r--r--chromium/net/third_party/quiche/src/quic/quartc/quartc_factory.cc12
-rw-r--r--chromium/net/third_party/quiche/src/quic/quartc/quartc_multiplexer.cc269
-rw-r--r--chromium/net/third_party/quiche/src/quic/quartc/quartc_multiplexer.h190
-rw-r--r--chromium/net/third_party/quiche/src/quic/quartc/quartc_multiplexer_test.cc490
-rw-r--r--chromium/net/third_party/quiche/src/quic/quartc/quartc_session.cc16
-rw-r--r--chromium/net/third_party/quiche/src/quic/quartc/quartc_stream.cc54
-rw-r--r--chromium/net/third_party/quiche/src/quic/quartc/quartc_stream_test.cc11
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/crypto_test_utils.cc15
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_session_visitor.h3
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_time_wait_list_manager.h3
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/packet_dropping_test_writer.h16
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/qpack_encoder_peer.cc30
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/qpack_encoder_peer.h30
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/qpack_header_table_peer.cc25
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/qpack_header_table_peer.h29
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.cc13
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/quic_crypto_server_config_peer.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/quic_framer_peer.h6
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.cc10
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/quic_spdy_session_peer.cc31
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/quic_spdy_session_peer.h10
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/quic_test_client.cc45
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/quic_test_client.h10
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/quic_test_server.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.cc15
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.h26
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/server_thread.h4
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/simple_quic_framer.cc4
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier.cc8
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier.h3
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier_test.cc9
-rw-r--r--chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.h6
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_client.cc26
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_client.h6
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_client_interop_test_bin.cc164
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_client_test.cc60
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.cc26
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.h6
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_packet_printer_bin.cc5
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_server.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_server_test.cc9
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_simple_crypto_server_stream_helper.cc12
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_simple_crypto_server_stream_helper.h9
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_simple_crypto_server_stream_helper_test.cc25
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session.cc30
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session.h9
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session_test.cc82
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream_test.cc16
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_spdy_client_base.cc3
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.cc31
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_toy_server.cc16
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/fifo_write_scheduler.h220
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/fifo_write_scheduler_test.cc85
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_decoder_adapter_test.cc62
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_encoder.cc8
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_encoder.h8
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_encoder_test.cc18
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_entry.cc2
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_entry.h8
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_entry_test.cc2
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_header_table_test.cc14
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_huffman_table.h1
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_huffman_table_test.cc41
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_output_stream.cc7
-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.cc50
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_round_trip_test.cc16
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/http2_frame_decoder_adapter.cc1
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/http2_frame_decoder_adapter.h5
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/http2_priority_write_scheduler.h41
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/http2_priority_write_scheduler_test.cc226
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/lifo_write_scheduler.h208
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/lifo_write_scheduler_test.cc156
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/priority_write_scheduler.h4
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/spdy_alt_svc_wire_format.cc20
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/spdy_alt_svc_wire_format.h16
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/spdy_alt_svc_wire_format_test.cc30
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/spdy_deframer_visitor.cc13
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/spdy_deframer_visitor.h5
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/spdy_framer.cc46
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/spdy_framer.h12
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/spdy_framer_test.cc47
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/spdy_header_block.cc8
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/spdy_header_block.h9
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/spdy_header_block_test.cc28
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/spdy_intrusive_list_test.cc98
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/spdy_pinnable_buffer_piece_test.cc9
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/spdy_prefixed_buffer_reader_test.cc9
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/spdy_protocol.cc26
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/spdy_protocol.h37
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/spdy_protocol_test.cc8
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/spdy_simple_arena_test.cc6
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/spdy_test_utils.cc12
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/spdy_test_utils.h12
-rw-r--r--chromium/net/third_party/quiche/src/spdy/core/write_scheduler.h4
-rw-r--r--chromium/net/third_party/quiche/src/spdy/platform/api/spdy_string.h16
-rw-r--r--chromium/net/third_party/quiche/src/spdy/platform/api/spdy_string_utils.h14
-rw-r--r--chromium/net/third_party/quiche/src/spdy/platform/api/spdy_string_utils_test.cc10
-rw-r--r--chromium/net/third_party/uri_template/uri_template_fuzzer.cc2
450 files changed, 23822 insertions, 6802 deletions
diff --git a/chromium/net/third_party/quiche/src/http2/decoder/decode_http2_structures_test.cc b/chromium/net/third_party/quiche/src/http2/decoder/decode_http2_structures_test.cc
index 91b3ef78bb9..48b79bd5582 100644
--- a/chromium/net/third_party/quiche/src/http2/decoder/decode_http2_structures_test.cc
+++ b/chromium/net/third_party/quiche/src/http2/decoder/decode_http2_structures_test.cc
@@ -9,13 +9,14 @@
#include <stddef.h>
+#include <string>
+
#include "testing/gtest/include/gtest/gtest.h"
#include "net/third_party/quiche/src/http2/decoder/decode_buffer.h"
#include "net/third_party/quiche/src/http2/decoder/decode_status.h"
#include "net/third_party/quiche/src/http2/http2_constants.h"
#include "net/third_party/quiche/src/http2/http2_structures_test_util.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_logging.h"
-#include "net/third_party/quiche/src/http2/platform/api/http2_string.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_string_piece.h"
#include "net/third_party/quiche/src/http2/test_tools/http2_random.h"
#include "net/third_party/quiche/src/http2/tools/http2_frame_builder.h"
@@ -32,7 +33,7 @@ Http2StringPiece ToStringPiece(T (&data)[N]) {
}
template <class S>
-Http2String SerializeStructure(const S& s) {
+std::string SerializeStructure(const S& s) {
Http2FrameBuilder fb;
fb.Append(s);
EXPECT_EQ(S::EncodedSize(), fb.size());
@@ -70,7 +71,7 @@ class StructureDecoderTest : public ::testing::Test {
// Encode the structure |in_s| into bytes, then decode the bytes
// and validate that the decoder produced the same field values.
void EncodeThenDecode(const S& in_s) {
- Http2String bytes = SerializeStructure(in_s);
+ std::string bytes = SerializeStructure(in_s);
EXPECT_EQ(S::EncodedSize(), bytes.size());
DecodeLeadingStructure(&in_s, bytes);
}
diff --git a/chromium/net/third_party/quiche/src/http2/decoder/http2_frame_decoder_test.cc b/chromium/net/third_party/quiche/src/http2/decoder/http2_frame_decoder_test.cc
index 50e75edf454..7ed67f39674 100644
--- a/chromium/net/third_party/quiche/src/http2/decoder/http2_frame_decoder_test.cc
+++ b/chromium/net/third_party/quiche/src/http2/decoder/http2_frame_decoder_test.cc
@@ -6,13 +6,13 @@
// Tests of Http2FrameDecoder.
+#include <string>
#include <vector>
#include "testing/gtest/include/gtest/gtest.h"
#include "net/third_party/quiche/src/http2/http2_constants.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_logging.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_reconstruct_object.h"
-#include "net/third_party/quiche/src/http2/platform/api/http2_string.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_string_piece.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_test_helpers.h"
#include "net/third_party/quiche/src/http2/test_tools/frame_parts.h"
@@ -84,7 +84,7 @@ class Http2FrameDecoderTest : public RandomDecoderTest {
// The decoder will discard the remaining bytes, but not go beyond that,
// which these conditions verify.
size_t extra = 10;
- Http2String junk(remaining + extra, '0');
+ std::string junk(remaining + extra, '0');
DecodeBuffer tmp(junk);
EXPECT_EQ(DecodeStatus::kDecodeDone, decoder_.DecodeFrame(&tmp));
EXPECT_EQ(remaining, tmp.Offset());
@@ -147,8 +147,8 @@ class Http2FrameDecoderTest : public RandomDecoderTest {
VERIFY_GT(slow_decode_count_, 0u);
// Repeat with more input; it should stop without reading that input.
- Http2String next_frame = Random().RandString(10);
- Http2String input(payload.data(), payload.size());
+ std::string next_frame = Random().RandString(10);
+ std::string input(payload.data(), payload.size());
input += next_frame;
ResetDecodeSpeedCounters();
diff --git a/chromium/net/third_party/quiche/src/http2/decoder/http2_structure_decoder_test.cc b/chromium/net/third_party/quiche/src/http2/decoder/http2_structure_decoder_test.cc
index 7b9afc59234..254510919d3 100644
--- a/chromium/net/third_party/quiche/src/http2/decoder/http2_structure_decoder_test.cc
+++ b/chromium/net/third_party/quiche/src/http2/decoder/http2_structure_decoder_test.cc
@@ -21,6 +21,7 @@
#include <stddef.h>
#include <cstdint>
+#include <string>
#include "testing/gtest/include/gtest/gtest.h"
#include "net/third_party/quiche/src/http2/decoder/decode_buffer.h"
@@ -29,7 +30,6 @@
#include "net/third_party/quiche/src/http2/http2_structures_test_util.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_logging.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_reconstruct_object.h"
-#include "net/third_party/quiche/src/http2/platform/api/http2_string.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_string_piece.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_test_helpers.h"
#include "net/third_party/quiche/src/http2/tools/http2_frame_builder.h"
@@ -159,7 +159,7 @@ class Http2StructureDecoderTest : public RandomDecoderTest {
// Encode the structure |in_s| into bytes, then decode the bytes
// and validate that the decoder produced the same field values.
AssertionResult EncodeThenDecode(const S& in_s) {
- Http2String bytes = SerializeStructure(in_s);
+ std::string bytes = SerializeStructure(in_s);
VERIFY_EQ(S::EncodedSize(), bytes.size());
VERIFY_AND_RETURN_SUCCESS(DecodeLeadingStructure(&in_s, bytes));
}
diff --git a/chromium/net/third_party/quiche/src/http2/decoder/payload_decoders/altsvc_payload_decoder_test.cc b/chromium/net/third_party/quiche/src/http2/decoder/payload_decoders/altsvc_payload_decoder_test.cc
index 6a4bee53b14..354fdae0621 100644
--- a/chromium/net/third_party/quiche/src/http2/decoder/payload_decoders/altsvc_payload_decoder_test.cc
+++ b/chromium/net/third_party/quiche/src/http2/decoder/payload_decoders/altsvc_payload_decoder_test.cc
@@ -6,13 +6,14 @@
#include <stddef.h>
+#include <string>
+
#include "testing/gtest/include/gtest/gtest.h"
#include "net/third_party/quiche/src/http2/decoder/http2_frame_decoder_listener.h"
#include "net/third_party/quiche/src/http2/decoder/payload_decoders/payload_decoder_base_test_util.h"
#include "net/third_party/quiche/src/http2/http2_constants.h"
#include "net/third_party/quiche/src/http2/http2_structures_test_util.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_logging.h"
-#include "net/third_party/quiche/src/http2/platform/api/http2_string.h"
#include "net/third_party/quiche/src/http2/test_tools/frame_parts.h"
#include "net/third_party/quiche/src/http2/test_tools/frame_parts_collector.h"
#include "net/third_party/quiche/src/http2/test_tools/http2_random.h"
@@ -103,8 +104,8 @@ INSTANTIATE_TEST_SUITE_P(VariousOriginAndValueLengths,
::testing::Values(0, 1, 3, 65537)));
TEST_P(AltSvcPayloadLengthTests, ValidOriginAndValueLength) {
- Http2String origin = Random().RandString(origin_length_);
- Http2String value = Random().RandString(value_length_);
+ std::string origin = Random().RandString(origin_length_);
+ std::string value = Random().RandString(value_length_);
Http2FrameBuilder fb;
fb.Append(Http2AltSvcFields{origin_length_});
fb.Append(origin);
diff --git a/chromium/net/third_party/quiche/src/http2/decoder/payload_decoders/continuation_payload_decoder_test.cc b/chromium/net/third_party/quiche/src/http2/decoder/payload_decoders/continuation_payload_decoder_test.cc
index 35479a15082..125e16fc7c9 100644
--- a/chromium/net/third_party/quiche/src/http2/decoder/payload_decoders/continuation_payload_decoder_test.cc
+++ b/chromium/net/third_party/quiche/src/http2/decoder/payload_decoders/continuation_payload_decoder_test.cc
@@ -6,6 +6,7 @@
#include <stddef.h>
+#include <string>
#include <type_traits>
#include "testing/gtest/include/gtest/gtest.h"
@@ -14,7 +15,6 @@
#include "net/third_party/quiche/src/http2/http2_constants.h"
#include "net/third_party/quiche/src/http2/http2_structures.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_logging.h"
-#include "net/third_party/quiche/src/http2/platform/api/http2_string.h"
#include "net/third_party/quiche/src/http2/test_tools/frame_parts.h"
#include "net/third_party/quiche/src/http2/test_tools/frame_parts_collector.h"
#include "net/third_party/quiche/src/http2/tools/random_decoder_test.h"
@@ -73,7 +73,7 @@ INSTANTIATE_TEST_SUITE_P(VariousLengths,
::testing::Values(0, 1, 2, 3, 4, 5, 6));
TEST_P(ContinuationPayloadDecoderTest, ValidLength) {
- Http2String hpack_payload = Random().RandString(length_);
+ std::string hpack_payload = Random().RandString(length_);
Http2FrameHeader frame_header(length_, Http2FrameType::CONTINUATION,
RandFlags(), RandStreamId());
set_frame_header(frame_header);
diff --git a/chromium/net/third_party/quiche/src/http2/decoder/payload_decoders/data_payload_decoder_test.cc b/chromium/net/third_party/quiche/src/http2/decoder/payload_decoders/data_payload_decoder_test.cc
index 1cae7141ef5..f1dc017c9da 100644
--- a/chromium/net/third_party/quiche/src/http2/decoder/payload_decoders/data_payload_decoder_test.cc
+++ b/chromium/net/third_party/quiche/src/http2/decoder/payload_decoders/data_payload_decoder_test.cc
@@ -6,6 +6,8 @@
#include <stddef.h>
+#include <string>
+
#include "testing/gtest/include/gtest/gtest.h"
#include "net/third_party/quiche/src/http2/decoder/http2_frame_decoder_listener.h"
#include "net/third_party/quiche/src/http2/decoder/payload_decoders/payload_decoder_base_test_util.h"
@@ -13,7 +15,6 @@
#include "net/third_party/quiche/src/http2/http2_structures.h"
#include "net/third_party/quiche/src/http2/http2_structures_test_util.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_logging.h"
-#include "net/third_party/quiche/src/http2/platform/api/http2_string.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_test_helpers.h"
#include "net/third_party/quiche/src/http2/test_tools/frame_parts.h"
#include "net/third_party/quiche/src/http2/test_tools/frame_parts_collector.h"
@@ -84,7 +85,7 @@ class DataPayloadDecoderTest
Reset();
uint8_t flags = RandFlags();
- Http2String data_payload = Random().RandString(data_size);
+ std::string data_payload = Random().RandString(data_size);
frame_builder_.Append(data_payload);
MaybeAppendTrailingPadding();
diff --git a/chromium/net/third_party/quiche/src/http2/decoder/payload_decoders/goaway_payload_decoder_test.cc b/chromium/net/third_party/quiche/src/http2/decoder/payload_decoders/goaway_payload_decoder_test.cc
index 5ea533a4703..b2d96fb2d71 100644
--- a/chromium/net/third_party/quiche/src/http2/decoder/payload_decoders/goaway_payload_decoder_test.cc
+++ b/chromium/net/third_party/quiche/src/http2/decoder/payload_decoders/goaway_payload_decoder_test.cc
@@ -6,13 +6,14 @@
#include <stddef.h>
+#include <string>
+
#include "testing/gtest/include/gtest/gtest.h"
#include "net/third_party/quiche/src/http2/decoder/http2_frame_decoder_listener.h"
#include "net/third_party/quiche/src/http2/decoder/payload_decoders/payload_decoder_base_test_util.h"
#include "net/third_party/quiche/src/http2/http2_constants.h"
#include "net/third_party/quiche/src/http2/http2_structures_test_util.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_logging.h"
-#include "net/third_party/quiche/src/http2/platform/api/http2_string.h"
#include "net/third_party/quiche/src/http2/test_tools/frame_parts.h"
#include "net/third_party/quiche/src/http2/test_tools/frame_parts_collector.h"
#include "net/third_party/quiche/src/http2/test_tools/http2_random.h"
@@ -92,7 +93,7 @@ INSTANTIATE_TEST_SUITE_P(VariousLengths,
TEST_P(GoAwayOpaqueDataLengthTests, ValidLength) {
Http2GoAwayFields goaway;
Randomize(&goaway, RandomPtr());
- Http2String opaque_data = Random().RandString(length_);
+ std::string opaque_data = Random().RandString(length_);
Http2FrameBuilder fb;
fb.Append(goaway);
fb.Append(opaque_data);
diff --git a/chromium/net/third_party/quiche/src/http2/decoder/payload_decoders/headers_payload_decoder_test.cc b/chromium/net/third_party/quiche/src/http2/decoder/payload_decoders/headers_payload_decoder_test.cc
index a7a90bfd21f..4e0f2e307bb 100644
--- a/chromium/net/third_party/quiche/src/http2/decoder/payload_decoders/headers_payload_decoder_test.cc
+++ b/chromium/net/third_party/quiche/src/http2/decoder/payload_decoders/headers_payload_decoder_test.cc
@@ -6,13 +6,14 @@
#include <stddef.h>
+#include <string>
+
#include "testing/gtest/include/gtest/gtest.h"
#include "net/third_party/quiche/src/http2/decoder/http2_frame_decoder_listener.h"
#include "net/third_party/quiche/src/http2/decoder/payload_decoders/payload_decoder_base_test_util.h"
#include "net/third_party/quiche/src/http2/http2_constants.h"
#include "net/third_party/quiche/src/http2/http2_structures_test_util.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_logging.h"
-#include "net/third_party/quiche/src/http2/platform/api/http2_string.h"
#include "net/third_party/quiche/src/http2/test_tools/frame_parts.h"
#include "net/third_party/quiche/src/http2/test_tools/frame_parts_collector.h"
#include "net/third_party/quiche/src/http2/test_tools/http2_random.h"
@@ -116,7 +117,7 @@ TEST_P(HeadersPayloadDecoderTest, VariousHpackPayloadSizes) {
frame_builder_.Append(priority);
}
- Http2String hpack_payload = Random().RandString(hpack_size);
+ std::string hpack_payload = Random().RandString(hpack_size);
frame_builder_.Append(hpack_payload);
MaybeAppendTrailingPadding();
diff --git a/chromium/net/third_party/quiche/src/http2/decoder/payload_decoders/payload_decoder_base_test_util.h b/chromium/net/third_party/quiche/src/http2/decoder/payload_decoders/payload_decoder_base_test_util.h
index 66dd88a48c0..5de0d1b88c1 100644
--- a/chromium/net/third_party/quiche/src/http2/decoder/payload_decoders/payload_decoder_base_test_util.h
+++ b/chromium/net/third_party/quiche/src/http2/decoder/payload_decoders/payload_decoder_base_test_util.h
@@ -9,6 +9,8 @@
#include <stddef.h>
+#include <string>
+
#include "testing/gtest/include/gtest/gtest.h"
#include "net/third_party/quiche/src/http2/decoder/decode_buffer.h"
#include "net/third_party/quiche/src/http2/decoder/decode_status.h"
@@ -19,7 +21,6 @@
#include "net/third_party/quiche/src/http2/http2_structures.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_logging.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_reconstruct_object.h"
-#include "net/third_party/quiche/src/http2/platform/api/http2_string.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_string_piece.h"
#include "net/third_party/quiche/src/http2/test_tools/frame_parts.h"
#include "net/third_party/quiche/src/http2/tools/http2_frame_builder.h"
@@ -429,7 +430,7 @@ class AbstractPaddablePayloadDecoderTest
}
HTTP2_VLOG(1) << "payload_length=" << payload_length;
- Http2String payload = fb.buffer().substr(0, payload_length);
+ std::string payload = fb.buffer().substr(0, payload_length);
// The missing length is the amount we cut off the end, unless
// payload_length is zero, in which case the decoder knows only that 1
diff --git a/chromium/net/third_party/quiche/src/http2/decoder/payload_decoders/push_promise_payload_decoder_test.cc b/chromium/net/third_party/quiche/src/http2/decoder/payload_decoders/push_promise_payload_decoder_test.cc
index 64dd935b44e..0561aa4b96b 100644
--- a/chromium/net/third_party/quiche/src/http2/decoder/payload_decoders/push_promise_payload_decoder_test.cc
+++ b/chromium/net/third_party/quiche/src/http2/decoder/payload_decoders/push_promise_payload_decoder_test.cc
@@ -6,13 +6,14 @@
#include <stddef.h>
+#include <string>
+
#include "testing/gtest/include/gtest/gtest.h"
#include "net/third_party/quiche/src/http2/decoder/http2_frame_decoder_listener.h"
#include "net/third_party/quiche/src/http2/decoder/payload_decoders/payload_decoder_base_test_util.h"
#include "net/third_party/quiche/src/http2/http2_constants.h"
#include "net/third_party/quiche/src/http2/http2_structures_test_util.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_logging.h"
-#include "net/third_party/quiche/src/http2/platform/api/http2_string.h"
#include "net/third_party/quiche/src/http2/test_tools/frame_parts.h"
#include "net/third_party/quiche/src/http2/test_tools/frame_parts_collector.h"
#include "net/third_party/quiche/src/http2/test_tools/http2_random.h"
@@ -98,7 +99,7 @@ TEST_P(PushPromisePayloadDecoderTest, VariousHpackPayloadSizes) {
HTTP2_LOG(INFO) << "########### hpack_size = " << hpack_size
<< " ###########";
Reset();
- Http2String hpack_payload = Random().RandString(hpack_size);
+ std::string hpack_payload = Random().RandString(hpack_size);
Http2PushPromiseFields push_promise{RandStreamId()};
frame_builder_.Append(push_promise);
frame_builder_.Append(hpack_payload);
diff --git a/chromium/net/third_party/quiche/src/http2/decoder/payload_decoders/unknown_payload_decoder_test.cc b/chromium/net/third_party/quiche/src/http2/decoder/payload_decoders/unknown_payload_decoder_test.cc
index 018bd82e046..10759329c0f 100644
--- a/chromium/net/third_party/quiche/src/http2/decoder/payload_decoders/unknown_payload_decoder_test.cc
+++ b/chromium/net/third_party/quiche/src/http2/decoder/payload_decoders/unknown_payload_decoder_test.cc
@@ -6,6 +6,7 @@
#include <stddef.h>
+#include <string>
#include <type_traits>
#include "testing/gtest/include/gtest/gtest.h"
@@ -14,7 +15,6 @@
#include "net/third_party/quiche/src/http2/http2_constants.h"
#include "net/third_party/quiche/src/http2/http2_structures.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_logging.h"
-#include "net/third_party/quiche/src/http2/platform/api/http2_string.h"
#include "net/third_party/quiche/src/http2/test_tools/frame_parts.h"
#include "net/third_party/quiche/src/http2/test_tools/frame_parts_collector.h"
#include "net/third_party/quiche/src/http2/test_tools/http2_random.h"
@@ -83,7 +83,7 @@ INSTANTIATE_TEST_SUITE_P(VariousLengths,
::testing::Values(0, 1, 2, 3, 255, 256));
TEST_P(UnknownPayloadDecoderTest, ValidLength) {
- Http2String unknown_payload = Random().RandString(length_);
+ std::string unknown_payload = Random().RandString(length_);
Http2FrameHeader frame_header(length_, g_unknown_frame_type, Random().Rand8(),
RandStreamId());
set_frame_header(frame_header);
diff --git a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_block_collector.cc b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_block_collector.cc
index 1137be53d85..3490ca7d740 100644
--- a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_block_collector.cc
+++ b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_block_collector.cc
@@ -77,14 +77,14 @@ void HpackBlockCollector::ExpectNameIndexAndLiteralValue(
HpackEntryType type,
size_t index,
bool value_huffman,
- const Http2String& value) {
+ const std::string& value) {
entries_.push_back(HpackEntryCollector(type, index, value_huffman, value));
}
void HpackBlockCollector::ExpectLiteralNameAndValue(HpackEntryType type,
bool name_huffman,
- const Http2String& name,
+ const std::string& name,
bool value_huffman,
- const Http2String& value) {
+ const std::string& value) {
entries_.push_back(
HpackEntryCollector(type, name_huffman, name, value_huffman, value));
}
diff --git a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_block_collector.h b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_block_collector.h
index 6ad14057c24..0d8f8113d70 100644
--- a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_block_collector.h
+++ b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_block_collector.h
@@ -15,6 +15,7 @@
#include <stddef.h>
+#include <string>
#include <vector>
#include "testing/gtest/include/gtest/gtest.h"
@@ -22,7 +23,6 @@
#include "net/third_party/quiche/src/http2/hpack/decoder/hpack_entry_decoder_listener.h"
#include "net/third_party/quiche/src/http2/hpack/http2_hpack_constants.h"
#include "net/third_party/quiche/src/http2/hpack/tools/hpack_block_builder.h"
-#include "net/third_party/quiche/src/http2/platform/api/http2_string.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_string_piece.h"
#include "net/third_party/quiche/src/http2/test_tools/http2_random.h"
@@ -66,14 +66,14 @@ class HpackBlockCollector : public HpackEntryDecoderListener {
void ExpectNameIndexAndLiteralValue(HpackEntryType type,
size_t index,
bool value_huffman,
- const Http2String& value);
+ const std::string& value);
// Add an HPACK entry for a header entry with a literal name and value.
void ExpectLiteralNameAndValue(HpackEntryType type,
bool name_huffman,
- const Http2String& name,
+ const std::string& name,
bool value_huffman,
- const Http2String& value);
+ const std::string& value);
// Shuffle the entries, in support of generating an HPACK block of entries
// in some random order.
diff --git a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_block_decoder.cc b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_block_decoder.cc
index 656f8e9866e..bb86597e812 100644
--- a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_block_decoder.cc
+++ b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_block_decoder.cc
@@ -48,7 +48,7 @@ DecodeStatus HpackBlockDecoder::Decode(DecodeBuffer* db) {
return DecodeStatus::kDecodeDone;
}
-Http2String HpackBlockDecoder::DebugString() const {
+std::string HpackBlockDecoder::DebugString() const {
return Http2StrCat("HpackBlockDecoder(", entry_decoder_.DebugString(),
", listener@",
Http2Hex(reinterpret_cast<intptr_t>(listener_)),
diff --git a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_block_decoder.h b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_block_decoder.h
index a17664f8ded..fb44c3f1617 100644
--- a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_block_decoder.h
+++ b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_block_decoder.h
@@ -10,13 +10,14 @@
// or dynamic table support, so table indices remain indices at this level.
// Reports the entries to an HpackEntryDecoderListener.
+#include <string>
+
#include "net/third_party/quiche/src/http2/decoder/decode_buffer.h"
#include "net/third_party/quiche/src/http2/decoder/decode_status.h"
#include "net/third_party/quiche/src/http2/hpack/decoder/hpack_entry_decoder.h"
#include "net/third_party/quiche/src/http2/hpack/decoder/hpack_entry_decoder_listener.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_export.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_logging.h"
-#include "net/third_party/quiche/src/http2/platform/api/http2_string.h"
namespace http2 {
@@ -48,7 +49,7 @@ class HTTP2_EXPORT_PRIVATE HpackBlockDecoder {
// first byte of a new HPACK entry)?
bool before_entry() const { return before_entry_; }
- Http2String DebugString() const;
+ std::string DebugString() const;
private:
HpackEntryDecoder entry_decoder_;
diff --git a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_block_decoder_test.cc b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_block_decoder_test.cc
index fce45b2a316..4988b5cde37 100644
--- a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_block_decoder_test.cc
+++ b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_block_decoder_test.cc
@@ -7,6 +7,7 @@
// Tests of HpackBlockDecoder.
#include <cstdint>
+#include <string>
#include "testing/gtest/include/gtest/gtest.h"
#include "net/third_party/quiche/src/http2/decoder/decode_buffer.h"
@@ -67,14 +68,14 @@ class HpackBlockDecoderTest : public RandomDecoderTest {
AssertionResult DecodeHpackExampleAndValidateSeveralWays(
Http2StringPiece hpack_example,
Validator validator) {
- Http2String input = HpackExampleToStringOrDie(hpack_example);
+ std::string input = HpackExampleToStringOrDie(hpack_example);
DecodeBuffer db(input);
return DecodeAndValidateSeveralWays(&db, validator);
}
uint8_t Rand8() { return Random().Rand8(); }
- Http2String Rand8String() { return Random().RandString(Rand8()); }
+ std::string Rand8String() { return Random().RandString(Rand8()); }
HpackBlockCollector collector_;
HpackEntryDecoderVLoggingListener listener_;
@@ -157,7 +158,7 @@ TEST_F(HpackBlockDecoderTest, SpecExample_C_2_4) {
}
// http://httpwg.org/specs/rfc7541.html#rfc.section.C.3.1
TEST_F(HpackBlockDecoderTest, SpecExample_C_3_1) {
- Http2String example = R"(
+ std::string example = R"(
82 | == Indexed - Add ==
| idx = 2
| -> :method: GET
@@ -191,7 +192,7 @@ TEST_F(HpackBlockDecoderTest, SpecExample_C_3_1) {
// http://httpwg.org/specs/rfc7541.html#rfc.section.C.5.1
TEST_F(HpackBlockDecoderTest, SpecExample_C_5_1) {
- Http2String example = R"(
+ std::string example = R"(
48 | == Literal indexed ==
| Indexed name (idx = 8)
| :status
diff --git a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_string_buffer.cc b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_string_buffer.cc
index 76431a6ffd0..6a200085cb7 100644
--- a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_string_buffer.cc
+++ b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_string_buffer.cc
@@ -9,7 +9,6 @@
#include "net/third_party/quiche/src/http2/platform/api/http2_bug_tracker.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_estimate_memory_usage.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_logging.h"
-#include "net/third_party/quiche/src/http2/platform/api/http2_string.h"
namespace http2 {
@@ -168,7 +167,7 @@ void HpackDecoderStringBuffer::BufferStringIfUnbuffered() {
<< state_ << ", backing=" << backing_;
if (state_ != State::RESET && backing_ == Backing::UNBUFFERED) {
HTTP2_DVLOG(2)
- << "HpackDecoderStringBuffer buffering Http2String of length "
+ << "HpackDecoderStringBuffer buffering std::string of length "
<< value_.size();
buffer_.assign(value_.data(), value_.size());
if (state_ == State::COMPLETE) {
@@ -194,7 +193,7 @@ Http2StringPiece HpackDecoderStringBuffer::str() const {
return value_;
}
-Http2String HpackDecoderStringBuffer::ReleaseString() {
+std::string HpackDecoderStringBuffer::ReleaseString() {
HTTP2_DVLOG(3) << "HpackDecoderStringBuffer::ReleaseString";
DCHECK_EQ(state_, State::COMPLETE);
DCHECK_EQ(backing_, Backing::BUFFERED);
@@ -203,7 +202,7 @@ Http2String HpackDecoderStringBuffer::ReleaseString() {
if (backing_ == Backing::BUFFERED) {
return std::move(buffer_);
} else {
- return Http2String(value_);
+ return std::string(value_);
}
}
return "";
diff --git a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_string_buffer.h b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_string_buffer.h
index 8a810b2d9d3..d8dce6c150d 100644
--- a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_string_buffer.h
+++ b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_string_buffer.h
@@ -12,10 +12,10 @@
#include <stddef.h>
#include <ostream>
+#include <string>
#include "net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_decoder.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_export.h"
-#include "net/third_party/quiche/src/http2/platform/api/http2_string.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_string_piece.h"
namespace http2 {
@@ -58,7 +58,7 @@ class HTTP2_EXPORT_PRIVATE HpackDecoderStringBuffer {
// unless the string has been buffered (to avoid forcing a potentially
// unnecessary copy). ReleaseString() also resets the instance so that it can
// be used to collect another string.
- Http2String ReleaseString();
+ std::string ReleaseString();
State state_for_testing() const { return state_; }
Backing backing_for_testing() const { return backing_; }
@@ -70,7 +70,7 @@ class HTTP2_EXPORT_PRIVATE HpackDecoderStringBuffer {
private:
// Storage for the string being buffered, if buffering is necessary
// (e.g. if Huffman encoded, buffer_ is storage for the decoded string).
- Http2String buffer_;
+ std::string buffer_;
// The Http2StringPiece to be returned by HpackDecoderStringBuffer::str(). If
// a string has been collected, but not buffered, value_ points to that
diff --git a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_string_buffer_test.cc b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_string_buffer_test.cc
index 11b0d9773bb..ec807c84b66 100644
--- a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_string_buffer_test.cc
+++ b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_string_buffer_test.cc
@@ -11,7 +11,6 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_logging.h"
-#include "net/third_party/quiche/src/http2/platform/api/http2_string.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_string_utils.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_test_helpers.h"
@@ -33,11 +32,11 @@ class HpackDecoderStringBufferTest : public ::testing::Test {
// We want to know that HTTP2_LOG(x) << buf_ will work in production should
// that be needed, so we test that it outputs the expected values.
- AssertionResult VerifyLogHasSubstrs(std::initializer_list<Http2String> strs) {
+ AssertionResult VerifyLogHasSubstrs(std::initializer_list<std::string> strs) {
HTTP2_VLOG(1) << buf_;
std::ostringstream ss;
buf_.OutputDebugStringTo(ss);
- Http2String dbg_str(ss.str());
+ std::string dbg_str(ss.str());
for (const auto& expected : strs) {
VERIFY_THAT(dbg_str, HasSubstr(expected));
}
@@ -153,7 +152,7 @@ TEST_F(HpackDecoderStringBufferTest, PlainSplit) {
}
TEST_F(HpackDecoderStringBufferTest, HuffmanWhole) {
- Http2String encoded = Http2HexDecode("f1e3c2e5f23a6ba0ab90f4ff");
+ std::string encoded = Http2HexDecode("f1e3c2e5f23a6ba0ab90f4ff");
Http2StringPiece decoded("www.example.com");
EXPECT_EQ(state(), State::RESET);
@@ -172,15 +171,15 @@ TEST_F(HpackDecoderStringBufferTest, HuffmanWhole) {
EXPECT_TRUE(VerifyLogHasSubstrs(
{"{state=COMPLETE", "backing=BUFFERED", "buffer: www.example.com}"}));
- Http2String s = buf_.ReleaseString();
+ std::string s = buf_.ReleaseString();
EXPECT_EQ(s, decoded);
EXPECT_EQ(state(), State::RESET);
}
TEST_F(HpackDecoderStringBufferTest, HuffmanSplit) {
- Http2String encoded = Http2HexDecode("f1e3c2e5f23a6ba0ab90f4ff");
- Http2String part1 = encoded.substr(0, 5);
- Http2String part2 = encoded.substr(5);
+ std::string encoded = Http2HexDecode("f1e3c2e5f23a6ba0ab90f4ff");
+ std::string part1 = encoded.substr(0, 5);
+ std::string part2 = encoded.substr(5);
Http2StringPiece decoded("www.example.com");
EXPECT_EQ(state(), State::RESET);
@@ -217,7 +216,7 @@ TEST_F(HpackDecoderStringBufferTest, HuffmanSplit) {
TEST_F(HpackDecoderStringBufferTest, InvalidHuffmanOnData) {
// Explicitly encode the End-of-String symbol, a no-no.
- Http2String encoded = Http2HexDecode("ffffffff");
+ std::string encoded = Http2HexDecode("ffffffff");
buf_.OnStart(/*huffman_encoded*/ true, encoded.size());
EXPECT_EQ(state(), State::COLLECTING);
@@ -231,7 +230,7 @@ TEST_F(HpackDecoderStringBufferTest, InvalidHuffmanOnData) {
TEST_F(HpackDecoderStringBufferTest, InvalidHuffmanOnEnd) {
// Last byte of string doesn't end with prefix of End-of-String symbol.
- Http2String encoded = Http2HexDecode("00");
+ std::string encoded = Http2HexDecode("00");
buf_.OnStart(/*huffman_encoded*/ true, encoded.size());
EXPECT_EQ(state(), State::COLLECTING);
diff --git a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_tables_test.cc b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_tables_test.cc
index 592ce563544..db4ada111fd 100644
--- a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_tables_test.cc
+++ b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_tables_test.cc
@@ -5,6 +5,7 @@
#include "net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_tables.h"
#include <algorithm>
+#include <string>
#include <tuple>
#include <vector>
@@ -12,7 +13,6 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "net/third_party/quiche/src/http2/hpack/http2_hpack_constants.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_logging.h"
-#include "net/third_party/quiche/src/http2/platform/api/http2_string.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_test_helpers.h"
#include "net/third_party/quiche/src/http2/test_tools/http2_random.h"
#include "net/third_party/quiche/src/http2/tools/random_util.h"
@@ -96,7 +96,7 @@ TEST_F(HpackDecoderStaticTableTest, StaticTableContents) {
EXPECT_TRUE(VerifyStaticTableContents());
}
-size_t Size(const Http2String& name, const Http2String& value) {
+size_t Size(const std::string& name, const std::string& value) {
return name.size() + value.size() + 32;
}
@@ -105,11 +105,11 @@ size_t Size(const Http2String& name, const Http2String& value) {
// dynamic table containing FakeHpackEntry instances. We can thus compare the
// contents of the actual table with those in fake_dynamic_table_.
-typedef std::tuple<Http2String, Http2String, size_t> FakeHpackEntry;
-const Http2String& Name(const FakeHpackEntry& entry) {
+typedef std::tuple<std::string, std::string, size_t> FakeHpackEntry;
+const std::string& Name(const FakeHpackEntry& entry) {
return std::get<0>(entry);
}
-const Http2String& Value(const FakeHpackEntry& entry) {
+const std::string& Value(const FakeHpackEntry& entry) {
return std::get<1>(entry);
}
size_t Size(const FakeHpackEntry& entry) {
@@ -133,7 +133,7 @@ class HpackDecoderTablesTest : public HpackDecoderStaticTableTest {
}
// Insert the name and value into fake_dynamic_table_.
- void FakeInsert(const Http2String& name, const Http2String& value) {
+ void FakeInsert(const std::string& name, const std::string& value) {
FakeHpackEntry entry(name, value, Size(name, value));
fake_dynamic_table_.insert(fake_dynamic_table_.begin(), entry);
}
@@ -204,7 +204,7 @@ class HpackDecoderTablesTest : public HpackDecoderStaticTableTest {
// Insert an entry into the dynamic table, confirming that trimming of entries
// occurs if the total size is greater than the limit, and that older entries
// move up by 1 index.
- AssertionResult Insert(const Http2String& name, const Http2String& value) {
+ AssertionResult Insert(const std::string& name, const std::string& value) {
size_t old_count = num_dynamic_entries();
if (tables_.Insert(HpackString(name), HpackString(value))) {
VERIFY_GT(current_dynamic_size(), 0u);
@@ -251,9 +251,9 @@ TEST_F(HpackDecoderTablesTest, RandomDynamicTable) {
for (size_t limit : table_sizes) {
ASSERT_TRUE(DynamicTableSizeUpdate(limit));
for (int insert_count = 0; insert_count < 100; ++insert_count) {
- Http2String name =
+ std::string name =
GenerateHttp2HeaderName(random_.UniformInRange(2, 40), RandomPtr());
- Http2String value =
+ std::string value =
GenerateWebSafeString(random_.UniformInRange(2, 600), RandomPtr());
ASSERT_TRUE(Insert(name, value));
}
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 bf2cee52c8d..9734bdd71a8 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
@@ -6,6 +6,7 @@
// Tests of HpackDecoder.
+#include <string>
#include <tuple>
#include <utility>
#include <vector>
@@ -22,7 +23,6 @@
#include "net/third_party/quiche/src/http2/hpack/tools/hpack_example.h"
#include "net/third_party/quiche/src/http2/http2_constants.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_logging.h"
-#include "net/third_party/quiche/src/http2/platform/api/http2_string.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_test_helpers.h"
#include "net/third_party/quiche/src/http2/test_tools/http2_random.h"
#include "net/third_party/quiche/src/http2/tools/random_util.h"
@@ -57,7 +57,7 @@ class HpackDecoderPeer {
namespace {
-typedef std::tuple<HpackEntryType, Http2String, Http2String> HpackHeaderEntry;
+typedef std::tuple<HpackEntryType, std::string, std::string> HpackHeaderEntry;
typedef std::vector<HpackHeaderEntry> HpackHeaderEntries;
// TODO(jamessynge): Create a ...test_utils.h file with the mock listener
@@ -121,7 +121,7 @@ class HpackDecoderTest : public ::testing::TestWithParam<bool>,
// error_message may be used in a GOAWAY frame as the Opaque Data.
void OnHeaderErrorDetected(Http2StringPiece error_message) override {
ASSERT_TRUE(saw_start_);
- error_messages_.push_back(Http2String(error_message));
+ error_messages_.push_back(std::string(error_message));
// No further callbacks should be made at this point, so replace 'this' as
// the listener with mock_listener_, which is a strict mock, so will
// generate an error for any calls.
@@ -219,7 +219,7 @@ class HpackDecoderTest : public ::testing::TestWithParam<bool>,
HpackDecoder decoder_;
testing::StrictMock<MockHpackDecoderListener> mock_listener_;
HpackHeaderEntries header_entries_;
- std::vector<Http2String> error_messages_;
+ std::vector<std::string> error_messages_;
bool fragment_the_hpack_block_;
bool saw_start_ = false;
bool saw_end_ = false;
@@ -232,7 +232,7 @@ INSTANTIATE_TEST_SUITE_P(AllWays, HpackDecoderTest, ::testing::Bool());
// http://httpwg.org/specs/rfc7541.html#rfc.section.C.3
TEST_P(HpackDecoderTest, C3_RequestExamples) {
// C.3.1 First Request
- Http2String hpack_block = HpackExampleToStringOrDie(R"(
+ std::string hpack_block = HpackExampleToStringOrDie(R"(
82 | == Indexed - Add ==
| idx = 2
| -> :method: GET
@@ -367,7 +367,7 @@ TEST_P(HpackDecoderTest, C3_RequestExamples) {
// http://httpwg.org/specs/rfc7541.html#rfc.section.C.4
TEST_P(HpackDecoderTest, C4_RequestExamplesWithHuffmanEncoding) {
// C.4.1 First Request
- Http2String hpack_block = HpackExampleToStringOrDie(R"(
+ std::string hpack_block = HpackExampleToStringOrDie(R"(
82 | == Indexed - Add ==
| idx = 2
| -> :method: GET
@@ -526,7 +526,7 @@ TEST_P(HpackDecoderTest, C5_ResponseExamples) {
// date: Mon, 21 Oct 2013 20:13:21 GMT
// location: https://www.example.com
- Http2String hpack_block = HpackExampleToStringOrDie(R"(
+ std::string hpack_block = HpackExampleToStringOrDie(R"(
48 | == Literal indexed ==
| Indexed name (idx = 8)
| :status
@@ -751,7 +751,7 @@ TEST_P(HpackDecoderTest, C6_ResponseExamplesWithHuffmanEncoding) {
// cache-control: private
// date: Mon, 21 Oct 2013 20:13:21 GMT
// location: https://www.example.com
- Http2String hpack_block = HpackExampleToStringOrDie(R"(
+ std::string hpack_block = HpackExampleToStringOrDie(R"(
48 | == Literal indexed ==
| Indexed name (idx = 8)
| :status
diff --git a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_entry_collector.cc b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_entry_collector.cc
index 327075df7ee..7706bd6c644 100644
--- a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_entry_collector.cc
+++ b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_entry_collector.cc
@@ -35,7 +35,7 @@ HpackEntryCollector::HpackEntryCollector(HpackEntryType type,
HpackEntryCollector::HpackEntryCollector(HpackEntryType type,
size_t index,
bool value_huffman,
- const Http2String& value)
+ const std::string& value)
: header_type_(type),
index_(index),
value_(value, value_huffman),
@@ -43,9 +43,9 @@ HpackEntryCollector::HpackEntryCollector(HpackEntryType type,
ended_(true) {}
HpackEntryCollector::HpackEntryCollector(HpackEntryType type,
bool name_huffman,
- const Http2String& name,
+ const std::string& name,
bool value_huffman,
- const Http2String& value)
+ const std::string& value)
: header_type_(type),
index_(0),
name_(name, name_huffman),
@@ -232,8 +232,8 @@ void HpackEntryCollector::AppendToHpackBlockBuilder(
}
}
-Http2String HpackEntryCollector::ToString() const {
- Http2String result("Type=");
+std::string HpackEntryCollector::ToString() const {
+ std::string result("Type=");
switch (header_type_) {
case HpackEntryType::kIndexedHeader:
result += "IndexedHeader";
diff --git a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_entry_collector.h b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_entry_collector.h
index c2c5fe5830d..6b27b7b7f81 100644
--- a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_entry_collector.h
+++ b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_entry_collector.h
@@ -13,13 +13,13 @@
#include <stddef.h>
#include <iosfwd>
+#include <string>
#include "testing/gtest/include/gtest/gtest.h"
#include "net/third_party/quiche/src/http2/hpack/decoder/hpack_entry_decoder_listener.h"
#include "net/third_party/quiche/src/http2/hpack/decoder/hpack_string_collector.h"
#include "net/third_party/quiche/src/http2/hpack/http2_hpack_constants.h"
#include "net/third_party/quiche/src/http2/hpack/tools/hpack_block_builder.h"
-#include "net/third_party/quiche/src/http2/platform/api/http2_string.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_string_piece.h"
namespace http2 {
@@ -37,12 +37,12 @@ class HpackEntryCollector : public HpackEntryDecoderListener {
HpackEntryCollector(HpackEntryType type,
size_t index,
bool value_huffman,
- const Http2String& value);
+ const std::string& value);
HpackEntryCollector(HpackEntryType type,
bool name_huffman,
- const Http2String& name,
+ const std::string& name,
bool value_huffman,
- const Http2String& value);
+ const std::string& value);
~HpackEntryCollector() override;
@@ -122,7 +122,7 @@ class HpackEntryCollector : public HpackEntryDecoderListener {
void AppendToHpackBlockBuilder(HpackBlockBuilder* hbb) const;
// Returns a debug string.
- Http2String ToString() const;
+ std::string ToString() const;
private:
void Init(HpackEntryType type, size_t maybe_index);
diff --git a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_entry_decoder.cc b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_entry_decoder.cc
index 5e1bd8c7176..97af6f9c53c 100644
--- a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_entry_decoder.cc
+++ b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_entry_decoder.cc
@@ -237,7 +237,7 @@ void HpackEntryDecoder::OutputDebugString(std::ostream& out) const {
<< ", " << string_decoder_ << ")";
}
-Http2String HpackEntryDecoder::DebugString() const {
+std::string HpackEntryDecoder::DebugString() const {
std::stringstream s;
s << *this;
return s.str();
diff --git a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_entry_decoder.h b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_entry_decoder.h
index 5858c1e82e6..1848fb6813c 100644
--- a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_entry_decoder.h
+++ b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_entry_decoder.h
@@ -10,6 +10,8 @@
// must provide a non-empty decode buffer. Continue with calls to Resume() if
// Start, and any subsequent calls to Resume, returns kDecodeInProgress.
+#include <string>
+
#include "net/third_party/quiche/src/http2/decoder/decode_buffer.h"
#include "net/third_party/quiche/src/http2/decoder/decode_status.h"
#include "net/third_party/quiche/src/http2/hpack/decoder/hpack_entry_decoder_listener.h"
@@ -18,7 +20,6 @@
#include "net/third_party/quiche/src/http2/hpack/http2_hpack_constants.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_export.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_logging.h"
-#include "net/third_party/quiche/src/http2/platform/api/http2_string.h"
namespace http2 {
@@ -62,7 +63,7 @@ class HTTP2_EXPORT_PRIVATE HpackEntryDecoder {
// in decoding the entry type and its varint.
DecodeStatus Resume(DecodeBuffer* db, HpackEntryDecoderListener* listener);
- Http2String DebugString() const;
+ std::string DebugString() const;
void OutputDebugString(std::ostream& out) const;
private:
diff --git a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_entry_decoder_test.cc b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_entry_decoder_test.cc
index b447e829bbc..d4113f8004e 100644
--- a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_entry_decoder_test.cc
+++ b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_entry_decoder_test.cc
@@ -167,7 +167,7 @@ TEST_P(HpackLiteralEntryDecoderTest, RandNameIndexAndLiteralValue) {
for (int n = 0; n < 10; n++) {
const uint32_t ndx = 1 + Random().Rand8();
const bool value_is_huffman_encoded = (n % 2) == 0;
- const Http2String value = Random().RandString(Random().Rand8());
+ const std::string value = Random().RandString(Random().Rand8());
HpackBlockBuilder hbb;
hbb.AppendNameIndexAndLiteralValue(entry_type_, ndx,
value_is_huffman_encoded, value);
@@ -186,10 +186,10 @@ TEST_P(HpackLiteralEntryDecoderTest, RandLiteralNameAndValue) {
for (int n = 0; n < 10; n++) {
const bool name_is_huffman_encoded = (n & 1) == 0;
const int name_len = 1 + Random().Rand8();
- const Http2String name = Random().RandString(name_len);
+ const std::string name = Random().RandString(name_len);
const bool value_is_huffman_encoded = (n & 2) == 0;
const int value_len = Random().Skewed(10);
- const Http2String value = Random().RandString(value_len);
+ const std::string value = Random().RandString(value_len);
HpackBlockBuilder hbb;
hbb.AppendLiteralNameAndValue(entry_type_, name_is_huffman_encoded, name,
value_is_huffman_encoded, value);
diff --git a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_entry_type_decoder.cc b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_entry_type_decoder.cc
index 7519f5a07b8..ce91978fefb 100644
--- a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_entry_type_decoder.cc
+++ b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_entry_type_decoder.cc
@@ -10,7 +10,7 @@
namespace http2 {
-Http2String HpackEntryTypeDecoder::DebugString() const {
+std::string HpackEntryTypeDecoder::DebugString() const {
return Http2StrCat(
"HpackEntryTypeDecoder(varint_decoder=", varint_decoder_.DebugString(),
", entry_type=", entry_type_, ")");
diff --git a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_entry_type_decoder.h b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_entry_type_decoder.h
index 092a8440f90..bf13cf94bc6 100644
--- a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_entry_type_decoder.h
+++ b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_entry_type_decoder.h
@@ -11,6 +11,7 @@
// zero, or is the new size limit of the dynamic table.
#include <cstdint>
+#include <string>
#include "net/third_party/quiche/src/http2/decoder/decode_buffer.h"
#include "net/third_party/quiche/src/http2/decoder/decode_status.h"
@@ -18,7 +19,6 @@
#include "net/third_party/quiche/src/http2/hpack/varint/hpack_varint_decoder.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_export.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_logging.h"
-#include "net/third_party/quiche/src/http2/platform/api/http2_string.h"
namespace http2 {
@@ -40,7 +40,7 @@ class HTTP2_EXPORT_PRIVATE HpackEntryTypeDecoder {
// preceding call to Start or Resume returned kDecodeDone.
uint64_t varint() const { return varint_decoder_.value(); }
- Http2String DebugString() const;
+ std::string DebugString() const;
private:
HpackVarintDecoder varint_decoder_;
diff --git a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_string_collector.cc b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_string_collector.cc
index 247ce9c2a6a..e903755dc72 100644
--- a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_string_collector.cc
+++ b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_string_collector.cc
@@ -36,7 +36,7 @@ HpackStringCollector::HpackStringCollector() {
Clear();
}
-HpackStringCollector::HpackStringCollector(const Http2String& str, bool huffman)
+HpackStringCollector::HpackStringCollector(const std::string& str, bool huffman)
: s(str), len(str.size()), huffman_encoded(huffman), state(kEnded) {}
void HpackStringCollector::Clear() {
@@ -89,7 +89,7 @@ void HpackStringCollector::OnStringEnd() {
return ::testing::AssertionSuccess();
}
-Http2String HpackStringCollector::ToString() const {
+std::string HpackStringCollector::ToString() const {
std::stringstream ss;
ss << *this;
return ss.str();
diff --git a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_string_collector.h b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_string_collector.h
index 76be13b743c..d56abee231e 100644
--- a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_string_collector.h
+++ b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_string_collector.h
@@ -10,10 +10,10 @@
#include <stddef.h>
#include <iosfwd>
+#include <string>
#include "testing/gtest/include/gtest/gtest.h"
#include "net/third_party/quiche/src/http2/hpack/decoder/hpack_string_decoder_listener.h"
-#include "net/third_party/quiche/src/http2/platform/api/http2_string.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_string_piece.h"
namespace http2 {
@@ -29,7 +29,7 @@ struct HpackStringCollector : public HpackStringDecoderListener {
};
HpackStringCollector();
- HpackStringCollector(const Http2String& str, bool huffman);
+ HpackStringCollector(const std::string& str, bool huffman);
void Clear();
bool IsClear() const;
@@ -43,9 +43,9 @@ struct HpackStringCollector : public HpackStringDecoderListener {
::testing::AssertionResult Collected(Http2StringPiece str,
bool is_huffman_encoded) const;
- Http2String ToString() const;
+ std::string ToString() const;
- Http2String s;
+ std::string s;
size_t len;
bool huffman_encoded;
CollectorState state;
diff --git a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_string_decoder.cc b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_string_decoder.cc
index 0b9eb596835..f74e536f8c1 100644
--- a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_string_decoder.cc
+++ b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_string_decoder.cc
@@ -8,7 +8,7 @@
namespace http2 {
-Http2String HpackStringDecoder::DebugString() const {
+std::string HpackStringDecoder::DebugString() const {
return Http2StrCat("HpackStringDecoder(state=", StateToString(state_),
", length=", length_decoder_.DebugString(),
", remaining=", remaining_,
@@ -16,7 +16,7 @@ Http2String HpackStringDecoder::DebugString() const {
}
// static
-Http2String HpackStringDecoder::StateToString(StringDecoderState v) {
+std::string HpackStringDecoder::StateToString(StringDecoderState v) {
switch (v) {
case kStartDecodingLength:
return "kStartDecodingLength";
diff --git a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_string_decoder.h b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_string_decoder.h
index e30b36dc0bd..0cd17423524 100644
--- a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_string_decoder.h
+++ b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_string_decoder.h
@@ -13,6 +13,7 @@
#include <algorithm>
#include <cstdint>
+#include <string>
#include "net/third_party/quiche/src/http2/decoder/decode_buffer.h"
#include "net/third_party/quiche/src/http2/decoder/decode_status.h"
@@ -20,7 +21,6 @@
#include "net/third_party/quiche/src/http2/platform/api/http2_export.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_logging.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_macros.h"
-#include "net/third_party/quiche/src/http2/platform/api/http2_string.h"
namespace http2 {
@@ -113,10 +113,10 @@ class HTTP2_EXPORT_PRIVATE HpackStringDecoder {
}
}
- Http2String DebugString() const;
+ std::string DebugString() const;
private:
- static Http2String StateToString(StringDecoderState v);
+ static std::string StateToString(StringDecoderState v);
// Returns true if the length is fully decoded and the listener wants the
// decoding to continue, false otherwise; status is set to the status from
diff --git a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_string_decoder_test.cc b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_string_decoder_test.cc
index 53469998d14..ceeebcae48a 100644
--- a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_string_decoder_test.cc
+++ b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_string_decoder_test.cc
@@ -48,10 +48,10 @@ class HpackStringDecoderTest : public RandomDecoderTest {
return collector_.Collected(s, huffman_encoded);
}
- // expected_str is a Http2String rather than a const Http2String& or
+ // expected_str is a std::string rather than a const std::string& or
// Http2StringPiece so that the lambda makes a copy of the string, and thus
// the string to be passed to Collected outlives the call to MakeValidator.
- Validator MakeValidator(const Http2String& expected_str,
+ Validator MakeValidator(const std::string& expected_str,
bool expected_huffman) {
return
[expected_str, expected_huffman, this](
@@ -119,8 +119,8 @@ TEST_F(HpackStringDecoderTest, DecodeShortString) {
}
TEST_F(HpackStringDecoderTest, DecodeLongStrings) {
- Http2String name = Random().RandString(1024);
- Http2String value = Random().RandString(65536);
+ std::string name = Random().RandString(1024);
+ std::string value = Random().RandString(65536);
HpackBlockBuilder hbb;
hbb.AppendString(false, name);
diff --git a/chromium/net/third_party/quiche/src/http2/hpack/hpack_string.cc b/chromium/net/third_party/quiche/src/http2/hpack/hpack_string.cc
index 957cffa62d7..85ba812f7f3 100644
--- a/chromium/net/third_party/quiche/src/http2/hpack/hpack_string.cc
+++ b/chromium/net/third_party/quiche/src/http2/hpack/hpack_string.cc
@@ -12,8 +12,8 @@
namespace http2 {
HpackString::HpackString(const char* data) : str_(data) {}
-HpackString::HpackString(Http2StringPiece str) : str_(Http2String(str)) {}
-HpackString::HpackString(Http2String str) : str_(std::move(str)) {}
+HpackString::HpackString(Http2StringPiece str) : str_(std::string(str)) {}
+HpackString::HpackString(std::string str) : str_(std::move(str)) {}
HpackString::HpackString(const HpackString& other) = default;
HpackString::~HpackString() = default;
@@ -59,7 +59,7 @@ HpackStringPair::~HpackStringPair() {
HTTP2_DVLOG(3) << DebugString() << " dtor";
}
-Http2String HpackStringPair::DebugString() const {
+std::string HpackStringPair::DebugString() const {
return Http2StrCat("HpackStringPair(name=", name.ToString(),
", value=", value.ToString(), ")");
}
diff --git a/chromium/net/third_party/quiche/src/http2/hpack/hpack_string.h b/chromium/net/third_party/quiche/src/http2/hpack/hpack_string.h
index b1c499c95be..e1535f7c114 100644
--- a/chromium/net/third_party/quiche/src/http2/hpack/hpack_string.h
+++ b/chromium/net/third_party/quiche/src/http2/hpack/hpack_string.h
@@ -13,9 +13,9 @@
#include <stddef.h>
#include <iosfwd>
+#include <string>
#include "net/third_party/quiche/src/http2/platform/api/http2_export.h"
-#include "net/third_party/quiche/src/http2/platform/api/http2_string.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_string_piece.h"
namespace http2 {
@@ -24,7 +24,7 @@ class HTTP2_EXPORT_PRIVATE HpackString {
public:
explicit HpackString(const char* data);
explicit HpackString(Http2StringPiece str);
- explicit HpackString(Http2String str);
+ explicit HpackString(std::string str);
HpackString(const HpackString& other);
// Not sure yet whether this move ctor is required/sensible.
@@ -33,7 +33,7 @@ class HTTP2_EXPORT_PRIVATE HpackString {
~HpackString();
size_t size() const { return str_.size(); }
- const Http2String& ToString() const { return str_; }
+ const std::string& ToString() const { return str_; }
Http2StringPiece ToStringPiece() const;
bool operator==(const HpackString& other) const;
@@ -41,7 +41,7 @@ class HTTP2_EXPORT_PRIVATE HpackString {
bool operator==(Http2StringPiece str) const;
private:
- Http2String str_;
+ std::string str_;
};
HTTP2_EXPORT_PRIVATE bool operator==(Http2StringPiece a, const HpackString& b);
@@ -61,7 +61,7 @@ struct HTTP2_EXPORT_PRIVATE HpackStringPair {
// http://httpwg.org/specs/rfc7541.html#calculating.table.size
size_t size() const { return 32 + name.size() + value.size(); }
- Http2String DebugString() const;
+ std::string DebugString() const;
const HpackString name;
const HpackString value;
diff --git a/chromium/net/third_party/quiche/src/http2/hpack/hpack_string_test.cc b/chromium/net/third_party/quiche/src/http2/hpack/hpack_string_test.cc
index 898ef8d1fd1..9230ecc0e14 100644
--- a/chromium/net/third_party/quiche/src/http2/hpack/hpack_string_test.cc
+++ b/chromium/net/third_party/quiche/src/http2/hpack/hpack_string_test.cc
@@ -26,7 +26,7 @@ const char kStr1[] = "S1 - some string to be copied into yet another string.";
class HpackStringTest : public ::testing::Test {
protected:
AssertionResult VerifyNotEqual(HpackString* actual,
- const Http2String& not_expected_str) {
+ const std::string& not_expected_str) {
const char* not_expected_ptr = not_expected_str.c_str();
Http2StringPiece not_expected_sp(not_expected_str);
@@ -52,7 +52,7 @@ class HpackStringTest : public ::testing::Test {
}
AssertionResult VerifyEqual(HpackString* actual,
- const Http2String& expected_str) {
+ const std::string& expected_str) {
VERIFY_EQ(actual->size(), expected_str.size());
const char* expected_ptr = expected_str.c_str();
@@ -103,12 +103,12 @@ TEST_F(HpackStringTest, StringPieceConstructor) {
}
TEST_F(HpackStringTest, MoveStringConstructor) {
- Http2String str0(kStr0);
+ std::string str0(kStr0);
HpackString hs0(str0);
EXPECT_TRUE(VerifyEqual(&hs0, kStr0));
EXPECT_TRUE(VerifyNotEqual(&hs0, kStr1));
- Http2String str1(kStr1);
+ std::string str1(kStr1);
HpackString hs1(str1);
EXPECT_TRUE(VerifyEqual(&hs1, kStr1));
EXPECT_TRUE(VerifyNotEqual(&hs1, kStr0));
diff --git a/chromium/net/third_party/quiche/src/http2/hpack/http2_hpack_constants.cc b/chromium/net/third_party/quiche/src/http2/hpack/http2_hpack_constants.cc
index f258ab9bcbd..d697db03d37 100644
--- a/chromium/net/third_party/quiche/src/http2/hpack/http2_hpack_constants.cc
+++ b/chromium/net/third_party/quiche/src/http2/hpack/http2_hpack_constants.cc
@@ -8,7 +8,7 @@
namespace http2 {
-Http2String HpackEntryTypeToString(HpackEntryType v) {
+std::string HpackEntryTypeToString(HpackEntryType v) {
switch (v) {
case HpackEntryType::kIndexedHeader:
return "kIndexedHeader";
diff --git a/chromium/net/third_party/quiche/src/http2/hpack/http2_hpack_constants.h b/chromium/net/third_party/quiche/src/http2/hpack/http2_hpack_constants.h
index de0d685595d..c9737749a7c 100644
--- a/chromium/net/third_party/quiche/src/http2/hpack/http2_hpack_constants.h
+++ b/chromium/net/third_party/quiche/src/http2/hpack/http2_hpack_constants.h
@@ -11,9 +11,9 @@
// https://http2.github.io/http2-spec/compression.html#rfc.section.6
#include <ostream>
+#include <string>
#include "net/third_party/quiche/src/http2/platform/api/http2_export.h"
-#include "net/third_party/quiche/src/http2/platform/api/http2_string.h"
namespace http2 {
@@ -52,7 +52,7 @@ enum class HpackEntryType {
};
// Returns the name of the enum member.
-HTTP2_EXPORT_PRIVATE Http2String HpackEntryTypeToString(HpackEntryType v);
+HTTP2_EXPORT_PRIVATE std::string HpackEntryTypeToString(HpackEntryType v);
// Inserts the name of the enum member into |out|.
HTTP2_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& out,
diff --git a/chromium/net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_decoder.cc b/chromium/net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_decoder.cc
index e74ca143403..71ce8558159 100644
--- a/chromium/net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_decoder.cc
+++ b/chromium/net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_decoder.cc
@@ -403,7 +403,7 @@ bool HuffmanBitBuffer::InputProperlyTerminated() const {
return false;
}
-Http2String HuffmanBitBuffer::DebugString() const {
+std::string HuffmanBitBuffer::DebugString() const {
std::stringstream ss;
ss << "{accumulator: " << HuffmanAccumulatorBitSet(accumulator_)
<< "; count: " << count_ << "}";
@@ -414,7 +414,7 @@ HpackHuffmanDecoder::HpackHuffmanDecoder() = default;
HpackHuffmanDecoder::~HpackHuffmanDecoder() = default;
-bool HpackHuffmanDecoder::Decode(Http2StringPiece input, Http2String* output) {
+bool HpackHuffmanDecoder::Decode(Http2StringPiece input, std::string* output) {
HTTP2_DVLOG(1) << "HpackHuffmanDecoder::Decode";
// Fill bit_buffer_ from input.
@@ -480,7 +480,7 @@ bool HpackHuffmanDecoder::Decode(Http2StringPiece input, Http2String* output) {
}
}
-Http2String HpackHuffmanDecoder::DebugString() const {
+std::string HpackHuffmanDecoder::DebugString() const {
return bit_buffer_.DebugString();
}
diff --git a/chromium/net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_decoder.h b/chromium/net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_decoder.h
index 8e511d62ae9..065fe853524 100644
--- a/chromium/net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_decoder.h
+++ b/chromium/net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_decoder.h
@@ -16,9 +16,9 @@
#include <cstdint>
#include <iosfwd>
+#include <string>
#include "net/third_party/quiche/src/http2/platform/api/http2_export.h"
-#include "net/third_party/quiche/src/http2/platform/api/http2_string.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_string_piece.h"
namespace http2 {
@@ -74,7 +74,7 @@ class HTTP2_EXPORT_PRIVATE HuffmanBitBuffer {
// of them 1. Otherwise returns false.
bool InputProperlyTerminated() const;
- Http2String DebugString() const;
+ std::string DebugString() const;
private:
HuffmanAccumulator accumulator_;
@@ -109,7 +109,7 @@ class HTTP2_EXPORT_PRIVATE HpackHuffmanDecoder {
// will contain the leading bits of the code for that symbol, but not the
// final bits of that code.
// Note that output should be empty, but that it is not cleared by Decode().
- bool Decode(Http2StringPiece input, Http2String* output);
+ bool Decode(Http2StringPiece input, std::string* output);
// Is what remains in the bit_buffer_ valid at the end of an encoded string?
// Call after passing the the final portion of a Huffman string to Decode,
@@ -118,7 +118,7 @@ class HTTP2_EXPORT_PRIVATE HpackHuffmanDecoder {
return bit_buffer_.InputProperlyTerminated();
}
- Http2String DebugString() const;
+ std::string DebugString() const;
private:
HuffmanBitBuffer bit_buffer_;
diff --git a/chromium/net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_decoder_test.cc b/chromium/net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_decoder_test.cc
index 30b586fd2a6..f1bed3ce6d4 100644
--- a/chromium/net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_decoder_test.cc
+++ b/chromium/net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_decoder_test.cc
@@ -32,7 +32,7 @@ TEST(HuffmanBitBufferTest, Reset) {
}
TEST(HuffmanBitBufferTest, AppendBytesAligned) {
- Http2String s;
+ std::string s;
s.push_back('\x11');
s.push_back('\x22');
s.push_back('\x33');
@@ -81,7 +81,7 @@ TEST(HuffmanBitBufferTest, AppendBytesAligned) {
}
TEST(HuffmanBitBufferTest, ConsumeBits) {
- Http2String s;
+ std::string s;
s.push_back('\x11');
s.push_back('\x22');
s.push_back('\x33');
@@ -103,7 +103,7 @@ TEST(HuffmanBitBufferTest, ConsumeBits) {
}
TEST(HuffmanBitBufferTest, AppendBytesUnaligned) {
- Http2String s;
+ std::string s;
s.push_back('\x11');
s.push_back('\x22');
s.push_back('\x33');
@@ -180,14 +180,14 @@ class HpackHuffmanDecoderTest : public RandomDecoderTest {
}
HpackHuffmanDecoder decoder_;
- Http2String output_buffer_;
+ std::string output_buffer_;
size_t input_bytes_seen_;
size_t input_bytes_expected_;
};
TEST_F(HpackHuffmanDecoderTest, SpecRequestExamples) {
HpackHuffmanDecoder decoder;
- Http2String test_table[] = {
+ std::string test_table[] = {
Http2HexDecode("f1e3c2e5f23a6ba0ab90f4ff"),
"www.example.com",
Http2HexDecode("a8eb10649cbf"),
@@ -198,9 +198,9 @@ TEST_F(HpackHuffmanDecoderTest, SpecRequestExamples) {
"custom-value",
};
for (size_t i = 0; i != HTTP2_ARRAYSIZE(test_table); i += 2) {
- const Http2String& huffman_encoded(test_table[i]);
- const Http2String& plain_string(test_table[i + 1]);
- Http2String buffer;
+ const std::string& huffman_encoded(test_table[i]);
+ const std::string& plain_string(test_table[i + 1]);
+ std::string buffer;
decoder.Reset();
EXPECT_TRUE(decoder.Decode(huffman_encoded, &buffer)) << decoder;
EXPECT_TRUE(decoder.InputProperlyTerminated()) << decoder;
@@ -211,7 +211,7 @@ TEST_F(HpackHuffmanDecoderTest, SpecRequestExamples) {
TEST_F(HpackHuffmanDecoderTest, SpecResponseExamples) {
HpackHuffmanDecoder decoder;
// clang-format off
- Http2String test_table[] = {
+ std::string test_table[] = {
Http2HexDecode("6402"),
"302",
Http2HexDecode("aec3771a4b"),
@@ -229,9 +229,9 @@ TEST_F(HpackHuffmanDecoderTest, SpecResponseExamples) {
};
// clang-format on
for (size_t i = 0; i != HTTP2_ARRAYSIZE(test_table); i += 2) {
- const Http2String& huffman_encoded(test_table[i]);
- const Http2String& plain_string(test_table[i + 1]);
- Http2String buffer;
+ const std::string& huffman_encoded(test_table[i]);
+ const std::string& plain_string(test_table[i + 1]);
+ std::string buffer;
decoder.Reset();
EXPECT_TRUE(decoder.Decode(huffman_encoded, &buffer)) << decoder;
EXPECT_TRUE(decoder.InputProperlyTerminated()) << decoder;
diff --git a/chromium/net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_encoder.cc b/chromium/net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_encoder.cc
index a92a4c0ed7c..8a5dee9698e 100644
--- a/chromium/net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_encoder.cc
+++ b/chromium/net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_encoder.cc
@@ -61,7 +61,7 @@ size_t BoundedHuffmanSize(Http2StringPiece plain) {
return (bits + 7) / 8;
}
-void HuffmanEncode(Http2StringPiece plain, Http2String* huffman) {
+void HuffmanEncode(Http2StringPiece plain, std::string* huffman) {
DCHECK(huffman != nullptr);
huffman->clear(); // Note that this doesn't release memory.
uint64_t bit_buffer = 0; // High-bit is next bit to output. Not clear if that
diff --git a/chromium/net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_encoder.h b/chromium/net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_encoder.h
index bf6b1b23b34..247aaff6ba7 100644
--- a/chromium/net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_encoder.h
+++ b/chromium/net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_encoder.h
@@ -9,9 +9,9 @@
// table.
#include <cstddef> // For size_t
+#include <string>
#include "net/third_party/quiche/src/http2/platform/api/http2_export.h"
-#include "net/third_party/quiche/src/http2/platform/api/http2_string.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_string_piece.h"
namespace http2 {
@@ -33,7 +33,7 @@ HTTP2_EXPORT_PRIVATE size_t BoundedHuffmanSize(Http2StringPiece plain);
// the beginning of this function. This allows reusing the same string object
// across multiple invocations.
HTTP2_EXPORT_PRIVATE void HuffmanEncode(Http2StringPiece plain,
- Http2String* huffman);
+ std::string* huffman);
} // namespace http2
diff --git a/chromium/net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_encoder_test.cc b/chromium/net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_encoder_test.cc
index 2a8999fd3a8..24d3cf12f19 100644
--- a/chromium/net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_encoder_test.cc
+++ b/chromium/net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_encoder_test.cc
@@ -12,7 +12,7 @@ namespace http2 {
namespace {
TEST(HuffmanEncoderTest, SpecRequestExamples) {
- Http2String test_table[] = {
+ std::string test_table[] = {
Http2HexDecode("f1e3c2e5f23a6ba0ab90f4ff"),
"www.example.com",
Http2HexDecode("a8eb10649cbf"),
@@ -23,11 +23,11 @@ TEST(HuffmanEncoderTest, SpecRequestExamples) {
"custom-value",
};
for (size_t i = 0; i != HTTP2_ARRAYSIZE(test_table); i += 2) {
- const Http2String& huffman_encoded(test_table[i]);
- const Http2String& plain_string(test_table[i + 1]);
+ const std::string& huffman_encoded(test_table[i]);
+ const std::string& plain_string(test_table[i + 1]);
EXPECT_EQ(ExactHuffmanSize(plain_string), huffman_encoded.size());
EXPECT_EQ(BoundedHuffmanSize(plain_string), huffman_encoded.size());
- Http2String buffer;
+ std::string buffer;
buffer.reserve();
HuffmanEncode(plain_string, &buffer);
EXPECT_EQ(buffer, huffman_encoded) << "Error encoding " << plain_string;
@@ -36,7 +36,7 @@ TEST(HuffmanEncoderTest, SpecRequestExamples) {
TEST(HuffmanEncoderTest, SpecResponseExamples) {
// clang-format off
- Http2String test_table[] = {
+ std::string test_table[] = {
Http2HexDecode("6402"),
"302",
Http2HexDecode("aec3771a4b"),
@@ -54,11 +54,11 @@ TEST(HuffmanEncoderTest, SpecResponseExamples) {
};
// clang-format on
for (size_t i = 0; i != HTTP2_ARRAYSIZE(test_table); i += 2) {
- const Http2String& huffman_encoded(test_table[i]);
- const Http2String& plain_string(test_table[i + 1]);
+ const std::string& huffman_encoded(test_table[i]);
+ const std::string& plain_string(test_table[i + 1]);
EXPECT_EQ(ExactHuffmanSize(plain_string), huffman_encoded.size());
EXPECT_EQ(BoundedHuffmanSize(plain_string), huffman_encoded.size());
- Http2String buffer;
+ std::string buffer;
buffer.reserve(huffman_encoded.size());
const size_t capacity = buffer.capacity();
HuffmanEncode(plain_string, &buffer);
@@ -68,14 +68,14 @@ TEST(HuffmanEncoderTest, SpecResponseExamples) {
}
TEST(HuffmanEncoderTest, EncodedSizeAgreesWithEncodeString) {
- Http2String test_table[] = {
+ std::string test_table[] = {
"",
"Mon, 21 Oct 2013 20:13:21 GMT",
"https://www.example.com",
"foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1",
- Http2String(1, '\0'),
- Http2String("foo\0bar", 7),
- Http2String(256, '\0'),
+ std::string(1, '\0'),
+ std::string("foo\0bar", 7),
+ std::string(256, '\0'),
};
// Modify last |test_table| entry to cover all codes.
for (size_t i = 0; i != 256; ++i) {
@@ -83,8 +83,8 @@ TEST(HuffmanEncoderTest, EncodedSizeAgreesWithEncodeString) {
}
for (size_t i = 0; i != HTTP2_ARRAYSIZE(test_table); ++i) {
- const Http2String& plain_string = test_table[i];
- Http2String huffman_encoded;
+ const std::string& plain_string = test_table[i];
+ std::string huffman_encoded;
HuffmanEncode(plain_string, &huffman_encoded);
EXPECT_EQ(huffman_encoded.size(), ExactHuffmanSize(plain_string));
EXPECT_LE(BoundedHuffmanSize(plain_string), plain_string.size());
diff --git a/chromium/net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_transcoder_test.cc b/chromium/net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_transcoder_test.cc
index 2791d6a14a7..9781094dfb8 100644
--- a/chromium/net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_transcoder_test.cc
+++ b/chromium/net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_transcoder_test.cc
@@ -11,7 +11,6 @@
#include "net/third_party/quiche/src/http2/decoder/decode_status.h"
#include "net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_decoder.h"
#include "net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_encoder.h"
-#include "net/third_party/quiche/src/http2/platform/api/http2_string.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_string_piece.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_string_utils.h"
#include "net/third_party/quiche/src/http2/tools/random_decoder_test.h"
@@ -24,8 +23,8 @@ namespace http2 {
namespace test {
namespace {
-Http2String GenAsciiNonControlSet() {
- Http2String s;
+std::string GenAsciiNonControlSet() {
+ std::string s;
const char space = ' '; // First character after the control characters: 0x20
const char del = 127; // First character after the non-control characters.
for (char c = space; c < del; ++c) {
@@ -74,7 +73,7 @@ class HpackHuffmanTranscoderTest : public RandomDecoderTest {
AssertionResult TranscodeAndValidateSeveralWays(
Http2StringPiece plain,
Http2StringPiece expected_huffman) {
- Http2String encoded;
+ std::string encoded;
HuffmanEncode(plain, &encoded);
if (expected_huffman.size() > 0 || plain.empty()) {
VERIFY_EQ(encoded, expected_huffman);
@@ -95,22 +94,22 @@ class HpackHuffmanTranscoderTest : public RandomDecoderTest {
return TranscodeAndValidateSeveralWays(plain, "");
}
- Http2String RandomAsciiNonControlString(int length) {
+ std::string RandomAsciiNonControlString(int length) {
return Random().RandStringWithAlphabet(length, ascii_non_control_set_);
}
- Http2String RandomBytes(int length) { return Random().RandString(length); }
+ std::string RandomBytes(int length) { return Random().RandString(length); }
- const Http2String ascii_non_control_set_;
+ const std::string ascii_non_control_set_;
HpackHuffmanDecoder decoder_;
- Http2String output_buffer_;
+ std::string output_buffer_;
size_t input_bytes_seen_;
size_t input_bytes_expected_;
};
TEST_F(HpackHuffmanTranscoderTest, RoundTripRandomAsciiNonControlString) {
for (size_t length = 0; length != 20; length++) {
- const Http2String s = RandomAsciiNonControlString(length);
+ const std::string s = RandomAsciiNonControlString(length);
ASSERT_TRUE(TranscodeAndValidateSeveralWays(s))
<< "Unable to decode:\n\n"
<< Http2HexDump(s) << "\n\noutput_buffer_:\n"
@@ -120,7 +119,7 @@ TEST_F(HpackHuffmanTranscoderTest, RoundTripRandomAsciiNonControlString) {
TEST_F(HpackHuffmanTranscoderTest, RoundTripRandomBytes) {
for (size_t length = 0; length != 20; length++) {
- const Http2String s = RandomBytes(length);
+ const std::string s = RandomBytes(length);
ASSERT_TRUE(TranscodeAndValidateSeveralWays(s))
<< "Unable to decode:\n\n"
<< Http2HexDump(s) << "\n\noutput_buffer_:\n"
@@ -145,7 +144,7 @@ INSTANTIATE_TEST_SUITE_P(HpackHuffmanTranscoderAdjacentCharTest,
// Test c_ adjacent to every other character, both before and after.
TEST_P(HpackHuffmanTranscoderAdjacentCharTest, RoundTripAdjacentChar) {
- Http2String s;
+ std::string s;
for (int a = 0; a < 256; ++a) {
s.push_back(static_cast<char>(a));
s.push_back(c_);
@@ -162,7 +161,7 @@ class HpackHuffmanTranscoderRepeatedCharTest
HpackHuffmanTranscoderRepeatedCharTest()
: c_(static_cast<char>(::testing::get<0>(GetParam()))),
length_(::testing::get<1>(GetParam())) {}
- Http2String MakeString() { return Http2String(length_, c_); }
+ std::string MakeString() { return std::string(length_, c_); }
private:
const char c_;
diff --git a/chromium/net/third_party/quiche/src/http2/hpack/tools/hpack_block_builder.h b/chromium/net/third_party/quiche/src/http2/hpack/tools/hpack_block_builder.h
index 560953cc341..59c3805bcb6 100644
--- a/chromium/net/third_party/quiche/src/http2/hpack/tools/hpack_block_builder.h
+++ b/chromium/net/third_party/quiche/src/http2/hpack/tools/hpack_block_builder.h
@@ -18,10 +18,10 @@
#include <stddef.h>
#include <cstdint>
+#include <string>
#include "testing/gtest/include/gtest/gtest.h"
#include "net/third_party/quiche/src/http2/hpack/http2_hpack_constants.h"
-#include "net/third_party/quiche/src/http2/platform/api/http2_string.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_string_piece.h"
namespace http2 {
@@ -35,7 +35,7 @@ class HpackBlockBuilder {
~HpackBlockBuilder() {}
size_t size() const { return buffer_.size(); }
- const Http2String& buffer() const { return buffer_; }
+ const std::string& buffer() const { return buffer_; }
//----------------------------------------------------------------------------
// Methods for appending a valid HPACK entry.
@@ -87,7 +87,7 @@ class HpackBlockBuilder {
void AppendString(bool is_huffman_encoded, Http2StringPiece str);
private:
- Http2String buffer_;
+ std::string buffer_;
};
} // namespace test
diff --git a/chromium/net/third_party/quiche/src/http2/hpack/tools/hpack_block_builder_test.cc b/chromium/net/third_party/quiche/src/http2/hpack/tools/hpack_block_builder_test.cc
index a7b80647979..bba363f2d2a 100644
--- a/chromium/net/third_party/quiche/src/http2/hpack/tools/hpack_block_builder_test.cc
+++ b/chromium/net/third_party/quiche/src/http2/hpack/tools/hpack_block_builder_test.cc
@@ -96,7 +96,7 @@ TEST(HpackBlockBuilderTest, ExamplesFromSpecC3) {
// 0x0000: 8286 8441 0f77 7777 2e65 7861 6d70 6c65 ...A.www.example
// 0x0010: 2e63 6f6d .com
- const Http2String expected =
+ const std::string expected =
Http2HexDecode("828684410f7777772e6578616d706c652e636f6d");
EXPECT_EQ(expected, b.buffer());
}
@@ -127,7 +127,7 @@ TEST(HpackBlockBuilderTest, ExamplesFromSpecC4) {
// 0x0000: 8286 8441 8cf1 e3c2 e5f2 3a6b a0ab 90f4 ...A......:k....
// 0x0010: ff .
- const Http2String expected =
+ const std::string expected =
Http2HexDecode("828684418cf1e3c2e5f23a6ba0ab90f4ff");
EXPECT_EQ(expected, b.buffer());
}
diff --git a/chromium/net/third_party/quiche/src/http2/hpack/tools/hpack_example.cc b/chromium/net/third_party/quiche/src/http2/hpack/tools/hpack_example.cc
index d7b8c7c6739..52d84f9747e 100644
--- a/chromium/net/third_party/quiche/src/http2/hpack/tools/hpack_example.cc
+++ b/chromium/net/third_party/quiche/src/http2/hpack/tools/hpack_example.cc
@@ -14,7 +14,7 @@ namespace http2 {
namespace test {
namespace {
-void HpackExampleToStringOrDie(Http2StringPiece example, Http2String* output) {
+void HpackExampleToStringOrDie(Http2StringPiece example, std::string* output) {
while (!example.empty()) {
const char c0 = example[0];
if (isxdigit(c0)) {
@@ -48,8 +48,8 @@ void HpackExampleToStringOrDie(Http2StringPiece example, Http2String* output) {
} // namespace
-Http2String HpackExampleToStringOrDie(Http2StringPiece example) {
- Http2String output;
+std::string HpackExampleToStringOrDie(Http2StringPiece example) {
+ std::string output;
HpackExampleToStringOrDie(example, &output);
return output;
}
diff --git a/chromium/net/third_party/quiche/src/http2/hpack/tools/hpack_example.h b/chromium/net/third_party/quiche/src/http2/hpack/tools/hpack_example.h
index ddb22a32534..0371e17abbe 100644
--- a/chromium/net/third_party/quiche/src/http2/hpack/tools/hpack_example.h
+++ b/chromium/net/third_party/quiche/src/http2/hpack/tools/hpack_example.h
@@ -5,7 +5,8 @@
#ifndef QUICHE_HTTP2_HPACK_TOOLS_HPACK_EXAMPLE_H_
#define QUICHE_HTTP2_HPACK_TOOLS_HPACK_EXAMPLE_H_
-#include "net/third_party/quiche/src/http2/platform/api/http2_string.h"
+#include <string>
+
#include "net/third_party/quiche/src/http2/platform/api/http2_string_piece.h"
// Parses HPACK examples in the format seen in the HPACK specification,
@@ -23,7 +24,7 @@
namespace http2 {
namespace test {
-Http2String HpackExampleToStringOrDie(Http2StringPiece example);
+std::string HpackExampleToStringOrDie(Http2StringPiece example);
} // namespace test
} // namespace http2
diff --git a/chromium/net/third_party/quiche/src/http2/hpack/varint/hpack_varint_decoder.cc b/chromium/net/third_party/quiche/src/http2/hpack/varint/hpack_varint_decoder.cc
index 9741a23cbdd..e7e2c9c19ca 100644
--- a/chromium/net/third_party/quiche/src/http2/hpack/varint/hpack_varint_decoder.cc
+++ b/chromium/net/third_party/quiche/src/http2/hpack/varint/hpack_varint_decoder.cc
@@ -120,7 +120,7 @@ void HpackVarintDecoder::set_value(uint64_t v) {
value_ = v;
}
-Http2String HpackVarintDecoder::DebugString() const {
+std::string HpackVarintDecoder::DebugString() const {
return Http2StrCat("HpackVarintDecoder(value=", value_, ", offset=", offset_,
")");
}
diff --git a/chromium/net/third_party/quiche/src/http2/hpack/varint/hpack_varint_decoder.h b/chromium/net/third_party/quiche/src/http2/hpack/varint/hpack_varint_decoder.h
index 855ced449ab..45764468b77 100644
--- a/chromium/net/third_party/quiche/src/http2/hpack/varint/hpack_varint_decoder.h
+++ b/chromium/net/third_party/quiche/src/http2/hpack/varint/hpack_varint_decoder.h
@@ -29,12 +29,12 @@
#include <cstdint>
#include <limits>
+#include <string>
#include "net/third_party/quiche/src/http2/decoder/decode_buffer.h"
#include "net/third_party/quiche/src/http2/decoder/decode_status.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_export.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_logging.h"
-#include "net/third_party/quiche/src/http2/platform/api/http2_string.h"
namespace http2 {
@@ -83,7 +83,7 @@ class HTTP2_EXPORT_PRIVATE HpackVarintDecoder {
// All the public methods below are for supporting assertions and tests.
- Http2String DebugString() const;
+ std::string DebugString() const;
// For benchmarking, these methods ensure the decoder
// is NOT inlined into the caller.
diff --git a/chromium/net/third_party/quiche/src/http2/hpack/varint/hpack_varint_decoder_test.cc b/chromium/net/third_party/quiche/src/http2/hpack/varint/hpack_varint_decoder_test.cc
index 16101262df8..07cb51b87b4 100644
--- a/chromium/net/third_party/quiche/src/http2/hpack/varint/hpack_varint_decoder_test.cc
+++ b/chromium/net/third_party/quiche/src/http2/hpack/varint/hpack_varint_decoder_test.cc
@@ -69,7 +69,7 @@ class HpackVarintDecoderTest : public RandomDecoderTest,
prefix_length_ = prefix_length;
// Copy |data| so that it can be modified.
- Http2String data_copy(data);
+ std::string data_copy(data);
// Bits of the first byte not part of the prefix should be ignored.
uint8_t high_bits_mask = 0b11111111 << prefix_length_;
@@ -101,7 +101,7 @@ class HpackVarintDecoderTest : public RandomDecoderTest,
// Bits of the first byte not part of the prefix.
const uint8_t high_bits_;
// Extra bytes appended to the input.
- const Http2String suffix_;
+ const std::string suffix_;
HpackVarintDecoder decoder_;
uint8_t prefix_length_;
diff --git a/chromium/net/third_party/quiche/src/http2/hpack/varint/hpack_varint_encoder.cc b/chromium/net/third_party/quiche/src/http2/hpack/varint/hpack_varint_encoder.cc
index 63cf2897839..11ebf6ae748 100644
--- a/chromium/net/third_party/quiche/src/http2/hpack/varint/hpack_varint_encoder.cc
+++ b/chromium/net/third_party/quiche/src/http2/hpack/varint/hpack_varint_encoder.cc
@@ -14,7 +14,7 @@ namespace http2 {
void HpackVarintEncoder::Encode(uint8_t high_bits,
uint8_t prefix_length,
uint64_t varint,
- Http2String* output) {
+ std::string* output) {
DCHECK_LE(1u, prefix_length);
DCHECK_LE(prefix_length, 8u);
diff --git a/chromium/net/third_party/quiche/src/http2/hpack/varint/hpack_varint_encoder.h b/chromium/net/third_party/quiche/src/http2/hpack/varint/hpack_varint_encoder.h
index 745222e9566..014380d76f4 100644
--- a/chromium/net/third_party/quiche/src/http2/hpack/varint/hpack_varint_encoder.h
+++ b/chromium/net/third_party/quiche/src/http2/hpack/varint/hpack_varint_encoder.h
@@ -7,9 +7,9 @@
#include <cstddef>
#include <cstdint>
+#include <string>
#include "net/third_party/quiche/src/http2/platform/api/http2_export.h"
-#include "net/third_party/quiche/src/http2/platform/api/http2_string.h"
namespace http2 {
@@ -23,7 +23,7 @@ class HTTP2_EXPORT_PRIVATE HpackVarintEncoder {
static void Encode(uint8_t high_bits,
uint8_t prefix_length,
uint64_t varint,
- Http2String* output);
+ std::string* output);
};
} // namespace http2
diff --git a/chromium/net/third_party/quiche/src/http2/hpack/varint/hpack_varint_encoder_test.cc b/chromium/net/third_party/quiche/src/http2/hpack/varint/hpack_varint_encoder_test.cc
index 94f9a9e5935..23c19c41603 100644
--- a/chromium/net/third_party/quiche/src/http2/hpack/varint/hpack_varint_encoder_test.cc
+++ b/chromium/net/third_party/quiche/src/http2/hpack/varint/hpack_varint_encoder_test.cc
@@ -31,7 +31,7 @@ struct {
// Encode integers that fit in the prefix.
TEST(HpackVarintEncoderTest, Short) {
for (size_t i = 0; i < HTTP2_ARRAYSIZE(kShortTestData); ++i) {
- Http2String output;
+ std::string output;
HpackVarintEncoder::Encode(kShortTestData[i].high_bits,
kShortTestData[i].prefix_length,
kShortTestData[i].value, &output);
@@ -104,10 +104,10 @@ TEST(HpackVarintEncoderTest, Long) {
// Test encoding byte by byte, also test encoding in
// a single ResumeEncoding() call.
for (size_t i = 0; i < HTTP2_ARRAYSIZE(kLongTestData); ++i) {
- Http2String expected_encoding =
+ std::string expected_encoding =
Http2HexDecode(kLongTestData[i].expected_encoding);
- Http2String output;
+ std::string output;
HpackVarintEncoder::Encode(kLongTestData[i].high_bits,
kLongTestData[i].prefix_length,
kLongTestData[i].value, &output);
@@ -131,7 +131,7 @@ struct {
// happens exactly when encoding the value 2^prefix_length - 1.
TEST(HpackVarintEncoderTest, LastByteIsZero) {
for (size_t i = 0; i < HTTP2_ARRAYSIZE(kLastByteIsZeroTestData); ++i) {
- Http2String output;
+ std::string output;
HpackVarintEncoder::Encode(kLastByteIsZeroTestData[i].high_bits,
kLastByteIsZeroTestData[i].prefix_length,
kLastByteIsZeroTestData[i].value, &output);
@@ -144,7 +144,7 @@ TEST(HpackVarintEncoderTest, LastByteIsZero) {
// Test that encoder appends correctly to non-empty string.
TEST(HpackVarintEncoderTest, Append) {
- Http2String output("foo");
+ std::string output("foo");
EXPECT_EQ(Http2HexDecode("666f6f"), output);
HpackVarintEncoder::Encode(0b10011000, 3, 103, &output);
diff --git a/chromium/net/third_party/quiche/src/http2/hpack/varint/hpack_varint_round_trip_test.cc b/chromium/net/third_party/quiche/src/http2/hpack/varint/hpack_varint_round_trip_test.cc
index 594317b3866..a5318fb9949 100644
--- a/chromium/net/third_party/quiche/src/http2/hpack/varint/hpack_varint_round_trip_test.cc
+++ b/chromium/net/third_party/quiche/src/http2/hpack/varint/hpack_varint_round_trip_test.cc
@@ -161,7 +161,7 @@ class HpackVarintRoundTripTest : public RandomDecoderTest {
for (const uint64_t value : values) {
Encode(value, prefix_length); // Sets buffer_.
- Http2String msg = Http2StrCat("value=", value, " (0x", Http2Hex(value),
+ std::string msg = Http2StrCat("value=", value, " (0x", Http2Hex(value),
"), prefix_length=", prefix_length,
", expected_bytes=", expected_bytes, "\n",
Http2HexDump(buffer_));
@@ -241,7 +241,7 @@ class HpackVarintRoundTripTest : public RandomDecoderTest {
}
HpackVarintDecoder decoder_;
- Http2String buffer_;
+ std::string buffer_;
uint8_t prefix_length_;
};
@@ -283,7 +283,7 @@ TEST_F(HpackVarintRoundTripTest, Encode) {
for (uint64_t value : values) {
EncodeNoRandom(value, prefix_length);
- Http2String dump = Http2HexDump(buffer_);
+ std::string dump = Http2HexDump(buffer_);
HTTP2_LOG(INFO) << Http2StringPrintf("%10llu %0#18x ", value, value)
<< Http2HexDump(buffer_).substr(7);
}
diff --git a/chromium/net/third_party/quiche/src/http2/http2_constants.cc b/chromium/net/third_party/quiche/src/http2/http2_constants.cc
index ad15b69da90..38f8ab58cf9 100644
--- a/chromium/net/third_party/quiche/src/http2/http2_constants.cc
+++ b/chromium/net/third_party/quiche/src/http2/http2_constants.cc
@@ -10,7 +10,7 @@
namespace http2 {
-Http2String Http2FrameTypeToString(Http2FrameType v) {
+std::string Http2FrameTypeToString(Http2FrameType v) {
switch (v) {
case Http2FrameType::DATA:
return "DATA";
@@ -38,13 +38,13 @@ Http2String Http2FrameTypeToString(Http2FrameType v) {
return Http2StrCat("UnknownFrameType(", static_cast<int>(v), ")");
}
-Http2String Http2FrameTypeToString(uint8_t v) {
+std::string Http2FrameTypeToString(uint8_t v) {
return Http2FrameTypeToString(static_cast<Http2FrameType>(v));
}
-Http2String Http2FrameFlagsToString(Http2FrameType type, uint8_t flags) {
- Http2String s;
- // Closure to append flag name |v| to the Http2String |s|,
+std::string Http2FrameFlagsToString(Http2FrameType type, uint8_t flags) {
+ std::string s;
+ // Closure to append flag name |v| to the std::string |s|,
// and to clear |bit| from |flags|.
auto append_and_clear = [&s, &flags](Http2StringPiece v, uint8_t bit) {
if (!s.empty()) {
@@ -85,11 +85,11 @@ Http2String Http2FrameFlagsToString(Http2FrameType type, uint8_t flags) {
DCHECK_EQ(0, flags);
return s;
}
-Http2String Http2FrameFlagsToString(uint8_t type, uint8_t flags) {
+std::string Http2FrameFlagsToString(uint8_t type, uint8_t flags) {
return Http2FrameFlagsToString(static_cast<Http2FrameType>(type), flags);
}
-Http2String Http2ErrorCodeToString(uint32_t v) {
+std::string Http2ErrorCodeToString(uint32_t v) {
switch (v) {
case 0x0:
return "NO_ERROR";
@@ -122,11 +122,11 @@ Http2String Http2ErrorCodeToString(uint32_t v) {
}
return Http2StrCat("UnknownErrorCode(0x", Http2Hex(v), ")");
}
-Http2String Http2ErrorCodeToString(Http2ErrorCode v) {
+std::string Http2ErrorCodeToString(Http2ErrorCode v) {
return Http2ErrorCodeToString(static_cast<uint32_t>(v));
}
-Http2String Http2SettingsParameterToString(uint32_t v) {
+std::string Http2SettingsParameterToString(uint32_t v) {
switch (v) {
case 0x1:
return "HEADER_TABLE_SIZE";
@@ -143,7 +143,7 @@ Http2String Http2SettingsParameterToString(uint32_t v) {
}
return Http2StrCat("UnknownSettingsParameter(0x", Http2Hex(v), ")");
}
-Http2String Http2SettingsParameterToString(Http2SettingsParameter v) {
+std::string Http2SettingsParameterToString(Http2SettingsParameter v) {
return Http2SettingsParameterToString(static_cast<uint32_t>(v));
}
diff --git a/chromium/net/third_party/quiche/src/http2/http2_constants.h b/chromium/net/third_party/quiche/src/http2/http2_constants.h
index 93920069c5a..75f294e6672 100644
--- a/chromium/net/third_party/quiche/src/http2/http2_constants.h
+++ b/chromium/net/third_party/quiche/src/http2/http2_constants.h
@@ -10,9 +10,9 @@
#include <cstdint>
#include <iosfwd>
#include <ostream>
+#include <string>
#include "net/third_party/quiche/src/http2/platform/api/http2_export.h"
-#include "net/third_party/quiche/src/http2/platform/api/http2_string.h"
namespace http2 {
@@ -52,12 +52,12 @@ inline bool IsSupportedHttp2FrameType(Http2FrameType v) {
return IsSupportedHttp2FrameType(static_cast<uint32_t>(v));
}
-// The return type is 'Http2String' so that they can generate a unique string
+// The return type is 'std::string' so that they can generate a unique string
// for each unsupported value. Since these are just used for debugging/error
// messages, that isn't a cost to we need to worry about. The same applies to
// the functions later in this file.
-HTTP2_EXPORT_PRIVATE Http2String Http2FrameTypeToString(Http2FrameType v);
-HTTP2_EXPORT_PRIVATE Http2String Http2FrameTypeToString(uint8_t v);
+HTTP2_EXPORT_PRIVATE std::string Http2FrameTypeToString(Http2FrameType v);
+HTTP2_EXPORT_PRIVATE std::string Http2FrameTypeToString(uint8_t v);
HTTP2_EXPORT_PRIVATE inline std::ostream& operator<<(std::ostream& out,
Http2FrameType v) {
return out << Http2FrameTypeToString(v);
@@ -75,9 +75,9 @@ enum Http2FrameFlag {
// Formats zero or more flags for the specified type of frame. Returns an
// empty string if flags==0.
-HTTP2_EXPORT_PRIVATE Http2String Http2FrameFlagsToString(Http2FrameType type,
+HTTP2_EXPORT_PRIVATE std::string Http2FrameFlagsToString(Http2FrameType type,
uint8_t flags);
-HTTP2_EXPORT_PRIVATE Http2String Http2FrameFlagsToString(uint8_t type,
+HTTP2_EXPORT_PRIVATE std::string Http2FrameFlagsToString(uint8_t type,
uint8_t flags);
// Error codes for GOAWAY and RST_STREAM frames.
@@ -142,8 +142,8 @@ inline bool IsSupportedHttp2ErrorCode(Http2ErrorCode v) {
}
// Format the specified error code.
-HTTP2_EXPORT_PRIVATE Http2String Http2ErrorCodeToString(uint32_t v);
-HTTP2_EXPORT_PRIVATE Http2String Http2ErrorCodeToString(Http2ErrorCode v);
+HTTP2_EXPORT_PRIVATE std::string Http2ErrorCodeToString(uint32_t v);
+HTTP2_EXPORT_PRIVATE std::string Http2ErrorCodeToString(Http2ErrorCode v);
HTTP2_EXPORT_PRIVATE inline std::ostream& operator<<(std::ostream& out,
Http2ErrorCode v) {
return out << Http2ErrorCodeToString(v);
@@ -222,9 +222,9 @@ inline bool IsSupportedHttp2SettingsParameter(Http2SettingsParameter v) {
}
// Format the specified settings parameter.
-HTTP2_EXPORT_PRIVATE Http2String Http2SettingsParameterToString(uint32_t v);
-HTTP2_EXPORT_PRIVATE Http2String
-Http2SettingsParameterToString(Http2SettingsParameter v);
+HTTP2_EXPORT_PRIVATE std::string Http2SettingsParameterToString(uint32_t v);
+HTTP2_EXPORT_PRIVATE std::string Http2SettingsParameterToString(
+ Http2SettingsParameter v);
inline std::ostream& operator<<(std::ostream& out, Http2SettingsParameter v) {
return out << Http2SettingsParameterToString(v);
}
diff --git a/chromium/net/third_party/quiche/src/http2/http2_structures.cc b/chromium/net/third_party/quiche/src/http2/http2_structures.cc
index 7dbaf30aedc..7b00db47cb2 100644
--- a/chromium/net/third_party/quiche/src/http2/http2_structures.cc
+++ b/chromium/net/third_party/quiche/src/http2/http2_structures.cc
@@ -19,13 +19,13 @@ bool Http2FrameHeader::IsProbableHttpResponse() const {
flags == '/'); // "/"
}
-Http2String Http2FrameHeader::ToString() const {
+std::string Http2FrameHeader::ToString() const {
return Http2StrCat("length=", payload_length,
", type=", Http2FrameTypeToString(type),
", flags=", FlagsToString(), ", stream=", stream_id);
}
-Http2String Http2FrameHeader::FlagsToString() const {
+std::string Http2FrameHeader::FlagsToString() const {
return Http2FrameFlagsToString(type, flags);
}
@@ -44,7 +44,7 @@ bool operator==(const Http2PriorityFields& a, const Http2PriorityFields& b) {
return a.stream_dependency == b.stream_dependency && a.weight == b.weight;
}
-Http2String Http2PriorityFields::ToString() const {
+std::string Http2PriorityFields::ToString() const {
std::stringstream ss;
ss << "E=" << (is_exclusive ? "true" : "false")
<< ", stream=" << stream_dependency
diff --git a/chromium/net/third_party/quiche/src/http2/http2_structures.h b/chromium/net/third_party/quiche/src/http2/http2_structures.h
index f236cfbacec..f73e1099b8d 100644
--- a/chromium/net/third_party/quiche/src/http2/http2_structures.h
+++ b/chromium/net/third_party/quiche/src/http2/http2_structures.h
@@ -29,11 +29,11 @@
#include <cstdint>
#include <ostream>
+#include <string>
#include "net/third_party/quiche/src/http2/http2_constants.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_export.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_logging.h"
-#include "net/third_party/quiche/src/http2/platform/api/http2_string.h"
namespace http2 {
@@ -106,8 +106,8 @@ struct HTTP2_EXPORT_PRIVATE Http2FrameHeader {
bool IsProbableHttpResponse() const;
// Produce strings useful for debugging/logging messages.
- Http2String ToString() const;
- Http2String FlagsToString() const;
+ std::string ToString() const;
+ std::string FlagsToString() const;
// 24 bit length of the payload after the header, including any padding.
// First field in encoding.
@@ -158,7 +158,7 @@ struct HTTP2_EXPORT_PRIVATE Http2PriorityFields {
static constexpr size_t EncodedSize() { return 5; }
// Produce strings useful for debugging/logging messages.
- Http2String ToString() const;
+ std::string ToString() const;
// A 31-bit stream identifier for the stream that this stream depends on.
uint32_t stream_dependency;
diff --git a/chromium/net/third_party/quiche/src/http2/http2_structures_test.cc b/chromium/net/third_party/quiche/src/http2/http2_structures_test.cc
index 9e38248b036..49032260056 100644
--- a/chromium/net/third_party/quiche/src/http2/http2_structures_test.cc
+++ b/chromium/net/third_party/quiche/src/http2/http2_structures_test.cc
@@ -14,6 +14,7 @@
#include <memory>
#include <ostream>
#include <sstream>
+#include <string>
#include <tuple>
#include <type_traits>
#include <vector>
@@ -171,7 +172,7 @@ INSTANTIATE_TEST_SUITE_P(IsEndStream,
TEST_P(IsEndStreamTest, IsEndStream) {
const bool is_set =
(flags_ & Http2FrameFlag::END_STREAM) == Http2FrameFlag::END_STREAM;
- Http2String flags_string;
+ std::string flags_string;
Http2FrameHeader v(0, type_, flags_, 0);
switch (type_) {
case Http2FrameType::DATA:
@@ -208,7 +209,7 @@ INSTANTIATE_TEST_SUITE_P(IsAck,
Values(~Http2FrameFlag::ACK, 0xff)));
TEST_P(IsACKTest, IsAck) {
const bool is_set = (flags_ & Http2FrameFlag::ACK) == Http2FrameFlag::ACK;
- Http2String flags_string;
+ std::string flags_string;
Http2FrameHeader v(0, type_, flags_, 0);
switch (type_) {
case Http2FrameType::SETTINGS:
@@ -246,7 +247,7 @@ INSTANTIATE_TEST_SUITE_P(IsEndHeaders,
TEST_P(IsEndHeadersTest, IsEndHeaders) {
const bool is_set =
(flags_ & Http2FrameFlag::END_HEADERS) == Http2FrameFlag::END_HEADERS;
- Http2String flags_string;
+ std::string flags_string;
Http2FrameHeader v(0, type_, flags_, 0);
switch (type_) {
case Http2FrameType::HEADERS:
@@ -287,7 +288,7 @@ INSTANTIATE_TEST_SUITE_P(IsPadded,
TEST_P(IsPaddedTest, IsPadded) {
const bool is_set =
(flags_ & Http2FrameFlag::PADDED) == Http2FrameFlag::PADDED;
- Http2String flags_string;
+ std::string flags_string;
Http2FrameHeader v(0, type_, flags_, 0);
switch (type_) {
case Http2FrameType::DATA:
@@ -326,7 +327,7 @@ INSTANTIATE_TEST_SUITE_P(HasPriority,
TEST_P(HasPriorityTest, HasPriority) {
const bool is_set =
(flags_ & Http2FrameFlag::PRIORITY) == Http2FrameFlag::PRIORITY;
- Http2String flags_string;
+ std::string flags_string;
Http2FrameHeader v(0, type_, flags_, 0);
switch (type_) {
case Http2FrameType::HEADERS:
diff --git a/chromium/net/third_party/quiche/src/http2/http2_structures_test_util.h b/chromium/net/third_party/quiche/src/http2/http2_structures_test_util.h
index 86fbf3f20af..77127a1ff3c 100644
--- a/chromium/net/third_party/quiche/src/http2/http2_structures_test_util.h
+++ b/chromium/net/third_party/quiche/src/http2/http2_structures_test_util.h
@@ -5,9 +5,10 @@
#ifndef QUICHE_HTTP2_HTTP2_STRUCTURES_TEST_UTIL_H_
#define QUICHE_HTTP2_HTTP2_STRUCTURES_TEST_UTIL_H_
+#include <string>
+
#include "testing/gtest/include/gtest/gtest.h"
#include "net/third_party/quiche/src/http2/http2_structures.h"
-#include "net/third_party/quiche/src/http2/platform/api/http2_string.h"
#include "net/third_party/quiche/src/http2/test_tools/http2_random.h"
#include "net/third_party/quiche/src/http2/tools/http2_frame_builder.h"
@@ -15,7 +16,7 @@ namespace http2 {
namespace test {
template <class S>
-Http2String SerializeStructure(const S& s) {
+std::string SerializeStructure(const S& s) {
Http2FrameBuilder fb;
fb.Append(s);
EXPECT_EQ(S::EncodedSize(), fb.size());
diff --git a/chromium/net/third_party/quiche/src/http2/platform/api/http2_string.h b/chromium/net/third_party/quiche/src/http2/platform/api/http2_string.h
deleted file mode 100644
index 25f9e593cc1..00000000000
--- a/chromium/net/third_party/quiche/src/http2/platform/api/http2_string.h
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright (c) 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef QUICHE_HTTP2_PLATFORM_API_HTTP2_STRING_H_
-#define QUICHE_HTTP2_PLATFORM_API_HTTP2_STRING_H_
-
-#include "net/http2/platform/impl/http2_string_impl.h"
-
-namespace http2 {
-
-using Http2String = Http2StringImpl;
-
-} // namespace http2
-
-#endif // QUICHE_HTTP2_PLATFORM_API_HTTP2_STRING_H_
diff --git a/chromium/net/third_party/quiche/src/http2/platform/api/http2_string_utils.h b/chromium/net/third_party/quiche/src/http2/platform/api/http2_string_utils.h
index ba4056051ee..1db9d66d7aa 100644
--- a/chromium/net/third_party/quiche/src/http2/platform/api/http2_string_utils.h
+++ b/chromium/net/third_party/quiche/src/http2/platform/api/http2_string_utils.h
@@ -5,48 +5,48 @@
#ifndef QUICHE_HTTP2_PLATFORM_API_HTTP2_STRING_UTILS_H_
#define QUICHE_HTTP2_PLATFORM_API_HTTP2_STRING_UTILS_H_
+#include <string>
#include <type_traits>
#include <utility>
-#include "net/third_party/quiche/src/http2/platform/api/http2_string.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_string_piece.h"
#include "net/http2/platform/impl/http2_string_utils_impl.h"
namespace http2 {
template <typename... Args>
-inline Http2String Http2StrCat(const Args&... args) {
+inline std::string Http2StrCat(const Args&... args) {
return Http2StrCatImpl(std::forward<const Args&>(args)...);
}
template <typename... Args>
-inline void Http2StrAppend(Http2String* output, const Args&... args) {
+inline void Http2StrAppend(std::string* output, const Args&... args) {
Http2StrAppendImpl(output, std::forward<const Args&>(args)...);
}
template <typename... Args>
-inline Http2String Http2StringPrintf(const Args&... args) {
+inline std::string Http2StringPrintf(const Args&... args) {
return Http2StringPrintfImpl(std::forward<const Args&>(args)...);
}
-inline Http2String Http2HexEncode(const void* bytes, size_t size) {
+inline std::string Http2HexEncode(const void* bytes, size_t size) {
return Http2HexEncodeImpl(bytes, size);
}
-inline Http2String Http2HexDecode(Http2StringPiece data) {
+inline std::string Http2HexDecode(Http2StringPiece data) {
return Http2HexDecodeImpl(data);
}
-inline Http2String Http2HexDump(Http2StringPiece data) {
+inline std::string Http2HexDump(Http2StringPiece data) {
return Http2HexDumpImpl(data);
}
-inline Http2String Http2HexEscape(Http2StringPiece data) {
+inline std::string Http2HexEscape(Http2StringPiece data) {
return Http2HexEscapeImpl(data);
}
template <typename Number>
-inline Http2String Http2Hex(Number number) {
+inline std::string Http2Hex(Number number) {
static_assert(std::is_integral<Number>::value, "Number has to be an int");
return Http2HexImpl(number);
}
diff --git a/chromium/net/third_party/quiche/src/http2/platform/api/http2_string_utils_test.cc b/chromium/net/third_party/quiche/src/http2/platform/api/http2_string_utils_test.cc
index 254f9d7d460..6ffc4b437cf 100644
--- a/chromium/net/third_party/quiche/src/http2/platform/api/http2_string_utils_test.cc
+++ b/chromium/net/third_party/quiche/src/http2/platform/api/http2_string_utils_test.cc
@@ -19,7 +19,7 @@ TEST(Http2StringUtilsTest, Http2StrCat) {
// Single string-like argument.
const char kFoo[] = "foo";
- const Http2String string_foo(kFoo);
+ const std::string string_foo(kFoo);
const Http2StringPiece stringpiece_foo(string_foo);
EXPECT_EQ("foo", Http2StrCat(kFoo));
EXPECT_EQ("foo", Http2StrCat(string_foo));
@@ -28,7 +28,7 @@ TEST(Http2StringUtilsTest, Http2StrCat) {
// Two string-like arguments.
const char kBar[] = "bar";
const Http2StringPiece stringpiece_bar(kBar);
- const Http2String string_bar(kBar);
+ const std::string string_bar(kBar);
EXPECT_EQ("foobar", Http2StrCat(kFoo, kBar));
EXPECT_EQ("foobar", Http2StrCat(kFoo, string_bar));
EXPECT_EQ("foobar", Http2StrCat(kFoo, stringpiece_bar));
@@ -72,13 +72,13 @@ TEST(Http2StringUtilsTest, Http2StrCat) {
TEST(Http2StringUtilsTest, Http2StrAppend) {
// No arguments on empty string.
- Http2String output;
+ std::string output;
Http2StrAppend(&output);
EXPECT_TRUE(output.empty());
// Single string-like argument.
const char kFoo[] = "foo";
- const Http2String string_foo(kFoo);
+ const std::string string_foo(kFoo);
const Http2StringPiece stringpiece_foo(string_foo);
Http2StrAppend(&output, kFoo);
EXPECT_EQ("foo", output);
@@ -96,7 +96,7 @@ TEST(Http2StringUtilsTest, Http2StrAppend) {
// Two string-like arguments.
const char kBar[] = "bar";
const Http2StringPiece stringpiece_bar(kBar);
- const Http2String string_bar(kBar);
+ const std::string string_bar(kBar);
Http2StrAppend(&output, kFoo, kBar);
EXPECT_EQ("foobar", output);
Http2StrAppend(&output, kFoo, string_bar);
diff --git a/chromium/net/third_party/quiche/src/http2/test_tools/frame_parts.cc b/chromium/net/third_party/quiche/src/http2/test_tools/frame_parts.cc
index d5507882da9..d9dffa146e2 100644
--- a/chromium/net/third_party/quiche/src/http2/test_tools/frame_parts.cc
+++ b/chromium/net/third_party/quiche/src/http2/test_tools/frame_parts.cc
@@ -507,7 +507,7 @@ AssertionResult FrameParts::InPaddedFrame() {
}
AssertionResult FrameParts::AppendString(Http2StringPiece source,
- Http2String* target,
+ std::string* target,
Http2Optional<size_t>* opt_length) {
target->append(source.data(), source.size());
if (opt_length != nullptr) {
diff --git a/chromium/net/third_party/quiche/src/http2/test_tools/frame_parts.h b/chromium/net/third_party/quiche/src/http2/test_tools/frame_parts.h
index 5a7d872e893..598a6878bff 100644
--- a/chromium/net/third_party/quiche/src/http2/test_tools/frame_parts.h
+++ b/chromium/net/third_party/quiche/src/http2/test_tools/frame_parts.h
@@ -13,6 +13,7 @@
#include <stddef.h>
#include <cstdint>
+#include <string>
#include <vector>
#include "testing/gtest/include/gtest/gtest.h"
@@ -21,7 +22,6 @@
#include "net/third_party/quiche/src/http2/http2_structures.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_logging.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_optional.h"
-#include "net/third_party/quiche/src/http2/platform/api/http2_string.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_string_piece.h"
namespace http2 {
@@ -208,15 +208,15 @@ class FrameParts : public Http2FrameDecoderListener {
// the optional has a value (i.e. that the necessary On*Start method has been
// called), and that target is not longer than opt_length->value().
::testing::AssertionResult AppendString(Http2StringPiece source,
- Http2String* target,
+ std::string* target,
Http2Optional<size_t>* opt_length);
const Http2FrameHeader frame_header_;
- Http2String payload_;
- Http2String padding_;
- Http2String altsvc_origin_;
- Http2String altsvc_value_;
+ std::string payload_;
+ std::string padding_;
+ std::string altsvc_origin_;
+ std::string altsvc_value_;
Http2Optional<Http2PriorityFields> opt_priority_;
Http2Optional<Http2ErrorCode> opt_rst_stream_error_code_;
diff --git a/chromium/net/third_party/quiche/src/http2/test_tools/http2_random.cc b/chromium/net/third_party/quiche/src/http2/test_tools/http2_random.cc
index 81c036679dd..6b61a583fed 100644
--- a/chromium/net/third_party/quiche/src/http2/test_tools/http2_random.cc
+++ b/chromium/net/third_party/quiche/src/http2/test_tools/http2_random.cc
@@ -17,12 +17,12 @@ Http2Random::Http2Random() {
}
Http2Random::Http2Random(Http2StringPiece key) {
- Http2String decoded_key = Http2HexDecode(key);
+ std::string decoded_key = Http2HexDecode(key);
CHECK_EQ(sizeof(key_), decoded_key.size());
memcpy(key_, decoded_key.data(), sizeof(key_));
}
-Http2String Http2Random::Key() const {
+std::string Http2Random::Key() const {
return Http2HexEncode(key_, sizeof(key_));
}
@@ -33,8 +33,8 @@ void Http2Random::FillRandom(void* buffer, size_t buffer_size) {
counter_++);
}
-Http2String Http2Random::RandString(int length) {
- Http2String result;
+std::string Http2Random::RandString(int length) {
+ std::string result;
result.resize(length);
FillRandom(&result[0], length);
return result;
@@ -58,9 +58,9 @@ double Http2Random::RandDouble() {
return value.f - 1.0;
}
-Http2String Http2Random::RandStringWithAlphabet(int length,
+std::string Http2Random::RandStringWithAlphabet(int length,
Http2StringPiece alphabet) {
- Http2String result;
+ std::string result;
result.resize(length);
for (int i = 0; i < length; i++) {
result[i] = alphabet[Uniform(alphabet.size())];
diff --git a/chromium/net/third_party/quiche/src/http2/test_tools/http2_random.h b/chromium/net/third_party/quiche/src/http2/test_tools/http2_random.h
index def60f8665d..774212cb5e9 100644
--- a/chromium/net/third_party/quiche/src/http2/test_tools/http2_random.h
+++ b/chromium/net/third_party/quiche/src/http2/test_tools/http2_random.h
@@ -9,8 +9,8 @@
#include <cstdint>
#include <limits>
#include <random>
+#include <string>
-#include "net/third_party/quiche/src/http2/platform/api/http2_string.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_string_piece.h"
namespace http2 {
@@ -29,10 +29,10 @@ class Http2Random {
// Reproducible random number generation: by using the same key, the same
// sequence of results is obtained.
explicit Http2Random(Http2StringPiece key);
- Http2String Key() const;
+ std::string Key() const;
void FillRandom(void* buffer, size_t buffer_size);
- Http2String RandString(int length);
+ std::string RandString(int length);
// Returns a random 64-bit value.
uint64_t Rand64();
@@ -67,7 +67,7 @@ class Http2Random {
// Return a random string consisting of the characters from the specified
// alphabet.
- Http2String RandStringWithAlphabet(int length, Http2StringPiece alphabet);
+ std::string RandStringWithAlphabet(int length, Http2StringPiece alphabet);
// STL UniformRandomNumberGenerator implementation.
using result_type = uint64_t;
diff --git a/chromium/net/third_party/quiche/src/http2/test_tools/http2_random_test.cc b/chromium/net/third_party/quiche/src/http2/test_tools/http2_random_test.cc
index a1b74f64a7b..c9490bdb2ba 100644
--- a/chromium/net/third_party/quiche/src/http2/test_tools/http2_random_test.cc
+++ b/chromium/net/third_party/quiche/src/http2/test_tools/http2_random_test.cc
@@ -43,9 +43,9 @@ TEST(Http2RandomTest, ReproducibleRandom) {
TEST(Http2RandomTest, STLShuffle) {
Http2Random random;
- const Http2String original = "abcdefghijklmonpqrsuvwxyz";
+ const std::string original = "abcdefghijklmonpqrsuvwxyz";
- Http2String shuffled = original;
+ std::string shuffled = original;
std::shuffle(shuffled.begin(), shuffled.end(), random);
EXPECT_NE(original, shuffled);
}
@@ -61,7 +61,7 @@ TEST(Http2RandomTest, RandFloat) {
TEST(Http2RandomTest, RandStringWithAlphabet) {
Http2Random random;
- Http2String str = random.RandStringWithAlphabet(1000, "xyz");
+ std::string str = random.RandStringWithAlphabet(1000, "xyz");
EXPECT_EQ(1000u, str.size());
std::set<char> characters(str.begin(), str.end());
diff --git a/chromium/net/third_party/quiche/src/http2/tools/http2_frame_builder.h b/chromium/net/third_party/quiche/src/http2/tools/http2_frame_builder.h
index c36cb56e48a..70d5f44415d 100644
--- a/chromium/net/third_party/quiche/src/http2/tools/http2_frame_builder.h
+++ b/chromium/net/third_party/quiche/src/http2/tools/http2_frame_builder.h
@@ -16,10 +16,10 @@
#include <stddef.h> // for size_t
#include <cstdint>
+#include <string>
#include "net/third_party/quiche/src/http2/http2_constants.h"
#include "net/third_party/quiche/src/http2/http2_structures.h"
-#include "net/third_party/quiche/src/http2/platform/api/http2_string.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_string_piece.h"
namespace http2 {
@@ -33,7 +33,7 @@ class Http2FrameBuilder {
~Http2FrameBuilder() {}
size_t size() const { return buffer_.size(); }
- const Http2String& buffer() const { return buffer_; }
+ const std::string& buffer() const { return buffer_; }
//----------------------------------------------------------------------------
// Methods for appending to the end of the buffer.
@@ -92,7 +92,7 @@ class Http2FrameBuilder {
size_t SetPayloadLength();
private:
- Http2String buffer_;
+ std::string buffer_;
};
} // namespace test
diff --git a/chromium/net/third_party/quiche/src/http2/tools/random_decoder_test.h b/chromium/net/third_party/quiche/src/http2/tools/random_decoder_test.h
index f162ad79ad9..ef31d01e455 100644
--- a/chromium/net/third_party/quiche/src/http2/tools/random_decoder_test.h
+++ b/chromium/net/third_party/quiche/src/http2/tools/random_decoder_test.h
@@ -21,7 +21,6 @@
#include "net/third_party/quiche/src/http2/decoder/decode_buffer.h"
#include "net/third_party/quiche/src/http2/decoder/decode_status.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_logging.h"
-#include "net/third_party/quiche/src/http2/platform/api/http2_string.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_string_piece.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_test_helpers.h"
#include "net/third_party/quiche/src/http2/test_tools/http2_random.h"
diff --git a/chromium/net/third_party/quiche/src/http2/tools/random_util.cc b/chromium/net/third_party/quiche/src/http2/tools/random_util.cc
index 82c3edd4063..a7d95c4f053 100644
--- a/chromium/net/third_party/quiche/src/http2/tools/random_util.cc
+++ b/chromium/net/third_party/quiche/src/http2/tools/random_util.cc
@@ -11,7 +11,7 @@ namespace test {
// Here "word" means something that starts with a lower-case letter, and has
// zero or more additional characters that are numbers or lower-case letters.
-Http2String GenerateHttp2HeaderName(size_t len, Http2Random* rng) {
+std::string GenerateHttp2HeaderName(size_t len, Http2Random* rng) {
Http2StringPiece alpha_lc = "abcdefghijklmnopqrstuvwxyz";
// If the name is short, just make it one word.
if (len < 8) {
@@ -25,13 +25,13 @@ Http2String GenerateHttp2HeaderName(size_t len, Http2Random* rng) {
rng->RandStringWithAlphabet(len - 4, alphanumdash_lc);
}
-Http2String GenerateWebSafeString(size_t len, Http2Random* rng) {
+std::string GenerateWebSafeString(size_t len, Http2Random* rng) {
static const char* kWebsafe64 =
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_";
return rng->RandStringWithAlphabet(len, kWebsafe64);
}
-Http2String GenerateWebSafeString(size_t lo, size_t hi, Http2Random* rng) {
+std::string GenerateWebSafeString(size_t lo, size_t hi, Http2Random* rng) {
return GenerateWebSafeString(rng->UniformInRange(lo, hi), rng);
}
diff --git a/chromium/net/third_party/quiche/src/http2/tools/random_util.h b/chromium/net/third_party/quiche/src/http2/tools/random_util.h
index a2107b7c7c9..6e721890650 100644
--- a/chromium/net/third_party/quiche/src/http2/tools/random_util.h
+++ b/chromium/net/third_party/quiche/src/http2/tools/random_util.h
@@ -7,7 +7,8 @@
#include <stddef.h>
-#include "net/third_party/quiche/src/http2/platform/api/http2_string.h"
+#include <string>
+
#include "net/third_party/quiche/src/http2/test_tools/http2_random.h"
namespace http2 {
@@ -15,13 +16,13 @@ namespace test {
// Generate a string with the allowed character set for HTTP/2 / HPACK header
// names.
-Http2String GenerateHttp2HeaderName(size_t len, Http2Random* rng);
+std::string GenerateHttp2HeaderName(size_t len, Http2Random* rng);
// Generate a string with the web-safe string character set of specified len.
-Http2String GenerateWebSafeString(size_t len, Http2Random* rng);
+std::string GenerateWebSafeString(size_t len, Http2Random* rng);
// Generate a string with the web-safe string character set of length [lo, hi).
-Http2String GenerateWebSafeString(size_t lo, size_t hi, Http2Random* rng);
+std::string GenerateWebSafeString(size_t lo, size_t hi, Http2Random* rng);
} // namespace test
} // namespace http2
diff --git a/chromium/net/third_party/quiche/src/quic/core/chlo_extractor.cc b/chromium/net/third_party/quiche/src/quic/core/chlo_extractor.cc
index 0e8e6f57402..38e97bd15fe 100644
--- a/chromium/net/third_party/quiche/src/quic/core/chlo_extractor.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/chlo_extractor.cc
@@ -44,6 +44,9 @@ class ChloFramerVisitor : public QuicFramerVisitorInterface,
void OnDecryptedPacket(EncryptionLevel /*level*/) override {}
bool OnPacketHeader(const QuicPacketHeader& header) override;
void OnCoalescedPacket(const QuicEncryptedPacket& packet) override;
+ void OnUndecryptablePacket(const QuicEncryptedPacket& packet,
+ EncryptionLevel decryption_level,
+ bool has_decryption_key) override;
bool OnStreamFrame(const QuicStreamFrame& frame) override;
bool OnCryptoFrame(const QuicCryptoFrame& frame) override;
bool OnAckFrameStart(QuicPacketNumber largest_acked,
@@ -142,8 +145,15 @@ bool ChloFramerVisitor::OnUnauthenticatedHeader(
bool ChloFramerVisitor::OnPacketHeader(const QuicPacketHeader& /*header*/) {
return true;
}
+
void ChloFramerVisitor::OnCoalescedPacket(
const QuicEncryptedPacket& /*packet*/) {}
+
+void ChloFramerVisitor::OnUndecryptablePacket(
+ const QuicEncryptedPacket& /*packet*/,
+ EncryptionLevel /*decryption_level*/,
+ bool /*has_decryption_key*/) {}
+
bool ChloFramerVisitor::OnStreamFrame(const QuicStreamFrame& frame) {
if (QuicVersionUsesCryptoFrames(framer_->transport_version())) {
// CHLO will be sent in CRYPTO frames in v47 and above.
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 11a625c768c..0311191d641 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
@@ -6,13 +6,49 @@
#include <algorithm>
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
namespace quic {
-BandwidthSampler::BandwidthSampler()
+
+QuicByteCount MaxAckHeightTracker::Update(QuicBandwidth bandwidth_estimate,
+ QuicRoundTripCount round_trip_count,
+ QuicTime ack_time,
+ QuicByteCount bytes_acked) {
+ if (aggregation_epoch_start_time_ == QuicTime::Zero()) {
+ aggregation_epoch_bytes_ = bytes_acked;
+ aggregation_epoch_start_time_ = ack_time;
+ 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_);
+ // Reset the current aggregation epoch as soon as the ack arrival rate is less
+ // than or equal to the max bandwidth.
+ if (aggregation_epoch_bytes_ <= expected_bytes_acked) {
+ // Reset to start measuring a new aggregation epoch.
+ aggregation_epoch_bytes_ = bytes_acked;
+ aggregation_epoch_start_time_ = ack_time;
+ return 0;
+ }
+
+ aggregation_epoch_bytes_ += bytes_acked;
+
+ // Compute how many extra bytes were delivered vs max bandwidth.
+ QuicByteCount extra_bytes_acked =
+ aggregation_epoch_bytes_ - expected_bytes_acked;
+ max_ack_height_filter_.Update(extra_bytes_acked, round_trip_count);
+ return extra_bytes_acked;
+}
+
+BandwidthSampler::BandwidthSampler(
+ const QuicUnackedPacketMap* unacked_packet_map,
+ QuicRoundTripCount max_height_tracker_window_length)
: total_bytes_sent_(0),
total_bytes_acked_(0),
total_bytes_lost_(0),
@@ -21,7 +57,16 @@ BandwidthSampler::BandwidthSampler()
last_acked_packet_ack_time_(QuicTime::Zero()),
is_app_limited_(false),
connection_state_map_(),
- max_tracked_packets_(GetQuicFlag(FLAGS_quic_max_tracked_packet_count)) {}
+ max_tracked_packets_(GetQuicFlag(FLAGS_quic_max_tracked_packet_count)),
+ unacked_packet_map_(unacked_packet_map),
+ max_ack_height_tracker_(max_height_tracker_window_length),
+ total_bytes_acked_after_last_ack_event_(0),
+ quic_track_ack_height_in_bandwidth_sampler_(
+ GetQuicReloadableFlag(quic_track_ack_height_in_bandwidth_sampler2)) {
+ if (quic_track_ack_height_in_bandwidth_sampler_) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_track_ack_height_in_bandwidth_sampler2);
+ }
+}
BandwidthSampler::~BandwidthSampler() {}
@@ -57,9 +102,18 @@ void BandwidthSampler::OnPacketSent(
if (!connection_state_map_.IsEmpty() &&
packet_number >
connection_state_map_.last_packet() + max_tracked_packets_) {
- QUIC_BUG << "BandwidthSampler in-flight packet map has exceeded maximum "
- "number "
- "of tracked packets.";
+ if (unacked_packet_map_ != nullptr) {
+ QUIC_BUG << "BandwidthSampler in-flight packet map has exceeded maximum "
+ "number of tracked packets. First tracked: "
+ << connection_state_map_.first_packet()
+ << "; last tracked: " << connection_state_map_.last_packet()
+ << "; least unacked: " << unacked_packet_map_->GetLeastUnacked()
+ << "; largest observed: "
+ << unacked_packet_map_->largest_acked();
+ } else {
+ QUIC_BUG << "BandwidthSampler in-flight packet map has exceeded maximum "
+ "number of tracked packets.";
+ }
}
bool success =
@@ -69,6 +123,22 @@ void BandwidthSampler::OnPacketSent(
"in it.";
}
+QuicByteCount BandwidthSampler::OnAckEventEnd(
+ QuicBandwidth bandwidth_estimate,
+ QuicRoundTripCount round_trip_count) {
+ const QuicByteCount newly_acked_bytes =
+ total_bytes_acked_ - total_bytes_acked_after_last_ack_event_;
+
+ if (newly_acked_bytes == 0) {
+ return 0;
+ }
+ total_bytes_acked_after_last_ack_event_ = total_bytes_acked_;
+
+ return max_ack_height_tracker_.Update(bandwidth_estimate, round_trip_count,
+ last_acked_packet_ack_time_,
+ newly_acked_bytes);
+}
+
BandwidthSample BandwidthSampler::OnPacketAcknowledged(
QuicTime ack_time,
QuicPacketNumber packet_number) {
@@ -96,7 +166,8 @@ BandwidthSample BandwidthSampler::OnPacketAcknowledgedInner(
// Exit app-limited phase once a packet that was sent while the connection is
// not app-limited is acknowledged.
- if (is_app_limited_ && packet_number > end_of_app_limited_phase_) {
+ if (is_app_limited_ && end_of_app_limited_phase_.IsInitialized() &&
+ packet_number > end_of_app_limited_phase_) {
is_app_limited_ = false;
}
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 9a58cf6e8de..8b279c61e32 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
@@ -5,11 +5,14 @@
#ifndef QUICHE_QUIC_CORE_CONGESTION_CONTROL_BANDWIDTH_SAMPLER_H_
#define QUICHE_QUIC_CORE_CONGESTION_CONTROL_BANDWIDTH_SAMPLER_H_
+#include "net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.h"
+#include "net/third_party/quiche/src/quic/core/congestion_control/windowed_filter.h"
#include "net/third_party/quiche/src/quic/core/packet_number_indexed_queue.h"
#include "net/third_party/quiche/src/quic/core/quic_bandwidth.h"
#include "net/third_party/quiche/src/quic/core/quic_packets.h"
#include "net/third_party/quiche/src/quic/core/quic_time.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/core/quic_unacked_packet_map.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
namespace quic {
@@ -75,6 +78,43 @@ struct QUIC_EXPORT_PRIVATE BandwidthSample {
: bandwidth(QuicBandwidth::Zero()), rtt(QuicTime::Delta::Zero()) {}
};
+// MaxAckHeightTracker is part of the BandwidthSampler. It is called after every
+// ack event to keep track the degree of ack aggregation(a.k.a "ack height").
+class QUIC_EXPORT_PRIVATE MaxAckHeightTracker {
+ public:
+ explicit MaxAckHeightTracker(QuicRoundTripCount initial_filter_window)
+ : max_ack_height_filter_(initial_filter_window, 0, 0) {}
+
+ QuicByteCount Get() const { return max_ack_height_filter_.GetBest(); }
+
+ QuicByteCount Update(QuicBandwidth bandwidth_estimate,
+ QuicRoundTripCount round_trip_count,
+ 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);
+ }
+
+ private:
+ // Tracks the maximum number of bytes acked faster than the estimated
+ // bandwidth.
+ typedef WindowedFilter<QuicByteCount,
+ MaxFilter<QuicByteCount>,
+ QuicRoundTripCount,
+ QuicRoundTripCount>
+ MaxAckHeightFilter;
+ 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;
+};
+
// An interface common to any class that can provide bandwidth samples from the
// information per individual acknowledged packet.
class QUIC_EXPORT_PRIVATE BandwidthSamplerInterface {
@@ -204,7 +244,8 @@ class QUIC_EXPORT_PRIVATE BandwidthSamplerInterface {
// connection is app-limited, the approach works in other cases too.
class QUIC_EXPORT_PRIVATE BandwidthSampler : public BandwidthSamplerInterface {
public:
- BandwidthSampler();
+ BandwidthSampler(const QuicUnackedPacketMap* unacked_packet_map,
+ QuicRoundTripCount max_height_tracker_window_length);
~BandwidthSampler() override;
void OnPacketSent(QuicTime sent_time,
@@ -214,6 +255,8 @@ class QUIC_EXPORT_PRIVATE BandwidthSampler : public BandwidthSamplerInterface {
HasRetransmittableData has_retransmittable_data) override;
BandwidthSample OnPacketAcknowledged(QuicTime ack_time,
QuicPacketNumber packet_number) override;
+ QuicByteCount OnAckEventEnd(QuicBandwidth bandwidth_estimate,
+ QuicRoundTripCount round_trip_count);
SendTimeState OnPacketLost(QuicPacketNumber packet_number) override;
void OnAppLimited() override;
@@ -228,6 +271,21 @@ class QUIC_EXPORT_PRIVATE BandwidthSampler : public BandwidthSamplerInterface {
QuicPacketNumber end_of_app_limited_phase() const override;
+ QuicByteCount max_ack_height() const { return max_ack_height_tracker_.Get(); }
+
+ void SetMaxAckHeightTrackerWindowLength(QuicRoundTripCount length) {
+ max_ack_height_tracker_.SetFilterWindowLength(length);
+ }
+
+ void ResetMaxAckHeightTracker(QuicByteCount new_height,
+ QuicRoundTripCount new_time) {
+ max_ack_height_tracker_.Reset(new_height, new_time);
+ }
+
+ bool quic_track_ack_height_in_bandwidth_sampler() const {
+ return quic_track_ack_height_in_bandwidth_sampler_;
+ }
+
private:
friend class test::BandwidthSamplerPeer;
@@ -327,12 +385,23 @@ class QUIC_EXPORT_PRIVATE BandwidthSampler : public BandwidthSamplerInterface {
// Maximum number of tracked packets.
const QuicPacketCount max_tracked_packets_;
+ // The main unacked packet map. Used for outputting extra debugging details.
+ // May be null.
+ // TODO(vasilvv): remove this once it's no longer useful for debugging.
+ const QuicUnackedPacketMap* unacked_packet_map_;
+
// Handles the actual bandwidth calculations, whereas the outer method handles
// retrieving and removing |sent_packet|.
BandwidthSample OnPacketAcknowledgedInner(
QuicTime ack_time,
QuicPacketNumber packet_number,
const ConnectionStateOnSentPacket& sent_packet);
+
+ MaxAckHeightTracker max_ack_height_tracker_;
+ QuicByteCount total_bytes_acked_after_last_ack_event_;
+
+ // Latched value of --quic_track_ack_height_in_bandwidth_sampler2.
+ const bool quic_track_ack_height_in_bandwidth_sampler_;
};
} // 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 750b14e6922..aeff9762f0e 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
@@ -32,7 +32,9 @@ static_assert((kRegularPacketSize & 31) == 0,
// A test fixture with utility methods for BandwidthSampler tests.
class BandwidthSamplerTest : public QuicTest {
protected:
- BandwidthSamplerTest() : bytes_in_flight_(0) {
+ BandwidthSamplerTest()
+ : sampler_(nullptr, /*max_height_tracker_window_length=*/0),
+ bytes_in_flight_(0) {
// Ensure that the clock does not start at zero.
clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
}
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 f5e3d188e6a..a527417a19d 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
@@ -15,8 +15,6 @@ namespace {
// Sensitivity in response to losses. 0 means no loss response.
// 0.3 is also used by TCP bbr and cubic.
const float kBeta = 0.3;
-
-const QuicTime::Delta kMinRttExpiry = QuicTime::Delta::FromSeconds(10);
} // namespace
RoundTripCounter::RoundTripCounter() : round_trip_count_(0) {}
@@ -79,42 +77,14 @@ const SendTimeState& SendStateOfLargestPacket(
return last_acked_sample.bandwidth_sample.state_at_send;
}
-QuicByteCount Bbr2MaxAckHeightTracker::Update(
- const QuicBandwidth& bandwidth_estimate,
- QuicRoundTripCount round_trip_count,
- QuicTime ack_time,
- QuicByteCount bytes_acked) {
- // TODO(wub): Find out whether TCP adds bytes_acked before or after the check.
- aggregation_epoch_bytes_ += bytes_acked;
-
- // 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_);
- // Reset the current aggregation epoch as soon as the ack arrival rate is less
- // than or equal to the max bandwidth.
- if (aggregation_epoch_bytes_ <= expected_bytes_acked) {
- // Reset to start measuring a new aggregation epoch.
- aggregation_epoch_bytes_ = bytes_acked;
- aggregation_epoch_start_time_ = ack_time;
- return 0;
- }
-
- // Compute how many extra bytes were delivered vs max bandwidth.
- QuicByteCount extra_bytes_acked =
- aggregation_epoch_bytes_ - expected_bytes_acked;
- max_ack_height_filter_.Update(extra_bytes_acked, round_trip_count);
- return extra_bytes_acked;
-}
-
Bbr2NetworkModel::Bbr2NetworkModel(const Bbr2Params* params,
QuicTime::Delta initial_rtt,
QuicTime initial_rtt_timestamp,
float cwnd_gain,
float pacing_gain)
: params_(params),
+ bandwidth_sampler_(nullptr, params->initial_max_ack_height_filter_window),
min_rtt_filter_(initial_rtt, initial_rtt_timestamp),
- max_ack_height_tracker_(params->initial_max_ack_height_filter_window),
cwnd_gain_(cwnd_gain),
pacing_gain_(pacing_gain) {}
@@ -200,8 +170,7 @@ void Bbr2NetworkModel::OnCongestionEventStart(
congestion_event->bytes_lost = total_bytes_lost() - prior_bytes_lost;
bytes_lost_in_round_ += congestion_event->bytes_lost;
- max_ack_height_tracker_.Update(BandwidthEstimate(), RoundTripCount(),
- event_time, congestion_event->bytes_acked);
+ bandwidth_sampler_.OnAckEventEnd(BandwidthEstimate(), RoundTripCount());
if (!congestion_event->end_of_round_trip) {
return;
@@ -264,7 +233,8 @@ void Bbr2NetworkModel::UpdateNetworkParameters(QuicBandwidth bandwidth,
bool Bbr2NetworkModel::MaybeExpireMinRtt(
const Bbr2CongestionEvent& congestion_event) {
- if (congestion_event.event_time < (MinRttTimestamp() + kMinRttExpiry)) {
+ if (congestion_event.event_time <
+ (MinRttTimestamp() + Params().probe_rtt_period)) {
return false;
}
if (congestion_event.sample_min_rtt.IsInfinite()) {
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 1b695e35314..4ad351e32cd 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
@@ -15,12 +15,11 @@
#include "net/third_party/quiche/src/quic/core/quic_time.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
#include "net/quic/platform/impl/quic_export_impl.h"
namespace quic {
-typedef uint64_t QuicRoundTripCount;
-
template <typename T>
class QUIC_EXPORT_PRIVATE Limits {
public:
@@ -88,7 +87,8 @@ struct QUIC_EXPORT_PRIVATE Bbr2Params {
QuicRoundTripCount startup_full_bw_rounds = 3;
// The minimum number of loss marking events to exit STARTUP.
- int64_t startup_full_loss_count = 8;
+ int64_t startup_full_loss_count =
+ GetQuicFlag(FLAGS_quic_bbr2_default_startup_full_loss_count);
/*
* DRAIN parameters.
@@ -111,11 +111,13 @@ struct QUIC_EXPORT_PRIVATE Bbr2Params {
// Minimum duration for BBR-native probes.
QuicTime::Delta probe_bw_probe_base_duration =
- QuicTime::Delta::FromSeconds(2);
+ QuicTime::Delta::FromMilliseconds(
+ GetQuicFlag(FLAGS_quic_bbr2_default_probe_bw_base_duration_ms));
- // The upper bound of the random amound of BBR-native probes.
+ // The upper bound of the random amount of BBR-native probes.
QuicTime::Delta probe_bw_probe_max_rand_duration =
- QuicTime::Delta::FromSeconds(1);
+ QuicTime::Delta::FromMilliseconds(
+ GetQuicFlag(FLAGS_quic_bbr2_default_probe_bw_max_rand_duration_ms));
// Multiplier to get target inflight (as multiple of BDP) for PROBE_UP phase.
float probe_bw_probe_inflight_gain = 1.25;
@@ -131,6 +133,8 @@ struct QUIC_EXPORT_PRIVATE Bbr2Params {
* PROBE_RTT parameters.
*/
float probe_rtt_inflight_target_bdp_fraction = 0.5;
+ QuicTime::Delta probe_rtt_period = QuicTime::Delta::FromMilliseconds(
+ GetQuicFlag(FLAGS_quic_bbr2_default_probe_rtt_period_ms));
QuicTime::Delta probe_rtt_duration = QuicTime::Delta::FromMilliseconds(200);
/*
@@ -144,7 +148,7 @@ struct QUIC_EXPORT_PRIVATE Bbr2Params {
float inflight_hi_headroom = 0.15;
// Estimate startup/bw probing has gone too far if loss rate exceeds this.
- float loss_threshold = 0.02;
+ float loss_threshold = GetQuicFlag(FLAGS_quic_bbr2_default_loss_threshold);
Limits<QuicByteCount> cwnd_limits;
};
@@ -267,32 +271,6 @@ struct QUIC_EXPORT_PRIVATE Bbr2CongestionEvent {
QUIC_EXPORT_PRIVATE const SendTimeState& SendStateOfLargestPacket(
const Bbr2CongestionEvent& congestion_event);
-class QUIC_EXPORT_PRIVATE Bbr2MaxAckHeightTracker {
- public:
- explicit Bbr2MaxAckHeightTracker(QuicRoundTripCount initial_filter_window)
- : max_ack_height_filter_(initial_filter_window, 0, 0) {}
-
- QuicByteCount Get() const { return max_ack_height_filter_.GetBest(); }
-
- QuicByteCount Update(const QuicBandwidth& bandwidth_estimate,
- QuicRoundTripCount round_trip_count,
- QuicTime ack_time,
- QuicByteCount bytes_acked);
-
- private:
- // Tracks the maximum number of bytes acked faster than the sending rate.
- typedef WindowedFilter<QuicByteCount,
- MaxFilter<QuicByteCount>,
- QuicRoundTripCount,
- QuicRoundTripCount>
- MaxAckHeightFilter;
- 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;
-};
-
// Bbr2NetworkModel takes low level congestion signals(packets sent/acked/lost)
// as input and produces BBRv2 model parameters like inflight_(hi|lo),
// bandwidth_(hi|lo), bandwidth and rtt estimates, etc.
@@ -348,7 +326,9 @@ class QUIC_EXPORT_PRIVATE Bbr2NetworkModel {
QuicBandwidth MaxBandwidth() const { return max_bandwidth_filter_.Get(); }
- QuicByteCount MaxAckHeight() const { return max_ack_height_tracker_.Get(); }
+ QuicByteCount MaxAckHeight() const {
+ return bandwidth_sampler_.max_ack_height();
+ }
bool MaybeExpireMinRtt(const Bbr2CongestionEvent& congestion_event);
@@ -428,8 +408,6 @@ class QUIC_EXPORT_PRIVATE Bbr2NetworkModel {
Bbr2MaxBandwidthFilter max_bandwidth_filter_;
MinRttFilter min_rtt_filter_;
- Bbr2MaxAckHeightTracker max_ack_height_tracker_;
-
// Bytes lost in the current round. Updated once per congestion event.
QuicByteCount bytes_lost_in_round_ = 0;
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 66aa123d78a..9cd40b93621 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
@@ -69,8 +69,9 @@ Bbr2Sender::Bbr2Sender(QuicTime now,
rtt_stats->last_update_time(),
/*cwnd_gain=*/1.0,
/*pacing_gain=*/kInitialPacingGain),
- cwnd_(
+ initial_cwnd_(
cwnd_limits().ApplyLimits(initial_cwnd_in_packets * kDefaultTCPMSS)),
+ cwnd_(initial_cwnd_),
pacing_rate_(kInitialPacingGain * QuicBandwidth::FromBytesAndTimeDelta(
cwnd_,
rtt_stats->SmoothedOrInitialRtt())),
@@ -240,7 +241,7 @@ void Bbr2Sender::UpdateCongestionWindow(QuicByteCount bytes_acked) {
if (startup_.FullBandwidthReached()) {
target_cwnd += model_.MaxAckHeight();
cwnd_ = std::min(prior_cwnd + bytes_acked, target_cwnd);
- } else if (prior_cwnd < target_cwnd || prior_cwnd < 2 * cwnd_limits().Min()) {
+ } else if (prior_cwnd < target_cwnd || prior_cwnd < 2 * initial_cwnd_) {
cwnd_ = prior_cwnd + bytes_acked;
}
const QuicByteCount desired_cwnd = cwnd_;
diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_sender.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_sender.h
index 64f63477558..b58dd93e271 100644
--- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_sender.h
+++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_sender.h
@@ -161,6 +161,8 @@ class QUIC_EXPORT_PRIVATE Bbr2Sender final : public SendAlgorithmInterface {
Bbr2NetworkModel model_;
+ const QuicByteCount initial_cwnd_;
+
// Current cwnd and pacing rate.
QuicByteCount cwnd_;
QuicBandwidth pacing_rate_;
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 736327fc0d4..ab4b67b2bcc 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
@@ -426,13 +426,13 @@ TEST_F(Bbr2DefaultTopologyTest, BandwidthIncrease) {
sender_endpoint_.AddBytesToTransfer(20 * 1024 * 1024);
- simulator_.RunFor(QuicTime::Delta::FromSeconds(10));
+ 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.20);
+ 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);
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 65a637c1611..ae1432a1956 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
@@ -90,6 +90,7 @@ BbrSender::BbrSender(QuicTime now,
random_(random),
stats_(stats),
mode_(STARTUP),
+ sampler_(unacked_packets, kBandwidthWindowSize),
round_trip_count_(0),
max_bandwidth_(kBandwidthWindowSize, QuicBandwidth::Zero(), 0),
max_ack_height_(kBandwidthWindowSize, 0, 0),
@@ -174,8 +175,10 @@ void BbrSender::OnPacketSent(QuicTime sent_time,
exiting_quiescence_ = true;
}
- if (!aggregation_epoch_start_time_.IsInitialized()) {
- aggregation_epoch_start_time_ = sent_time;
+ if (!sampler_.quic_track_ack_height_in_bandwidth_sampler()) {
+ if (!aggregation_epoch_start_time_.IsInitialized()) {
+ aggregation_epoch_start_time_ = sent_time;
+ }
}
sampler_.OnPacketSent(sent_time, packet_number, bytes, bytes_in_flight,
@@ -284,10 +287,18 @@ void BbrSender::SetFromConfig(const QuicConfig& config,
startup_rate_reduction_multiplier_ = 2;
}
if (config.HasClientRequestedIndependentOption(kBBR4, perspective)) {
- max_ack_height_.SetWindowLength(2 * kBandwidthWindowSize);
+ if (sampler_.quic_track_ack_height_in_bandwidth_sampler()) {
+ sampler_.SetMaxAckHeightTrackerWindowLength(2 * kBandwidthWindowSize);
+ } else {
+ max_ack_height_.SetWindowLength(2 * kBandwidthWindowSize);
+ }
}
if (config.HasClientRequestedIndependentOption(kBBR5, perspective)) {
- max_ack_height_.SetWindowLength(4 * kBandwidthWindowSize);
+ if (sampler_.quic_track_ack_height_in_bandwidth_sampler()) {
+ sampler_.SetMaxAckHeightTrackerWindowLength(4 * kBandwidthWindowSize);
+ } else {
+ max_ack_height_.SetWindowLength(4 * kBandwidthWindowSize);
+ }
}
if (GetQuicReloadableFlag(quic_bbr_less_probe_rtt) &&
config.HasClientRequestedIndependentOption(kBBR6, perspective)) {
@@ -405,7 +416,10 @@ void BbrSender::OnCongestionEvent(bool /*rtt_updated*/,
const QuicByteCount bytes_acked =
sampler_.total_bytes_acked() - total_bytes_acked_before;
- excess_acked = UpdateAckAggregationBytes(event_time, bytes_acked);
+ excess_acked = sampler_.quic_track_ack_height_in_bandwidth_sampler()
+ ? sampler_.OnAckEventEnd(max_bandwidth_.GetBest(),
+ round_trip_count_)
+ : UpdateAckAggregationBytes(event_time, bytes_acked);
}
// Handle logic specific to PROBE_BW mode.
@@ -647,7 +661,11 @@ void BbrSender::CheckIfFullBandwidthReached() {
rounds_without_bandwidth_gain_ = 0;
if (expire_ack_aggregation_in_startup_) {
// Expire old excess delivery measurements now that bandwidth increased.
- max_ack_height_.Reset(0, round_trip_count_);
+ if (sampler_.quic_track_ack_height_in_bandwidth_sampler()) {
+ sampler_.ResetMaxAckHeightTracker(0, round_trip_count_);
+ } else {
+ max_ack_height_.Reset(0, round_trip_count_);
+ }
}
return;
}
@@ -847,7 +865,9 @@ void BbrSender::CalculateCongestionWindow(QuicByteCount bytes_acked,
GetTargetCongestionWindow(congestion_window_gain_);
if (is_at_full_bandwidth_) {
// Add the max recently measured ack aggregation to CWND.
- target_window += max_ack_height_.GetBest();
+ target_window += sampler_.quic_track_ack_height_in_bandwidth_sampler()
+ ? sampler_.max_ack_height()
+ : max_ack_height_.GetBest();
} else if (enable_ack_aggregation_during_startup_) {
// Add the most recent excess acked. Because CWND never decreases in
// STARTUP, this will automatically create a very localized max filter.
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 a4d9925b535..592893ef661 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
@@ -25,8 +25,6 @@ namespace quic {
class RttStats;
-typedef uint64_t QuicRoundTripCount;
-
// BbrSender implements BBR congestion control algorithm. BBR aims to estimate
// the current available Bottleneck Bandwidth and RTT (hence the name), and
// regulates the pacing rate and the size of the congestion window based on
diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.cc
index d42896cee57..356501f7f92 100644
--- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.cc
@@ -66,11 +66,7 @@ void GeneralLossAlgorithm::DetectLosses(
loss_detection_timeout_ = QuicTime::Zero();
if (!packets_acked.empty() &&
packets_acked.front().packet_number == least_in_flight_) {
- if (GetQuicReloadableFlag(quic_fix_packets_acked)) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_fix_packets_acked);
- }
- if ((!GetQuicReloadableFlag(quic_fix_packets_acked) ||
- packets_acked.back().packet_number == largest_newly_acked) &&
+ if (packets_acked.back().packet_number == largest_newly_acked &&
least_in_flight_ + packets_acked.size() - 1 == largest_newly_acked) {
// Optimization for the case when no packet is missing. Please note,
// packets_acked can include packets of different packet number space, so
diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm_test.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm_test.cc
index f2ebbb2a68b..4fdd05f20c5 100644
--- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm_test.cc
@@ -34,8 +34,9 @@ class GeneralLossAlgorithmTest : public QuicTest {
void SendDataPacket(uint64_t packet_number) {
QuicStreamFrame frame;
- frame.stream_id = QuicUtils::GetHeadersStreamId(
- CurrentSupportedVersions()[0].transport_version);
+ frame.stream_id = QuicUtils::GetFirstBidirectionalStreamId(
+ CurrentSupportedVersions()[0].transport_version,
+ Perspective::IS_CLIENT);
SerializedPacket packet(QuicPacketNumber(packet_number),
PACKET_1BYTE_PACKET_NUMBER, nullptr, kDefaultLength,
false, false);
diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/rtt_stats.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/rtt_stats.h
index 7b58276aa86..997faa402e8 100644
--- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/rtt_stats.h
+++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/rtt_stats.h
@@ -73,7 +73,10 @@ class QUIC_EXPORT_PRIVATE RttStats {
QuicTime::Delta mean_deviation() const { return mean_deviation_; }
- QuicTime::Delta max_ack_delay() const { return max_ack_delay_; }
+ QuicTime::Delta max_ack_delay() const {
+ DCHECK(!GetQuicReloadableFlag(quic_sent_packet_manager_cleanup));
+ return max_ack_delay_;
+ }
QuicTime last_update_time() const { return last_update_time_; }
@@ -101,6 +104,7 @@ class QUIC_EXPORT_PRIVATE RttStats {
QuicTime::Delta initial_rtt_;
// The maximum ack delay observed over the connection after excluding ack
// delays that were too large to be included in an RTT measurement.
+ // TODO(ianswett): Remove when deprecating quic_sent_packet_manager_cleanup.
QuicTime::Delta max_ack_delay_;
QuicTime last_update_time_;
// Whether to ignore the peer's max ack delay.
diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/rtt_stats_test.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/rtt_stats_test.cc
index 83cb15578a8..4d259d3b248 100644
--- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/rtt_stats_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/rtt_stats_test.cc
@@ -35,20 +35,28 @@ TEST_F(RttStatsTest, SmoothedRtt) {
QuicTime::Zero());
EXPECT_EQ(QuicTime::Delta::FromMilliseconds(300), rtt_stats_.latest_rtt());
EXPECT_EQ(QuicTime::Delta::FromMilliseconds(300), rtt_stats_.smoothed_rtt());
- EXPECT_EQ(QuicTime::Delta::Zero(), rtt_stats_.max_ack_delay());
+ if (!GetQuicReloadableFlag(quic_sent_packet_manager_cleanup)) {
+ EXPECT_EQ(QuicTime::Delta::Zero(), rtt_stats_.max_ack_delay());
+ }
// Verify that a plausible ack delay increases the max ack delay.
rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(400),
QuicTime::Delta::FromMilliseconds(100),
QuicTime::Zero());
EXPECT_EQ(QuicTime::Delta::FromMilliseconds(300), rtt_stats_.latest_rtt());
EXPECT_EQ(QuicTime::Delta::FromMilliseconds(300), rtt_stats_.smoothed_rtt());
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(100), rtt_stats_.max_ack_delay());
+ if (!GetQuicReloadableFlag(quic_sent_packet_manager_cleanup)) {
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(100),
+ rtt_stats_.max_ack_delay());
+ }
// Verify that Smoothed RTT includes max ack delay if it's reasonable.
rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(350),
QuicTime::Delta::FromMilliseconds(50), QuicTime::Zero());
EXPECT_EQ(QuicTime::Delta::FromMilliseconds(300), rtt_stats_.latest_rtt());
EXPECT_EQ(QuicTime::Delta::FromMilliseconds(300), rtt_stats_.smoothed_rtt());
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(100), rtt_stats_.max_ack_delay());
+ if (!GetQuicReloadableFlag(quic_sent_packet_manager_cleanup)) {
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(100),
+ rtt_stats_.max_ack_delay());
+ }
// Verify that large erroneous ack_delay does not change Smoothed RTT.
rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(200),
QuicTime::Delta::FromMilliseconds(300),
@@ -56,7 +64,10 @@ TEST_F(RttStatsTest, SmoothedRtt) {
EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.latest_rtt());
EXPECT_EQ(QuicTime::Delta::FromMicroseconds(287500),
rtt_stats_.smoothed_rtt());
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(100), rtt_stats_.max_ack_delay());
+ if (!GetQuicReloadableFlag(quic_sent_packet_manager_cleanup)) {
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(100),
+ rtt_stats_.max_ack_delay());
+ }
}
TEST_F(RttStatsTest, SmoothedRttIgnoreAckDelay) {
@@ -67,14 +78,18 @@ TEST_F(RttStatsTest, SmoothedRttIgnoreAckDelay) {
QuicTime::Zero());
EXPECT_EQ(QuicTime::Delta::FromMilliseconds(300), rtt_stats_.latest_rtt());
EXPECT_EQ(QuicTime::Delta::FromMilliseconds(300), rtt_stats_.smoothed_rtt());
- EXPECT_EQ(QuicTime::Delta::Zero(), rtt_stats_.max_ack_delay());
+ if (!GetQuicReloadableFlag(quic_sent_packet_manager_cleanup)) {
+ EXPECT_EQ(QuicTime::Delta::Zero(), rtt_stats_.max_ack_delay());
+ }
// Verify that a plausible ack delay increases the max ack delay.
rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(300),
QuicTime::Delta::FromMilliseconds(100),
QuicTime::Zero());
EXPECT_EQ(QuicTime::Delta::FromMilliseconds(300), rtt_stats_.latest_rtt());
EXPECT_EQ(QuicTime::Delta::FromMilliseconds(300), rtt_stats_.smoothed_rtt());
- EXPECT_EQ(QuicTime::Delta::Zero(), rtt_stats_.max_ack_delay());
+ if (!GetQuicReloadableFlag(quic_sent_packet_manager_cleanup)) {
+ EXPECT_EQ(QuicTime::Delta::Zero(), rtt_stats_.max_ack_delay());
+ }
// Verify that Smoothed RTT includes max ack delay if it's reasonable.
rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(300),
QuicTime::Delta::FromMilliseconds(50), QuicTime::Zero());
@@ -87,7 +102,9 @@ TEST_F(RttStatsTest, SmoothedRttIgnoreAckDelay) {
EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.latest_rtt());
EXPECT_EQ(QuicTime::Delta::FromMicroseconds(287500),
rtt_stats_.smoothed_rtt());
- EXPECT_EQ(QuicTime::Delta::Zero(), rtt_stats_.max_ack_delay());
+ if (!GetQuicReloadableFlag(quic_sent_packet_manager_cleanup)) {
+ EXPECT_EQ(QuicTime::Delta::Zero(), rtt_stats_.max_ack_delay());
+ }
}
// Ensure that the potential rounding artifacts in EWMA calculation do not cause
@@ -208,7 +225,9 @@ TEST_F(RttStatsTest, ResetAfterConnectionMigrations) {
EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.latest_rtt());
EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.smoothed_rtt());
EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.min_rtt());
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(0), rtt_stats_.max_ack_delay());
+ if (!GetQuicReloadableFlag(quic_sent_packet_manager_cleanup)) {
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(0), rtt_stats_.max_ack_delay());
+ }
rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(300),
QuicTime::Delta::FromMilliseconds(100),
@@ -216,14 +235,19 @@ TEST_F(RttStatsTest, ResetAfterConnectionMigrations) {
EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.latest_rtt());
EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.smoothed_rtt());
EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.min_rtt());
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(100), rtt_stats_.max_ack_delay());
+ if (!GetQuicReloadableFlag(quic_sent_packet_manager_cleanup)) {
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(100),
+ rtt_stats_.max_ack_delay());
+ }
// Reset rtt stats on connection migrations.
rtt_stats_.OnConnectionMigration();
EXPECT_EQ(QuicTime::Delta::Zero(), rtt_stats_.latest_rtt());
EXPECT_EQ(QuicTime::Delta::Zero(), rtt_stats_.smoothed_rtt());
EXPECT_EQ(QuicTime::Delta::Zero(), rtt_stats_.min_rtt());
- EXPECT_EQ(QuicTime::Delta::Zero(), rtt_stats_.max_ack_delay());
+ if (!GetQuicReloadableFlag(quic_sent_packet_manager_cleanup)) {
+ EXPECT_EQ(QuicTime::Delta::Zero(), rtt_stats_.max_ack_delay());
+ }
}
} // namespace test
diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.h
index 69f7455219c..dab8fc294a7 100644
--- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.h
+++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.h
@@ -24,6 +24,8 @@
namespace quic {
+typedef uint64_t QuicRoundTripCount;
+
class CachedNetworkParameters;
class RttStats;
diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm_test.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm_test.cc
index 0c79ac55352..84b9c993ced 100644
--- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm_test.cc
@@ -32,7 +32,8 @@ class UberLossAlgorithmTest : public QuicTest {
QuicStreamFrame frame;
QuicTransportVersion version =
CurrentSupportedVersions()[0].transport_version;
- frame.stream_id = QuicUtils::GetHeadersStreamId(version);
+ frame.stream_id = QuicUtils::GetFirstBidirectionalStreamId(
+ version, Perspective::IS_CLIENT);
if (encryption_level == ENCRYPTION_INITIAL) {
if (QuicVersionUsesCryptoFrames(version)) {
frame.stream_id = QuicUtils::GetFirstBidirectionalStreamId(
@@ -183,13 +184,8 @@ TEST_F(UberLossAlgorithmTest, PacketInLimbo) {
AckPackets({5, 6});
unacked_packets_->MaybeUpdateLargestAckedOfPacketNumberSpace(
APPLICATION_DATA, QuicPacketNumber(6));
- if (GetQuicReloadableFlag(quic_fix_packets_acked)) {
- // Verify packet 2 is detected lost.
- VerifyLosses(6, packets_acked_, std::vector<uint64_t>{2});
- } else {
- // No losses, packet 2 is in limbo.
- VerifyLosses(6, packets_acked_, std::vector<uint64_t>{});
- }
+ // Verify packet 2 is detected lost.
+ VerifyLosses(6, packets_acked_, std::vector<uint64_t>{2});
}
} // namespace
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.cc
index bf1df2b5396..022a86b9227 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.cc
@@ -278,6 +278,7 @@ std::string CryptoHandshakeMessage::DebugStringInternal(size_t indent) const {
case kMIBS:
case kSCLS:
case kTCID:
+ case kMAD:
// uint32_t value
if (it->second.size() == 4) {
uint32_t value;
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 f2033e1228b..812aae082a9 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
@@ -170,6 +170,14 @@ const QuicTag kSMHL = TAG('S', 'M', 'H', 'L'); // Support MAX_HEADER_LIST_SIZE
const QuicTag kNSTP = TAG('N', 'S', 'T', 'P'); // No stop waiting frames.
const QuicTag kNRTT = TAG('N', 'R', 'T', 'T'); // Ignore initial RTT
+const QuicTag k1PTO = TAG('1', 'P', 'T', 'O'); // Send 1 packet upon PTO.
+const QuicTag k2PTO = TAG('2', 'P', 'T', 'O'); // Send 2 packets upon PTO.
+
+const QuicTag k7PTO = TAG('7', 'P', 'T', 'O'); // Closes connection on 7
+ // consecutive PTOs.
+const QuicTag k8PTO = TAG('8', 'P', 'T', 'O'); // Closes connection on 8
+ // consecutive PTOs.
+
// Optional support of truncated Connection IDs. If sent by a peer, the value
// is the minimum number of bytes allowed for the connection ID sent to the
// peer.
@@ -197,6 +205,13 @@ const QuicTag kBWS5 = TAG('B', 'W', 'S', '5'); // QUIC Initial CWND up and down
const QuicTag kMTUH = TAG('M', 'T', 'U', 'H'); // High-target MTU discovery.
const QuicTag kMTUL = TAG('M', 'T', 'U', 'L'); // Low-target MTU discovery.
+// Enable Priority scheme experiment.
+const QuicTag kH2PR = TAG('H', '2', 'P', 'R'); // HTTP2 priorities.
+const QuicTag kFIFO = TAG('F', 'I', 'F', 'O'); // Stream with the smallest ID
+ // has the highest priority.
+const QuicTag kLIFO = TAG('L', 'I', 'F', 'O'); // Stream with the largest ID
+ // has the highest priority.
+
// Proof types (i.e. certificate types)
// NOTE: although it would be silly to do so, specifying both kX509 and kX59R
// is allowed and is equivalent to specifying only kX509.
@@ -219,6 +234,8 @@ const QuicTag kICSL = TAG('I', 'C', 'S', 'L'); // Idle network timeout
const QuicTag kSCLS = TAG('S', 'C', 'L', 'S'); // Silently close on timeout
const QuicTag kMIBS = TAG('M', 'I', 'D', 'S'); // Max incoming bidi streams
const QuicTag kMIUS = TAG('M', 'I', 'U', 'S'); // Max incoming unidi streams
+const QuicTag kADE = TAG('A', 'D', 'E', 0); // Ack Delay Exponent (IETF
+ // QUIC ACK Frame Only).
const QuicTag kIRTT = TAG('I', 'R', 'T', 'T'); // Estimated initial RTT in us.
const QuicTag kSNI = TAG('S', 'N', 'I', '\0'); // Server name
// indication
@@ -238,6 +255,8 @@ const QuicTag kCFCW = TAG('C', 'F', 'C', 'W'); // Initial session/connection
const QuicTag kUAID = TAG('U', 'A', 'I', 'D'); // Client's User Agent ID.
const QuicTag kXLCT = TAG('X', 'L', 'C', 'T'); // Expected leaf certificate.
+const QuicTag kMAD = TAG('M', 'A', 'D', 0); // Max Ack Delay (IETF QUIC)
+
// Rejection tags
const QuicTag kRREJ = TAG('R', 'R', 'E', 'J'); // Reasons for server sending
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_secret_boxer.h b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_secret_boxer.h
index 395d3892d4f..eba7a57baea 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_secret_boxer.h
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_secret_boxer.h
@@ -59,7 +59,7 @@ class QUIC_EXPORT_PRIVATE CryptoSecretBoxer {
// state_ is an opaque pointer to whatever additional state the concrete
// implementation of CryptoSecretBoxer requires.
- std::unique_ptr<State> state_ GUARDED_BY(lock_);
+ std::unique_ptr<State> state_ QUIC_GUARDED_BY(lock_);
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_server_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_server_test.cc
index 5cc4d363c95..3216ea85b27 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_server_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_server_test.cc
@@ -103,7 +103,10 @@ class CryptoServerTest : public QuicTestWithParam<TestParams> {
config_.set_enable_serving_sct(true);
client_version_ = supported_versions_.front();
- client_version_string_ = ParsedQuicVersionToString(client_version_);
+ client_version_label_ = CreateQuicVersionLabel(client_version_);
+ client_version_string_ =
+ std::string(reinterpret_cast<const char*>(&client_version_label_),
+ sizeof(client_version_label_));
}
void SetUp() override {
@@ -265,7 +268,6 @@ class CryptoServerTest : public QuicTestWithParam<TestParams> {
} else {
ASSERT_NE(error, QUIC_NO_ERROR)
<< "Message didn't fail: " << result_->client_hello.DebugString();
-
EXPECT_TRUE(error_details.find(error_substr_) != std::string::npos)
<< error_substr_ << " not in " << error_details;
}
@@ -341,6 +343,7 @@ class CryptoServerTest : public QuicTestWithParam<TestParams> {
QuicSocketAddress client_address_;
ParsedQuicVersionVector supported_versions_;
ParsedQuicVersion client_version_;
+ QuicVersionLabel client_version_label_;
std::string client_version_string_;
QuicCryptoServerConfig config_;
QuicCryptoServerConfigPeer peer_;
@@ -497,9 +500,8 @@ TEST_P(CryptoServerTest, RejectTooLargeButValidSTK) {
TEST_P(CryptoServerTest, TooSmall) {
ShouldFailMentioning(
- "too small",
- crypto_test_utils::CreateCHLO(
- {{"PDMD", "X509"}, {"VER\0", client_version_string_.c_str()}}));
+ "too small", crypto_test_utils::CreateCHLO(
+ {{"PDMD", "X509"}, {"VER\0", client_version_string_}}));
const HandshakeFailureReason kRejectReasons[] = {
SERVER_CONFIG_INCHOATE_HELLO_FAILURE};
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 085a65a52bb..642799e7792 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
@@ -88,6 +88,8 @@ void CryptoUtils::SetKeyAndIV(const EVP_MD* prf,
namespace {
+static_assert(kQuicIetfDraftVersion == 22, "Salts do not match draft version");
+// Salt from https://tools.ietf.org/html/draft-ietf-quic-tls-22#section-5.2
const uint8_t kInitialSalt[] = {0x7f, 0xbc, 0xdb, 0x0e, 0x7c, 0x66, 0xbb,
0xe9, 0x19, 0x3a, 0x96, 0xcd, 0x21, 0x51,
0x9e, 0xbd, 0x7a, 0x02, 0x64, 0x4a};
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 50ea2f88264..862dc622b2f 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
@@ -1490,24 +1490,18 @@ void QuicCryptoServerConfig::BuildRejection(
out->SetStringPiece(kPROF, context.signed_config()->proof.signature);
if (should_return_sct) {
if (cert_sct.empty()) {
- if (!GetQuicReloadableFlag(quic_log_cert_name_for_empty_sct)) {
- QUIC_LOG_EVERY_N_SEC(WARNING, 60)
- << "SCT is expected but it is empty. sni :"
- << context.params()->sni;
- } else {
- // Log SNI and subject name for the leaf cert if its SCT is empty.
- // This is for debugging b/28342827.
- const std::vector<std::string>& certs =
- context.signed_config()->chain->certs;
- QuicStringPiece ca_subject;
- if (!certs.empty()) {
- QuicCertUtils::ExtractSubjectNameFromDERCert(certs[0], &ca_subject);
- }
- QUIC_LOG_EVERY_N_SEC(WARNING, 60)
- << "SCT is expected but it is empty. sni: '"
- << context.params()->sni << "' cert subject: '" << ca_subject
- << "'";
+ // Log SNI and subject name for the leaf cert if its SCT is empty.
+ // This is for debugging b/28342827.
+ const std::vector<std::string>& certs =
+ context.signed_config()->chain->certs;
+ QuicStringPiece ca_subject;
+ if (!certs.empty()) {
+ QuicCertUtils::ExtractSubjectNameFromDERCert(certs[0], &ca_subject);
}
+ QUIC_LOG_EVERY_N_SEC(WARNING, 60)
+ << "SCT is expected but it is empty. sni: '"
+ << context.params()->sni << "' cert subject: '" << ca_subject
+ << "'";
} else {
out->SetStringPiece(kCertificateSCTTag, cert_sct);
}
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 d8d9cab7a51..3fb424d4022 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
@@ -508,7 +508,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerConfig {
// Get a ref to the config with a given server config id.
QuicReferenceCountedPointer<Config> GetConfigWithScid(
QuicStringPiece requested_scid) const
- SHARED_LOCKS_REQUIRED(configs_lock_);
+ QUIC_SHARED_LOCKS_REQUIRED(configs_lock_);
// A snapshot of the configs associated with an in-progress handshake.
struct Configs {
@@ -537,7 +537,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerConfig {
// SelectNewPrimaryConfig reevaluates the primary config based on the
// "primary_time" deadlines contained in each.
void SelectNewPrimaryConfig(QuicWallTime now) const
- EXCLUSIVE_LOCKS_REQUIRED(configs_lock_);
+ QUIC_EXCLUSIVE_LOCKS_REQUIRED(configs_lock_);
// EvaluateClientHello checks |client_hello_state->client_hello| for gross
// errors and determines whether it is fresh (i.e. not a replay). The results
@@ -850,7 +850,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerConfig {
// Returns true if the next config promotion should happen now.
bool IsNextConfigReady(QuicWallTime now) const
- SHARED_LOCKS_REQUIRED(configs_lock_);
+ QUIC_SHARED_LOCKS_REQUIRED(configs_lock_);
// replay_protection_ controls whether the server enforces that handshakes
// aren't replays.
@@ -869,12 +869,12 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerConfig {
// configs_ contains all active server configs. It's expected that there are
// about half-a-dozen configs active at any one time.
- ConfigMap configs_ GUARDED_BY(configs_lock_);
+ ConfigMap configs_ QUIC_GUARDED_BY(configs_lock_);
// primary_config_ points to a Config (which is also in |configs_|) which is
// the primary config - i.e. the one that we'll give out to new clients.
mutable QuicReferenceCountedPointer<Config> primary_config_
- GUARDED_BY(configs_lock_);
+ QUIC_GUARDED_BY(configs_lock_);
// fallback_config_ points to a Config (which is also in |configs_|) which is
// the fallback config, which will be used if the other configs are unuseable
@@ -882,15 +882,16 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerConfig {
//
// TODO(b/112548056): This is currently always nullptr.
QuicReferenceCountedPointer<Config> fallback_config_
- GUARDED_BY(configs_lock_);
+ QUIC_GUARDED_BY(configs_lock_);
// next_config_promotion_time_ contains the nearest, future time when an
// active config will be promoted to primary.
- mutable QuicWallTime next_config_promotion_time_ GUARDED_BY(configs_lock_);
+ mutable QuicWallTime next_config_promotion_time_
+ QUIC_GUARDED_BY(configs_lock_);
// Callback to invoke when the primary config changes.
std::unique_ptr<PrimaryConfigChangedCallback> primary_config_changed_cb_
- GUARDED_BY(configs_lock_);
+ QUIC_GUARDED_BY(configs_lock_);
// Used to protect the source-address tokens that are given to clients.
CryptoSecretBoxer source_address_token_boxer_;
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 c15d9202af4..4774ba6924d 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
@@ -69,7 +69,7 @@ class QUIC_EXPORT_PRIVATE TlsConnection {
static enum ssl_encryption_level_t BoringEncryptionLevel(
EncryptionLevel level);
- SSL* ssl() { return ssl_.get(); }
+ SSL* ssl() const { return ssl_.get(); }
protected:
// TlsConnection does not take ownership of any of its arguments; they must
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 247f4071c32..8f2349cd335 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
@@ -13,6 +13,7 @@
#include "net/third_party/quiche/src/quic/core/quic_data_reader.h"
#include "net/third_party/quiche/src/quic/core/quic_data_writer.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/core/quic_utils.h"
#include "net/third_party/quiche/src/quic/core/quic_versions.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
@@ -365,7 +366,8 @@ bool TransportParameters::AreValid() const {
TransportParameters::~TransportParameters() = default;
-bool SerializeTransportParameters(const TransportParameters& in,
+bool SerializeTransportParameters(ParsedQuicVersion /*version*/,
+ const TransportParameters& in,
std::vector<uint8_t>* out) {
if (!in.AreValid()) {
QUIC_DLOG(ERROR) << "Not serializing invalid transport parameters " << in;
@@ -543,9 +545,10 @@ bool SerializeTransportParameters(const TransportParameters& in,
return true;
}
-bool ParseTransportParameters(const uint8_t* in,
- size_t in_len,
+bool ParseTransportParameters(ParsedQuicVersion version,
Perspective perspective,
+ const uint8_t* in,
+ size_t in_len,
TransportParameters* out) {
out->perspective = perspective;
CBS cbs;
@@ -572,22 +575,25 @@ bool ParseTransportParameters(const uint8_t* in,
}
bool parse_success = true;
switch (param_id) {
- case TransportParameters::kOriginalConnectionId:
+ case TransportParameters::kOriginalConnectionId: {
if (!out->original_connection_id.IsEmpty()) {
QUIC_DLOG(ERROR) << "Received a second original connection ID";
return false;
}
- if (CBS_len(&value) > static_cast<size_t>(kQuicMaxConnectionIdLength)) {
+ const size_t connection_id_length = CBS_len(&value);
+ if (!QuicUtils::IsConnectionIdLengthValidForVersion(
+ connection_id_length, version.transport_version)) {
QUIC_DLOG(ERROR) << "Received original connection ID of "
- << "invalid length " << CBS_len(&value);
+ << "invalid length " << connection_id_length;
return false;
}
- if (CBS_len(&value) != 0) {
- out->original_connection_id.set_length(CBS_len(&value));
+ out->original_connection_id.set_length(
+ static_cast<uint8_t>(connection_id_length));
+ if (out->original_connection_id.length() != 0) {
memcpy(out->original_connection_id.mutable_data(), CBS_data(&value),
- CBS_len(&value));
+ out->original_connection_id.length());
}
- break;
+ } break;
case TransportParameters::kIdleTimeout:
parse_success = out->idle_timeout_milliseconds.ReadFromCbs(&value);
break;
@@ -675,11 +681,15 @@ bool ParseTransportParameters(const uint8_t* in,
<< "Failed to parse length of preferred address connection ID";
return false;
}
- if (CBS_len(&connection_id_cbs) > kQuicMaxConnectionIdLength) {
- QUIC_DLOG(ERROR) << "Bad preferred address connection ID length";
+ const size_t connection_id_length = CBS_len(&connection_id_cbs);
+ if (!QuicUtils::IsConnectionIdLengthValidForVersion(
+ connection_id_length, version.transport_version)) {
+ QUIC_DLOG(ERROR) << "Received preferred address connection ID of "
+ << "invalid length " << connection_id_length;
return false;
}
- preferred_address.connection_id.set_length(CBS_len(&connection_id_cbs));
+ preferred_address.connection_id.set_length(
+ static_cast<uint8_t>(connection_id_length));
if (preferred_address.connection_id.length() > 0 &&
!CBS_copy_bytes(&connection_id_cbs,
reinterpret_cast<uint8_t*>(
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.h b/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.h
index 368a7bf6aba..95a01dac8d9 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.h
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.h
@@ -185,6 +185,7 @@ struct QUIC_EXPORT_PRIVATE TransportParameters {
// TLS extension. The serialized bytes are written to |*out|. Returns if the
// parameters are valid and serialization succeeded.
QUIC_EXPORT_PRIVATE bool SerializeTransportParameters(
+ ParsedQuicVersion version,
const TransportParameters& in,
std::vector<uint8_t>* out);
@@ -193,9 +194,10 @@ QUIC_EXPORT_PRIVATE bool SerializeTransportParameters(
// |perspective| indicates whether the input came from a client or a server.
// This method returns true if the input was successfully parsed.
// TODO(nharper): Write fuzz tests for this method.
-QUIC_EXPORT_PRIVATE bool ParseTransportParameters(const uint8_t* in,
- size_t in_len,
+QUIC_EXPORT_PRIVATE bool ParseTransportParameters(ParsedQuicVersion version,
Perspective perspective,
+ const uint8_t* in,
+ size_t in_len,
TransportParameters* out);
} // namespace quic
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 3f7e339339b..7379224a366 100644
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters_test.cc
@@ -7,6 +7,7 @@
#include <cstring>
#include "third_party/boringssl/src/include/openssl/mem.h"
+#include "net/third_party/quiche/src/quic/core/quic_versions.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
@@ -16,6 +17,7 @@
namespace quic {
namespace test {
namespace {
+const ParsedQuicVersion kVersion(PROTOCOL_TLS1_3, QUIC_VERSION_99);
const QuicVersionLabel kFakeVersionLabel = 0x01234567;
const QuicVersionLabel kFakeVersionLabel2 = 0x89ABCDEF;
const QuicConnectionId kFakeOriginalConnectionId = TestConnectionId(0x1337);
@@ -101,11 +103,12 @@ TEST_F(TransportParametersTest, RoundTripClient) {
kFakeActiveConnectionIdLimit);
std::vector<uint8_t> serialized;
- ASSERT_TRUE(SerializeTransportParameters(orig_params, &serialized));
+ ASSERT_TRUE(SerializeTransportParameters(kVersion, orig_params, &serialized));
TransportParameters new_params;
- ASSERT_TRUE(ParseTransportParameters(serialized.data(), serialized.size(),
- Perspective::IS_CLIENT, &new_params));
+ ASSERT_TRUE(ParseTransportParameters(kVersion, Perspective::IS_CLIENT,
+ serialized.data(), serialized.size(),
+ &new_params));
EXPECT_EQ(Perspective::IS_CLIENT, new_params.perspective);
EXPECT_EQ(kFakeVersionLabel, new_params.version);
@@ -160,11 +163,12 @@ TEST_F(TransportParametersTest, RoundTripServer) {
kFakeActiveConnectionIdLimit);
std::vector<uint8_t> serialized;
- ASSERT_TRUE(SerializeTransportParameters(orig_params, &serialized));
+ ASSERT_TRUE(SerializeTransportParameters(kVersion, orig_params, &serialized));
TransportParameters new_params;
- ASSERT_TRUE(ParseTransportParameters(serialized.data(), serialized.size(),
- Perspective::IS_SERVER, &new_params));
+ ASSERT_TRUE(ParseTransportParameters(kVersion, Perspective::IS_SERVER,
+ serialized.data(), serialized.size(),
+ &new_params));
EXPECT_EQ(Perspective::IS_SERVER, new_params.perspective);
EXPECT_EQ(kFakeVersionLabel, new_params.version);
@@ -255,7 +259,7 @@ TEST_F(TransportParametersTest, NoClientParamsWithStatelessResetToken) {
orig_params.max_packet_size.set_value(kFakeMaxPacketSize);
std::vector<uint8_t> out;
- EXPECT_FALSE(SerializeTransportParameters(orig_params, &out));
+ EXPECT_FALSE(SerializeTransportParameters(kVersion, orig_params, &out));
}
TEST_F(TransportParametersTest, ParseClientParams) {
@@ -317,9 +321,9 @@ TEST_F(TransportParametersTest, ParseClientParams) {
// clang-format on
TransportParameters new_params;
- ASSERT_TRUE(ParseTransportParameters(kClientParams,
- QUIC_ARRAYSIZE(kClientParams),
- Perspective::IS_CLIENT, &new_params));
+ ASSERT_TRUE(
+ ParseTransportParameters(kVersion, Perspective::IS_CLIENT, kClientParams,
+ QUIC_ARRAYSIZE(kClientParams), &new_params));
EXPECT_EQ(Perspective::IS_CLIENT, new_params.perspective);
EXPECT_EQ(kFakeVersionLabel, new_params.version);
@@ -374,8 +378,8 @@ TEST_F(TransportParametersTest, ParseClientParamsFailsWithStatelessResetToken) {
// clang-format on
EXPECT_FALSE(ParseTransportParameters(
- kClientParamsWithFullToken, QUIC_ARRAYSIZE(kClientParamsWithFullToken),
- Perspective::IS_CLIENT, &out_params));
+ kVersion, Perspective::IS_CLIENT, kClientParamsWithFullToken,
+ QUIC_ARRAYSIZE(kClientParamsWithFullToken), &out_params));
// clang-format off
const uint8_t kClientParamsWithEmptyToken[] = {
@@ -399,8 +403,8 @@ TEST_F(TransportParametersTest, ParseClientParamsFailsWithStatelessResetToken) {
// clang-format on
EXPECT_FALSE(ParseTransportParameters(
- kClientParamsWithEmptyToken, QUIC_ARRAYSIZE(kClientParamsWithEmptyToken),
- Perspective::IS_CLIENT, &out_params));
+ kVersion, Perspective::IS_CLIENT, kClientParamsWithEmptyToken,
+ QUIC_ARRAYSIZE(kClientParamsWithEmptyToken), &out_params));
}
TEST_F(TransportParametersTest, ParseClientParametersRepeated) {
@@ -425,9 +429,9 @@ TEST_F(TransportParametersTest, ParseClientParametersRepeated) {
};
// clang-format on
TransportParameters out_params;
- EXPECT_FALSE(ParseTransportParameters(kClientParamsRepeated,
- QUIC_ARRAYSIZE(kClientParamsRepeated),
- Perspective::IS_CLIENT, &out_params));
+ EXPECT_FALSE(ParseTransportParameters(
+ kVersion, Perspective::IS_CLIENT, kClientParamsRepeated,
+ QUIC_ARRAYSIZE(kClientParamsRepeated), &out_params));
}
TEST_F(TransportParametersTest, ParseServerParams) {
@@ -513,9 +517,9 @@ TEST_F(TransportParametersTest, ParseServerParams) {
// clang-format on
TransportParameters new_params;
- ASSERT_TRUE(ParseTransportParameters(kServerParams,
- QUIC_ARRAYSIZE(kServerParams),
- Perspective::IS_SERVER, &new_params));
+ ASSERT_TRUE(
+ ParseTransportParameters(kVersion, Perspective::IS_SERVER, kServerParams,
+ QUIC_ARRAYSIZE(kServerParams), &new_params));
EXPECT_EQ(Perspective::IS_SERVER, new_params.perspective);
EXPECT_EQ(kFakeVersionLabel, new_params.version);
@@ -579,9 +583,9 @@ TEST_F(TransportParametersTest, ParseServerParametersRepeated) {
// clang-format on
TransportParameters out_params;
- EXPECT_FALSE(ParseTransportParameters(kServerParamsRepeated,
- QUIC_ARRAYSIZE(kServerParamsRepeated),
- Perspective::IS_SERVER, &out_params));
+ EXPECT_FALSE(ParseTransportParameters(
+ kVersion, Perspective::IS_SERVER, kServerParamsRepeated,
+ QUIC_ARRAYSIZE(kServerParamsRepeated), &out_params));
}
TEST_F(TransportParametersTest, CryptoHandshakeMessageRoundtrip) {
@@ -597,11 +601,12 @@ TEST_F(TransportParametersTest, CryptoHandshakeMessageRoundtrip) {
orig_params.google_quic_params->SetValue(1337, kTestValue);
std::vector<uint8_t> serialized;
- ASSERT_TRUE(SerializeTransportParameters(orig_params, &serialized));
+ ASSERT_TRUE(SerializeTransportParameters(kVersion, orig_params, &serialized));
TransportParameters new_params;
- ASSERT_TRUE(ParseTransportParameters(serialized.data(), serialized.size(),
- Perspective::IS_CLIENT, &new_params));
+ ASSERT_TRUE(ParseTransportParameters(kVersion, Perspective::IS_CLIENT,
+ serialized.data(), serialized.size(),
+ &new_params));
ASSERT_NE(new_params.google_quic_params.get(), nullptr);
EXPECT_EQ(new_params.google_quic_params->tag(),
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_connection_close_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_connection_close_frame.cc
index d436499ca0c..a7b3d53e0ef 100644
--- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_connection_close_frame.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_connection_close_frame.cc
@@ -6,6 +6,8 @@
#include <memory>
+#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h"
+
namespace quic {
QuicConnectionCloseFrame::QuicConnectionCloseFrame()
@@ -20,7 +22,7 @@ QuicConnectionCloseFrame::QuicConnectionCloseFrame(QuicErrorCode error_code,
// Default close type ensures that existing, pre-V99 code works as expected.
: close_type(GOOGLE_QUIC_CONNECTION_CLOSE),
quic_error_code(error_code),
- extracted_error_code(QUIC_IETF_GQUIC_ERROR_MISSING),
+ extracted_error_code(error_code),
error_details(std::move(error_details)),
transport_close_frame_type(0) {}
@@ -49,39 +51,28 @@ std::ostream& operator<<(
std::ostream& os,
const QuicConnectionCloseFrame& connection_close_frame) {
os << "{ Close type: " << connection_close_frame.close_type
- << ", error_code: "
- << ((connection_close_frame.close_type ==
- IETF_QUIC_TRANSPORT_CONNECTION_CLOSE)
- ? static_cast<uint16_t>(
- connection_close_frame.transport_error_code)
- : ((connection_close_frame.close_type ==
- IETF_QUIC_APPLICATION_CONNECTION_CLOSE)
- ? connection_close_frame.application_error_code
- : static_cast<uint16_t>(
- connection_close_frame.quic_error_code)))
- << ", extracted_error_code: "
- << connection_close_frame.extracted_error_code << ", error_details: '"
- << connection_close_frame.error_details
- << "', frame_type: " << connection_close_frame.transport_close_frame_type
- << "}\n";
- return os;
-}
-
-std::ostream& operator<<(std::ostream& os, const QuicConnectionCloseType type) {
- switch (type) {
- case GOOGLE_QUIC_CONNECTION_CLOSE:
- os << "GOOGLE_QUIC_CONNECTION_CLOSE";
- break;
+ << ", error_code: ";
+ switch (connection_close_frame.close_type) {
case IETF_QUIC_TRANSPORT_CONNECTION_CLOSE:
- os << "IETF_QUIC_TRANSPORT_CONNECTION_CLOSE";
+ os << connection_close_frame.transport_error_code;
break;
case IETF_QUIC_APPLICATION_CONNECTION_CLOSE:
- os << "IETF_QUIC_APPLICATION_CONNECTION_CLOSE";
+ os << connection_close_frame.application_error_code;
break;
- default:
- os << "Unknown: " << static_cast<int>(type);
+ case GOOGLE_QUIC_CONNECTION_CLOSE:
+ os << connection_close_frame.quic_error_code;
break;
}
+ os << ", extracted_error_code: "
+ << QuicErrorCodeToString(connection_close_frame.extracted_error_code)
+ << ", error_details: '" << connection_close_frame.error_details << "'";
+ if (connection_close_frame.close_type ==
+ IETF_QUIC_TRANSPORT_CONNECTION_CLOSE) {
+ os << ", frame_type: "
+ << static_cast<QuicIetfFrameType>(
+ connection_close_frame.transport_close_frame_type);
+ }
+ os << "}\n";
return os;
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_connection_close_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_connection_close_frame.h
index aba67b9a88f..b4f4fd70971 100644
--- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_connection_close_frame.h
+++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_connection_close_frame.h
@@ -14,16 +14,6 @@
namespace quic {
-// There are three different forms of CONNECTION_CLOSE.
-typedef enum QuicConnectionCloseType {
- GOOGLE_QUIC_CONNECTION_CLOSE = 0,
- IETF_QUIC_TRANSPORT_CONNECTION_CLOSE = 1,
- IETF_QUIC_APPLICATION_CONNECTION_CLOSE = 2
-} QuicConnectionCloseType;
-QUIC_EXPORT_PRIVATE std::ostream& operator<<(
- std::ostream& os,
- const QuicConnectionCloseType type);
-
struct QUIC_EXPORT_PRIVATE QuicConnectionCloseFrame {
QuicConnectionCloseFrame();
@@ -64,9 +54,10 @@ struct QUIC_EXPORT_PRIVATE QuicConnectionCloseFrame {
QuicErrorCode quic_error_code;
};
- // This error code is extracted from, or added to, the "QuicErrorCode:
- // QUIC_...(123)" text in the error_details. It provides fine-grained
- // information as to the source of the error.
+ // For IETF QUIC frames, this is the error code is extracted from, or added
+ // to, the error details text. For received Google QUIC frames, the Google
+ // QUIC error code from the frame's error code field is copied here (as well
+ // as in quic_error_code, above).
QuicErrorCode extracted_error_code;
// String with additional error details. "QuicErrorCode: 123" will be appended
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 3467c7849f1..b1030ee3b7f 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
@@ -148,10 +148,31 @@ TEST_F(QuicFramesTest, ConnectionCloseFrameToString) {
// underlying frame.
EXPECT_EQ(
"{ Close type: GOOGLE_QUIC_CONNECTION_CLOSE, error_code: 25, "
- "extracted_error_code: 122, "
+ "extracted_error_code: QUIC_IETF_GQUIC_ERROR_MISSING, "
+ "error_details: 'No recent "
+ "network activity.'"
+ "}\n",
+ stream.str());
+ QuicFrame quic_frame(&frame);
+ EXPECT_FALSE(IsControlFrame(quic_frame.type));
+}
+
+TEST_F(QuicFramesTest, TransportConnectionCloseFrameToString) {
+ QuicConnectionCloseFrame frame;
+ frame.close_type = IETF_QUIC_TRANSPORT_CONNECTION_CLOSE;
+ frame.transport_error_code = FINAL_SIZE_ERROR;
+ frame.extracted_error_code = QUIC_NETWORK_IDLE_TIMEOUT;
+ frame.error_details = "No recent network activity.";
+ frame.transport_close_frame_type = IETF_STREAM;
+ std::ostringstream stream;
+ stream << frame;
+ EXPECT_EQ(
+ "{ Close type: IETF_QUIC_TRANSPORT_CONNECTION_CLOSE, error_code: "
+ "FINAL_SIZE_ERROR, "
+ "extracted_error_code: QUIC_NETWORK_IDLE_TIMEOUT, "
"error_details: 'No recent "
"network activity.', "
- "frame_type: 0"
+ "frame_type: IETF_STREAM"
"}\n",
stream.str());
QuicFrame quic_frame(&frame);
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 578df127ddd..3a6d5149230 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
@@ -15,6 +15,7 @@
#include "net/third_party/quiche/src/quic/core/http/http_constants.h"
#include "net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream.h"
#include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test_utils.h"
+#include "net/third_party/quiche/src/quic/core/quic_data_writer.h"
#include "net/third_party/quiche/src/quic/core/quic_epoll_connection_helper.h"
#include "net/third_party/quiche/src/quic/core/quic_error_codes.h"
#include "net/third_party/quiche/src/quic/core/quic_framer.h"
@@ -85,11 +86,13 @@ struct TestParams {
TestParams(const ParsedQuicVersionVector& client_supported_versions,
const ParsedQuicVersionVector& server_supported_versions,
ParsedQuicVersion negotiated_version,
- QuicTag congestion_control_tag)
+ QuicTag congestion_control_tag,
+ QuicTag priority_tag)
: client_supported_versions(client_supported_versions),
server_supported_versions(server_supported_versions),
negotiated_version(negotiated_version),
- congestion_control_tag(congestion_control_tag) {}
+ congestion_control_tag(congestion_control_tag),
+ priority_tag(priority_tag) {}
friend std::ostream& operator<<(std::ostream& os, const TestParams& p) {
os << "{ server_supported_versions: "
@@ -99,7 +102,8 @@ struct TestParams {
os << " negotiated_version: "
<< ParsedQuicVersionToString(p.negotiated_version);
os << " congestion_control_tag: "
- << QuicTagToString(p.congestion_control_tag) << " }";
+ << QuicTagToString(p.congestion_control_tag);
+ os << " priority_tag: " << QuicTagToString(p.priority_tag) << " }";
return os;
}
@@ -107,6 +111,7 @@ struct TestParams {
ParsedQuicVersionVector server_supported_versions;
ParsedQuicVersion negotiated_version;
QuicTag congestion_control_tag;
+ QuicTag priority_tag;
};
// Constructs various test permutations.
@@ -153,28 +158,32 @@ std::vector<TestParams> GetTestParams(bool use_tls_handshake) {
if (FilterSupportedVersions(client_versions).empty()) {
continue;
}
- // Add an entry for server and client supporting all versions.
- params.push_back(TestParams(client_versions, all_supported_versions,
- client_versions.front(),
- congestion_control_tag));
-
- // Test client supporting all versions and server supporting
- // 1 version. Simulate an old server and exercise version
- // downgrade in the client. Protocol negotiation should
- // occur. Skip the i = 0 case because it is essentially the
- // same as the default case.
- for (size_t i = 1; i < client_versions.size(); ++i) {
- ParsedQuicVersionVector server_supported_versions;
- server_supported_versions.push_back(client_versions[i]);
- if (FilterSupportedVersions(server_supported_versions).empty()) {
- continue;
- }
- params.push_back(TestParams(client_versions, server_supported_versions,
- server_supported_versions.front(),
- congestion_control_tag));
- } // End of inner version loop.
- } // End of outer version loop.
- } // End of congestion_control_tag loop.
+ for (const QuicTag priority_tag :
+ {/*no tag*/ static_cast<QuicTag>(0), kH2PR, kFIFO, kLIFO}) {
+ // Add an entry for server and client supporting all versions.
+ params.push_back(TestParams(client_versions, all_supported_versions,
+ client_versions.front(),
+ congestion_control_tag, priority_tag));
+
+ // Test client supporting all versions and server supporting
+ // 1 version. Simulate an old server and exercise version
+ // downgrade in the client. Protocol negotiation should
+ // occur. Skip the i = 0 case because it is essentially the
+ // same as the default case.
+ for (size_t i = 1; i < client_versions.size(); ++i) {
+ ParsedQuicVersionVector server_supported_versions;
+ server_supported_versions.push_back(client_versions[i]);
+ if (FilterSupportedVersions(server_supported_versions).empty()) {
+ continue;
+ }
+ params.push_back(TestParams(client_versions,
+ server_supported_versions,
+ server_supported_versions.front(),
+ congestion_control_tag, priority_tag));
+ } // End of inner version loop.
+ } // End of priority_tag loop.
+ } // End of outer version loop.
+ } // End of congestion_control_tag loop.
return params;
}
@@ -216,8 +225,8 @@ class EndToEndTest : public QuicTestWithParam<TestParams> {
EndToEndTest()
: initialized_(false),
connect_to_server_on_initialize_(true),
- server_address_(
- QuicSocketAddress(TestLoopback(), QuicPickUnusedPortOrDie())),
+ server_address_(QuicSocketAddress(TestLoopback(),
+ QuicPickServerPortForTestsOrDie())),
server_hostname_("test.example.com"),
client_writer_(nullptr),
server_writer_(nullptr),
@@ -225,10 +234,9 @@ class EndToEndTest : public QuicTestWithParam<TestParams> {
chlo_multiplier_(0),
stream_factory_(nullptr),
support_server_push_(false),
- override_server_connection_id_(nullptr),
- override_client_connection_id_(nullptr),
expected_server_connection_id_length_(kQuicDefaultConnectionIdLength) {
SetQuicFlag(FLAGS_quic_supports_tls_handshake, true);
+ SetQuicReloadableFlag(quic_simplify_stop_waiting, true);
client_supported_versions_ = GetParam().client_supported_versions;
server_supported_versions_ = GetParam().server_supported_versions;
negotiated_version_ = GetParam().negotiated_version;
@@ -272,13 +280,11 @@ class EndToEndTest : public QuicTestWithParam<TestParams> {
if (!pre_shared_key_client_.empty()) {
client->client()->SetPreSharedKey(pre_shared_key_client_);
}
- if (override_server_connection_id_ != nullptr) {
- client->UseConnectionId(*override_server_connection_id_);
+ client->UseConnectionIdLength(override_server_connection_id_length_);
+ client->UseClientConnectionIdLength(override_client_connection_id_length_);
+ if (support_server_push_) {
+ client->client()->set_max_allowed_push_id(kMaxQuicStreamId);
}
- if (override_client_connection_id_ != nullptr) {
- client->UseClientConnectionId(*override_client_connection_id_);
- }
- client->client()->set_max_allowed_push_id(kMaxQuicStreamId);
client->Connect();
return client;
}
@@ -326,15 +332,24 @@ class EndToEndTest : public QuicTestWithParam<TestParams> {
return &GetServerConnection()->sent_packet_manager();
}
+ QuicSpdyClientSession* GetClientSession() {
+ return client_->client()->client_session();
+ }
+
+ QuicConnection* GetClientConnection() {
+ return GetClientSession()->connection();
+ }
+
QuicConnection* GetServerConnection() {
return GetServerSession()->connection();
}
- QuicSession* GetServerSession() {
+ QuicSpdySession* GetServerSession() {
QuicDispatcher* dispatcher =
QuicServerPeer::GetDispatcher(server_thread_->server());
EXPECT_EQ(1u, dispatcher->session_map().size());
- return dispatcher->session_map().begin()->second.get();
+ return static_cast<QuicSpdySession*>(
+ dispatcher->session_map().begin()->second.get());
}
bool Initialize() {
@@ -349,7 +364,10 @@ class EndToEndTest : public QuicTestWithParam<TestParams> {
GetQuicReloadableFlag(quic_enable_pcc3)) {
copt.push_back(kTPCC);
}
-
+ copt.push_back(GetParam().priority_tag);
+ if (GetQuicReloadableFlag(quic_enable_pto)) {
+ copt.push_back(k2PTO);
+ }
client_config_.SetConnectionOptionsToSend(copt);
// Start the server first, because CreateQuicClient() attempts
@@ -365,10 +383,8 @@ class EndToEndTest : public QuicTestWithParam<TestParams> {
static QuicEpollEvent event(EPOLLOUT);
if (client_writer_ != nullptr) {
client_writer_->Initialize(
- QuicConnectionPeer::GetHelper(
- client_->client()->client_session()->connection()),
- QuicConnectionPeer::GetAlarmFactory(
- client_->client()->client_session()->connection()),
+ QuicConnectionPeer::GetHelper(GetClientConnection()),
+ QuicConnectionPeer::GetAlarmFactory(GetClientConnection()),
QuicMakeUnique<ClientDelegate>(client_->client()));
}
initialized_ = true;
@@ -401,6 +417,8 @@ class EndToEndTest : public QuicTestWithParam<TestParams> {
server_thread_->server()->SetPreSharedKey(pre_shared_key_server_);
}
server_thread_->Initialize();
+ server_address_ =
+ QuicSocketAddress(server_address_.host(), server_thread_->GetPort());
QuicDispatcher* dispatcher =
QuicServerPeer::GetDispatcher(server_thread_->server());
QuicDispatcherPeer::UseWriter(dispatcher, server_writer_);
@@ -450,8 +468,7 @@ class EndToEndTest : public QuicTestWithParam<TestParams> {
// Calls server_thread_ Pause() and Resume(), which may only be called once
// per test.
void VerifyCleanConnection(bool had_packet_loss) {
- QuicConnectionStats client_stats =
- client_->client()->client_session()->connection()->GetStats();
+ QuicConnectionStats client_stats = GetClientConnection()->GetStats();
// TODO(ianswett): Determine why this becomes even more flaky with BBR
// enabled. b/62141144
if (!had_packet_loss && !GetQuicReloadableFlag(quic_default_to_bbr)) {
@@ -505,12 +522,23 @@ class EndToEndTest : public QuicTestWithParam<TestParams> {
version.handshake_protocol == PROTOCOL_TLS1_3;
}
- void ExpectFlowControlsSynced(QuicFlowController* client,
- QuicFlowController* server) {
- EXPECT_EQ(QuicFlowControllerPeer::SendWindowSize(client),
- QuicFlowControllerPeer::ReceiveWindowSize(server));
- EXPECT_EQ(QuicFlowControllerPeer::ReceiveWindowSize(client),
- QuicFlowControllerPeer::SendWindowSize(server));
+ static void ExpectFlowControlsSynced(QuicSession* client,
+ QuicSession* server) {
+ EXPECT_EQ(
+ QuicFlowControllerPeer::SendWindowSize(client->flow_controller()),
+ QuicFlowControllerPeer::ReceiveWindowSize(server->flow_controller()));
+ EXPECT_EQ(
+ QuicFlowControllerPeer::ReceiveWindowSize(client->flow_controller()),
+ QuicFlowControllerPeer::SendWindowSize(server->flow_controller()));
+ }
+
+ static void ExpectFlowControlsSynced(QuicStream* client, QuicStream* server) {
+ EXPECT_EQ(
+ QuicFlowControllerPeer::SendWindowSize(client->flow_controller()),
+ QuicFlowControllerPeer::ReceiveWindowSize(server->flow_controller()));
+ EXPECT_EQ(
+ QuicFlowControllerPeer::ReceiveWindowSize(client->flow_controller()),
+ QuicFlowControllerPeer::SendWindowSize(server->flow_controller()));
}
// Must be called before Initialize to have effect.
@@ -520,14 +548,12 @@ class EndToEndTest : public QuicTestWithParam<TestParams> {
QuicStreamId GetNthClientInitiatedBidirectionalId(int n) {
return GetNthClientInitiatedBidirectionalStreamId(
- client_->client()->client_session()->connection()->transport_version(),
- n);
+ GetClientConnection()->transport_version(), n);
}
QuicStreamId GetNthServerInitiatedBidirectionalId(int n) {
return GetNthServerInitiatedBidirectionalStreamId(
- client_->client()->client_session()->connection()->transport_version(),
- n);
+ GetClientConnection()->transport_version(), n);
}
ScopedEnvironmentForThreads environment_;
@@ -554,8 +580,8 @@ class EndToEndTest : public QuicTestWithParam<TestParams> {
bool support_server_push_;
std::string pre_shared_key_client_;
std::string pre_shared_key_server_;
- QuicConnectionId* override_server_connection_id_;
- QuicConnectionId* override_client_connection_id_;
+ int override_server_connection_id_length_ = -1;
+ int override_client_connection_id_length_ = -1;
uint8_t expected_server_connection_id_length_;
};
@@ -578,12 +604,11 @@ TEST_P(EndToEndTestWithTls, HandshakeSuccessful) {
// version in the connection are not in sync. If it is happening, it has not
// been recreatable; this assert is here just to check and raise a flag if it
// happens.
- ASSERT_EQ(
- client_->client()->client_session()->connection()->transport_version(),
- negotiated_version_.transport_version);
+ ASSERT_EQ(GetClientConnection()->transport_version(),
+ negotiated_version_.transport_version);
- QuicCryptoStream* crypto_stream = QuicSessionPeer::GetMutableCryptoStream(
- client_->client()->client_session());
+ QuicCryptoStream* crypto_stream =
+ QuicSessionPeer::GetMutableCryptoStream(GetClientSession());
QuicStreamSequencer* sequencer = QuicStreamPeer::sequencer(crypto_stream);
EXPECT_FALSE(QuicStreamSequencerPeer::IsUnderlyingBufferAllocated(sequencer));
server_thread_->Pause();
@@ -603,6 +628,14 @@ TEST_P(EndToEndTest, SimpleRequestResponse) {
}
EXPECT_EQ(expected_num_client_hellos,
client_->client()->GetNumSentClientHellos());
+ if (VersionUsesQpack(GetClientConnection()->transport_version())) {
+ EXPECT_TRUE(QuicSpdySessionPeer::GetSendControlStream(GetClientSession()));
+ EXPECT_TRUE(
+ QuicSpdySessionPeer::GetReceiveControlStream(GetClientSession()));
+ EXPECT_TRUE(QuicSpdySessionPeer::GetSendControlStream(GetServerSession()));
+ EXPECT_TRUE(
+ QuicSpdySessionPeer::GetReceiveControlStream(GetServerSession()));
+ }
}
TEST_P(EndToEndTestWithTls, SimpleRequestResponse) {
@@ -611,7 +644,70 @@ TEST_P(EndToEndTestWithTls, SimpleRequestResponse) {
EXPECT_EQ("200", client_->response_headers()->find(":status")->second);
}
+// Simple transaction, but set a non-default ack delay at the client
+// and ensure it gets to the server.
+TEST_P(EndToEndTest, SimpleRequestResponseWithAckDelayChange) {
+ // Force the ACK delay to be something other than the default.
+ // Note that it is sent only if doing IETF QUIC.
+ client_config_.SetMaxAckDelayToSendMs(kDefaultDelayedAckTimeMs + 100u);
+ ASSERT_TRUE(Initialize());
+
+ EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
+ EXPECT_EQ("200", client_->response_headers()->find(":status")->second);
+ int expected_num_client_hellos = 2;
+ if (ServerSendsVersionNegotiation()) {
+ ++expected_num_client_hellos;
+ }
+ EXPECT_EQ(expected_num_client_hellos,
+ client_->client()->GetNumSentClientHellos());
+ if (GetQuicReloadableFlag(quic_negotiate_ack_delay_time)) {
+ EXPECT_EQ(kDefaultDelayedAckTimeMs + 100u,
+ GetSentPacketManagerFromFirstServerSession()
+ ->peer_max_ack_delay()
+ .ToMilliseconds());
+ } else {
+ EXPECT_EQ(kDefaultDelayedAckTimeMs,
+ GetSentPacketManagerFromFirstServerSession()
+ ->peer_max_ack_delay()
+ .ToMilliseconds());
+ }
+}
+
+// Simple transaction, but set a non-default ack exponent at the client
+// and ensure it gets to the server.
+TEST_P(EndToEndTest, SimpleRequestResponseWithAckExponentChange) {
+ const uint32_t kClientAckDelayExponent = kDefaultAckDelayExponent + 100u;
+ // Force the ACK exponent to be something other than the default.
+ // Note that it is sent only if doing IETF QUIC.
+ client_config_.SetAckDelayExponentToSend(kClientAckDelayExponent);
+ ASSERT_TRUE(Initialize());
+
+ EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
+ EXPECT_EQ("200", client_->response_headers()->find(":status")->second);
+ int expected_num_client_hellos = 2;
+ if (ServerSendsVersionNegotiation()) {
+ ++expected_num_client_hellos;
+ }
+
+ EXPECT_EQ(expected_num_client_hellos,
+ client_->client()->GetNumSentClientHellos());
+ if (VersionHasIetfQuicFrames(
+ GetParam().negotiated_version.transport_version)) {
+ // Should be only for IETF QUIC.
+ EXPECT_EQ(kClientAckDelayExponent,
+ GetServerConnection()->framer().peer_ack_delay_exponent());
+ } else {
+ // No change for Google QUIC.
+ EXPECT_EQ(kDefaultAckDelayExponent,
+ GetServerConnection()->framer().peer_ack_delay_exponent());
+ }
+ // No change, regardless of version.
+ EXPECT_EQ(kDefaultAckDelayExponent,
+ GetServerConnection()->framer().local_ack_delay_exponent());
+}
+
TEST_P(EndToEndTest, SimpleRequestResponseForcedVersionNegotiation) {
+ SetQuicReloadableFlag(quic_use_parse_public_header, true);
client_supported_versions_.insert(client_supported_versions_.begin(),
QuicVersionReservedForNegotiation());
ASSERT_TRUE(Initialize());
@@ -624,6 +720,7 @@ TEST_P(EndToEndTest, SimpleRequestResponseForcedVersionNegotiation) {
}
TEST_P(EndToEndTestWithTls, ForcedVersionNegotiation) {
+ SetQuicReloadableFlag(quic_use_parse_public_header, true);
client_supported_versions_.insert(client_supported_versions_.begin(),
QuicVersionReservedForNegotiation());
ASSERT_TRUE(Initialize());
@@ -634,10 +731,13 @@ TEST_P(EndToEndTestWithTls, ForcedVersionNegotiation) {
}
TEST_P(EndToEndTest, SimpleRequestResponseZeroConnectionID) {
- QuicConnectionId connection_id = QuicUtils::CreateZeroConnectionId(
- GetParam().negotiated_version.transport_version);
- override_server_connection_id_ = &connection_id;
- expected_server_connection_id_length_ = connection_id.length();
+ if (!QuicUtils::VariableLengthConnectionIdAllowedForVersion(
+ GetParam().negotiated_version.transport_version)) {
+ ASSERT_TRUE(Initialize());
+ return;
+ }
+ override_server_connection_id_length_ = 0;
+ expected_server_connection_id_length_ = 0;
ASSERT_TRUE(Initialize());
EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
@@ -648,21 +748,24 @@ TEST_P(EndToEndTest, SimpleRequestResponseZeroConnectionID) {
}
EXPECT_EQ(expected_num_client_hellos,
client_->client()->GetNumSentClientHellos());
- EXPECT_EQ(client_->client()->client_session()->connection()->connection_id(),
+ EXPECT_EQ(GetClientConnection()->connection_id(),
QuicUtils::CreateZeroConnectionId(
GetParam().negotiated_version.transport_version));
}
TEST_P(EndToEndTestWithTls, ZeroConnectionID) {
- QuicConnectionId connection_id = QuicUtils::CreateZeroConnectionId(
- GetParam().negotiated_version.transport_version);
- override_server_connection_id_ = &connection_id;
- expected_server_connection_id_length_ = connection_id.length();
+ if (!QuicUtils::VariableLengthConnectionIdAllowedForVersion(
+ GetParam().negotiated_version.transport_version)) {
+ ASSERT_TRUE(Initialize());
+ return;
+ }
+ override_server_connection_id_length_ = 0;
+ expected_server_connection_id_length_ = 0;
ASSERT_TRUE(Initialize());
EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
EXPECT_EQ("200", client_->response_headers()->find(":status")->second);
- EXPECT_EQ(client_->client()->client_session()->connection()->connection_id(),
+ EXPECT_EQ(GetClientConnection()->connection_id(),
QuicUtils::CreateZeroConnectionId(
GetParam().negotiated_version.transport_version));
}
@@ -673,9 +776,7 @@ TEST_P(EndToEndTestWithTls, BadConnectionIdLength) {
ASSERT_TRUE(Initialize());
return;
}
- QuicConnectionId connection_id =
- TestConnectionIdNineBytesLong(UINT64_C(0xBADbadBADbad));
- override_server_connection_id_ = &connection_id;
+ override_server_connection_id_length_ = 9;
ASSERT_TRUE(Initialize());
EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
EXPECT_EQ("200", client_->response_headers()->find(":status")->second);
@@ -694,12 +795,7 @@ TEST_P(EndToEndTestWithTls, LongBadConnectionIdLength) {
ASSERT_TRUE(Initialize());
return;
}
- const char connection_id_bytes[16] = {0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5,
- 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb,
- 0xbc, 0xbd, 0xbe, 0xbf};
- QuicConnectionId connection_id =
- QuicConnectionId(connection_id_bytes, sizeof(connection_id_bytes));
- override_server_connection_id_ = &connection_id;
+ override_server_connection_id_length_ = 16;
ASSERT_TRUE(Initialize());
EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
EXPECT_EQ("200", client_->response_headers()->find(":status")->second);
@@ -715,16 +811,15 @@ TEST_P(EndToEndTestWithTls, ClientConnectionId) {
ASSERT_TRUE(Initialize());
return;
}
- QuicConnectionId client_connection_id =
- TestConnectionId(UINT64_C(0xc1c2c3c4c5c6c7c8));
- override_client_connection_id_ = &client_connection_id;
+ override_client_connection_id_length_ = kQuicDefaultConnectionIdLength;
ASSERT_TRUE(Initialize());
EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
EXPECT_EQ("200", client_->response_headers()->find(":status")->second);
- EXPECT_EQ(client_connection_id, client_->client()
- ->client_session()
- ->connection()
- ->client_connection_id());
+ EXPECT_EQ(override_client_connection_id_length_, client_->client()
+ ->client_session()
+ ->connection()
+ ->client_connection_id()
+ .length());
}
TEST_P(EndToEndTestWithTls, ForcedVersionNegotiationAndClientConnectionId) {
@@ -732,19 +827,19 @@ TEST_P(EndToEndTestWithTls, ForcedVersionNegotiationAndClientConnectionId) {
ASSERT_TRUE(Initialize());
return;
}
+ SetQuicReloadableFlag(quic_use_parse_public_header, true);
client_supported_versions_.insert(client_supported_versions_.begin(),
QuicVersionReservedForNegotiation());
- QuicConnectionId client_connection_id =
- TestConnectionId(UINT64_C(0xc1c2c3c4c5c6c7c8));
- override_client_connection_id_ = &client_connection_id;
+ override_client_connection_id_length_ = kQuicDefaultConnectionIdLength;
ASSERT_TRUE(Initialize());
ASSERT_TRUE(ServerSendsVersionNegotiation());
EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
EXPECT_EQ("200", client_->response_headers()->find(":status")->second);
- EXPECT_EQ(client_connection_id, client_->client()
- ->client_session()
- ->connection()
- ->client_connection_id());
+ EXPECT_EQ(override_client_connection_id_length_, client_->client()
+ ->client_session()
+ ->connection()
+ ->client_connection_id()
+ .length());
}
TEST_P(EndToEndTestWithTls, ForcedVersionNegotiationAndBadConnectionIdLength) {
@@ -753,11 +848,10 @@ TEST_P(EndToEndTestWithTls, ForcedVersionNegotiationAndBadConnectionIdLength) {
ASSERT_TRUE(Initialize());
return;
}
+ SetQuicReloadableFlag(quic_use_parse_public_header, true);
client_supported_versions_.insert(client_supported_versions_.begin(),
QuicVersionReservedForNegotiation());
- QuicConnectionId connection_id =
- TestConnectionIdNineBytesLong(UINT64_C(0xBADbadBADbad));
- override_server_connection_id_ = &connection_id;
+ override_server_connection_id_length_ = 9;
ASSERT_TRUE(Initialize());
ASSERT_TRUE(ServerSendsVersionNegotiation());
EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
@@ -780,18 +874,8 @@ TEST_P(EndToEndTestWithTls, ForcedVersNegoAndClientCIDAndLongCID) {
}
client_supported_versions_.insert(client_supported_versions_.begin(),
QuicVersionReservedForNegotiation());
- const char connection_id_bytes[16] = {0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5,
- 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb,
- 0xbc, 0xbd, 0xbe, 0xbf};
- QuicConnectionId connection_id =
- QuicConnectionId(connection_id_bytes, sizeof(connection_id_bytes));
- override_server_connection_id_ = &connection_id;
- const char client_connection_id_bytes[18] = {
- 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8,
- 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xc0, 0xc1};
- QuicConnectionId client_connection_id = QuicConnectionId(
- client_connection_id_bytes, sizeof(client_connection_id_bytes));
- override_client_connection_id_ = &client_connection_id;
+ override_server_connection_id_length_ = 16;
+ override_client_connection_id_length_ = 18;
ASSERT_TRUE(Initialize());
ASSERT_TRUE(ServerSendsVersionNegotiation());
EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
@@ -801,10 +885,11 @@ TEST_P(EndToEndTestWithTls, ForcedVersNegoAndClientCIDAndLongCID) {
->connection()
->connection_id()
.length());
- EXPECT_EQ(client_connection_id, client_->client()
- ->client_session()
- ->connection()
- ->client_connection_id());
+ EXPECT_EQ(override_client_connection_id_length_, client_->client()
+ ->client_session()
+ ->connection()
+ ->client_connection_id()
+ .length());
}
TEST_P(EndToEndTest, MixGoodAndBadConnectionIdLengths) {
@@ -815,11 +900,9 @@ TEST_P(EndToEndTest, MixGoodAndBadConnectionIdLengths) {
}
// Start client_ which will use a bad connection ID length.
- QuicConnectionId connection_id =
- TestConnectionIdNineBytesLong(UINT64_C(0xBADbadBADbad));
- override_server_connection_id_ = &connection_id;
+ override_server_connection_id_length_ = 9;
ASSERT_TRUE(Initialize());
- override_server_connection_id_ = nullptr;
+ override_server_connection_id_length_ = -1;
// Start client2 which will use a good connection ID length.
std::unique_ptr<QuicTestClient> client2(CreateQuicClient(nullptr));
@@ -856,7 +939,7 @@ TEST_P(EndToEndTestWithTls, SimpleRequestResponseWithIetfDraftSupport) {
ASSERT_TRUE(Initialize());
return;
}
- QuicVersionInitializeSupportForIetfDraft(1);
+ QuicVersionInitializeSupportForIetfDraft();
ASSERT_TRUE(Initialize());
EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
@@ -891,8 +974,7 @@ TEST_P(EndToEndTestWithTls, NoUndecryptablePackets) {
EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
EXPECT_EQ("200", client_->response_headers()->find(":status")->second);
- QuicConnectionStats client_stats =
- client_->client()->client_session()->connection()->GetStats();
+ QuicConnectionStats client_stats = GetClientConnection()->GetStats();
EXPECT_EQ(0u, client_stats.undecryptable_packets_received);
server_thread_->Pause();
@@ -935,10 +1017,13 @@ TEST_P(EndToEndTestWithTls, MultipleRequestResponse) {
}
TEST_P(EndToEndTest, MultipleRequestResponseZeroConnectionID) {
- QuicConnectionId connection_id = QuicUtils::CreateZeroConnectionId(
- GetParam().negotiated_version.transport_version);
- override_server_connection_id_ = &connection_id;
- expected_server_connection_id_length_ = connection_id.length();
+ if (!QuicUtils::VariableLengthConnectionIdAllowedForVersion(
+ GetParam().negotiated_version.transport_version)) {
+ ASSERT_TRUE(Initialize());
+ return;
+ }
+ override_server_connection_id_length_ = 0;
+ expected_server_connection_id_length_ = 0;
ASSERT_TRUE(Initialize());
EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
@@ -1195,7 +1280,7 @@ TEST_P(EndToEndTest, LargePostZeroRTTFailure) {
client_->SendCustomSynchronousRequest(headers, body));
// The same session is used for both hellos, so the number of hellos sent on
// that session is 2.
- EXPECT_EQ(2, client_->client()->client_session()->GetNumSentClientHellos());
+ EXPECT_EQ(2, GetClientSession()->GetNumSentClientHellos());
if (ServerSendsVersionNegotiation()) {
EXPECT_EQ(3, client_->client()->GetNumSentClientHellos());
} else {
@@ -1211,7 +1296,7 @@ TEST_P(EndToEndTest, LargePostZeroRTTFailure) {
EXPECT_EQ(kFooResponseBody,
client_->SendCustomSynchronousRequest(headers, body));
- EXPECT_EQ(1, client_->client()->client_session()->GetNumSentClientHellos());
+ EXPECT_EQ(1, GetClientSession()->GetNumSentClientHellos());
if (ServerSendsVersionNegotiation()) {
EXPECT_EQ(2, client_->client()->GetNumSentClientHellos());
} else {
@@ -1232,7 +1317,7 @@ TEST_P(EndToEndTest, LargePostZeroRTTFailure) {
client_->SendCustomSynchronousRequest(headers, body));
// The same session is used for both hellos, so the number of hellos sent on
// that session is 2.
- EXPECT_EQ(2, client_->client()->client_session()->GetNumSentClientHellos());
+ EXPECT_EQ(2, GetClientSession()->GetNumSentClientHellos());
if (ServerSendsVersionNegotiation()) {
EXPECT_EQ(3, client_->client()->GetNumSentClientHellos());
} else {
@@ -1250,7 +1335,7 @@ TEST_P(EndToEndTest, SynchronousRequestZeroRTTFailure) {
EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
// The same session is used for both hellos, so the number of hellos sent on
// that session is 2.
- EXPECT_EQ(2, client_->client()->client_session()->GetNumSentClientHellos());
+ EXPECT_EQ(2, GetClientSession()->GetNumSentClientHellos());
if (ServerSendsVersionNegotiation()) {
EXPECT_EQ(3, client_->client()->GetNumSentClientHellos());
} else {
@@ -1265,7 +1350,7 @@ TEST_P(EndToEndTest, SynchronousRequestZeroRTTFailure) {
ASSERT_TRUE(client_->client()->connected());
EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
- EXPECT_EQ(1, client_->client()->client_session()->GetNumSentClientHellos());
+ EXPECT_EQ(1, GetClientSession()->GetNumSentClientHellos());
if (ServerSendsVersionNegotiation()) {
EXPECT_EQ(2, client_->client()->GetNumSentClientHellos());
} else {
@@ -1284,7 +1369,7 @@ TEST_P(EndToEndTest, SynchronousRequestZeroRTTFailure) {
ASSERT_TRUE(client_->client()->connected());
EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
- EXPECT_EQ(2, client_->client()->client_session()->GetNumSentClientHellos());
+ EXPECT_EQ(2, GetClientSession()->GetNumSentClientHellos());
if (ServerSendsVersionNegotiation()) {
EXPECT_EQ(3, client_->client()->GetNumSentClientHellos());
} else {
@@ -1310,7 +1395,7 @@ TEST_P(EndToEndTest, LargePostSynchronousRequest) {
client_->SendCustomSynchronousRequest(headers, body));
// The same session is used for both hellos, so the number of hellos sent on
// that session is 2.
- EXPECT_EQ(2, client_->client()->client_session()->GetNumSentClientHellos());
+ EXPECT_EQ(2, GetClientSession()->GetNumSentClientHellos());
if (ServerSendsVersionNegotiation()) {
EXPECT_EQ(3, client_->client()->GetNumSentClientHellos());
} else {
@@ -1326,7 +1411,7 @@ TEST_P(EndToEndTest, LargePostSynchronousRequest) {
EXPECT_EQ(kFooResponseBody,
client_->SendCustomSynchronousRequest(headers, body));
- EXPECT_EQ(1, client_->client()->client_session()->GetNumSentClientHellos());
+ EXPECT_EQ(1, GetClientSession()->GetNumSentClientHellos());
if (ServerSendsVersionNegotiation()) {
EXPECT_EQ(2, client_->client()->GetNumSentClientHellos());
} else {
@@ -1346,7 +1431,7 @@ TEST_P(EndToEndTest, LargePostSynchronousRequest) {
EXPECT_EQ(kFooResponseBody,
client_->SendCustomSynchronousRequest(headers, body));
- EXPECT_EQ(2, client_->client()->client_session()->GetNumSentClientHellos());
+ EXPECT_EQ(2, GetClientSession()->GetNumSentClientHellos());
if (ServerSendsVersionNegotiation()) {
EXPECT_EQ(3, client_->client()->GetNumSentClientHellos());
} else {
@@ -1429,7 +1514,7 @@ TEST_P(EndToEndTestWithTls, DoNotSetSendAlarmIfConnectionFlowControlBlocked) {
const uint64_t flow_control_window =
server_config_.GetInitialStreamFlowControlWindowToSend();
QuicSpdyClientStream* stream = client_->GetOrCreateStream();
- QuicSession* session = client_->client()->client_session();
+ QuicSession* session = GetClientSession();
QuicFlowControllerPeer::SetSendWindowOffset(stream->flow_controller(), 0);
QuicFlowControllerPeer::SetSendWindowOffset(session->flow_controller(), 0);
EXPECT_TRUE(stream->flow_controller()->IsBlocked());
@@ -1471,7 +1556,7 @@ TEST_P(EndToEndTest, InvalidStream) {
// Force the client to write with a stream ID belonging to a nonexistent
// server-side stream.
- QuicSpdySession* session = client_->client()->client_session();
+ QuicSpdySession* session = GetClientSession();
QuicSessionPeer::SetNextOutgoingBidirectionalStreamId(
session, GetNthServerInitiatedBidirectionalId(0));
@@ -1585,8 +1670,8 @@ TEST_P(EndToEndTestWithTls, MaxIncomingDynamicStreamsLimitRespected) {
// Make the client misbehave after negotiation.
const int kServerMaxStreams = kMaxStreamsMinimumIncrement + 1;
- QuicSessionPeer::SetMaxOpenOutgoingStreams(
- client_->client()->client_session(), kServerMaxStreams + 1);
+ QuicSessionPeer::SetMaxOpenOutgoingStreams(GetClientSession(),
+ kServerMaxStreams + 1);
SpdyHeaderBlock headers;
headers[":method"] = "POST";
@@ -1609,8 +1694,8 @@ TEST_P(EndToEndTestWithTls, MaxIncomingDynamicStreamsLimitRespected) {
TEST_P(EndToEndTest, SetIndependentMaxIncomingDynamicStreamsLimits) {
// Each endpoint can set max incoming dynamic streams independently.
- const uint32_t kClientMaxIncomingDynamicStreams = 2;
- const uint32_t kServerMaxIncomingDynamicStreams = 1;
+ const uint32_t kClientMaxIncomingDynamicStreams = 4;
+ const uint32_t kServerMaxIncomingDynamicStreams = 3;
client_config_.SetMaxIncomingBidirectionalStreamsToSend(
kClientMaxIncomingDynamicStreams);
server_config_.SetMaxIncomingBidirectionalStreamsToSend(
@@ -1624,7 +1709,7 @@ TEST_P(EndToEndTest, SetIndependentMaxIncomingDynamicStreamsLimits) {
EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
// The client has received the server's limit and vice versa.
- QuicSpdyClientSession* client_session = client_->client()->client_session();
+ QuicSpdyClientSession* client_session = GetClientSession();
// The value returned by max_allowed... includes the Crypto and Header
// stream (created as a part of initialization). The config. values,
// above, are treated as "number of requests/responses" - that is, they do
@@ -1635,10 +1720,7 @@ TEST_P(EndToEndTest, SetIndependentMaxIncomingDynamicStreamsLimits) {
VersionHasIetfQuicFrames(
client_session->connection()->transport_version())
? QuicSessionPeer::v99_streamid_manager(client_session)
- ->max_allowed_outgoing_bidirectional_streams() -
- QuicSessionPeer::v99_bidirectional_stream_id_manager(
- client_session)
- ->outgoing_static_stream_count()
+ ->max_allowed_outgoing_bidirectional_streams()
: QuicSessionPeer::GetStreamIdManager(client_session)
->max_open_outgoing_streams();
size_t client_max_open_outgoing_unidirectional_streams =
@@ -1646,9 +1728,7 @@ TEST_P(EndToEndTest, SetIndependentMaxIncomingDynamicStreamsLimits) {
client_session->connection()->transport_version())
? QuicSessionPeer::v99_streamid_manager(client_session)
->max_allowed_outgoing_unidirectional_streams() -
- QuicSessionPeer::v99_unidirectional_stream_id_manager(
- client_session)
- ->outgoing_static_stream_count()
+ client_session->num_expected_unidirectional_static_streams()
: QuicSessionPeer::GetStreamIdManager(client_session)
->max_open_outgoing_streams();
EXPECT_EQ(kServerMaxIncomingDynamicStreams,
@@ -1669,15 +1749,14 @@ TEST_P(EndToEndTest, SetIndependentMaxIncomingDynamicStreamsLimits) {
server_session->connection()->transport_version())
? QuicSessionPeer::v99_streamid_manager(server_session)
->max_allowed_outgoing_unidirectional_streams() -
- QuicSessionPeer::v99_unidirectional_stream_id_manager(
- server_session)
- ->outgoing_static_stream_count()
+ server_session->num_expected_unidirectional_static_streams()
: QuicSessionPeer::GetStreamIdManager(server_session)
->max_open_outgoing_streams();
EXPECT_EQ(kClientMaxIncomingDynamicStreams,
server_max_open_outgoing_bidirectional_streams);
EXPECT_EQ(kClientMaxIncomingDynamicStreams,
server_max_open_outgoing_unidirectional_streams);
+
server_thread_->Resume();
}
@@ -1733,7 +1812,7 @@ TEST_P(EndToEndTest, ClientSuggestsRTT) {
QuicServerPeer::GetDispatcher(server_thread_->server());
ASSERT_EQ(1u, dispatcher->session_map().size());
const QuicSentPacketManager& client_sent_packet_manager =
- client_->client()->client_session()->connection()->sent_packet_manager();
+ GetClientConnection()->sent_packet_manager();
const QuicSentPacketManager* server_sent_packet_manager =
GetSentPacketManagerFromFirstServerSession();
@@ -1762,7 +1841,7 @@ TEST_P(EndToEndTest, ClientSuggestsIgnoredRTT) {
QuicServerPeer::GetDispatcher(server_thread_->server());
ASSERT_EQ(1u, dispatcher->session_map().size());
const QuicSentPacketManager& client_sent_packet_manager =
- client_->client()->client_session()->connection()->sent_packet_manager();
+ GetClientConnection()->sent_packet_manager();
const QuicSentPacketManager* server_sent_packet_manager =
GetSentPacketManagerFromFirstServerSession();
@@ -1786,7 +1865,7 @@ TEST_P(EndToEndTest, MaxInitialRTT) {
// Pause the server so we can access the server's internals without races.
server_thread_->Pause();
const QuicSentPacketManager& client_sent_packet_manager =
- client_->client()->client_session()->connection()->sent_packet_manager();
+ GetClientConnection()->sent_packet_manager();
// Now that acks have been exchanged, the RTT estimate has decreased on the
// server and is not infinite on the client.
@@ -1812,7 +1891,7 @@ TEST_P(EndToEndTest, MinInitialRTT) {
// Pause the server so we can access the server's internals without races.
server_thread_->Pause();
const QuicSentPacketManager& client_sent_packet_manager =
- client_->client()->client_session()->connection()->sent_packet_manager();
+ GetClientConnection()->sent_packet_manager();
const QuicSentPacketManager& server_sent_packet_manager =
GetServerConnection()->sent_packet_manager();
@@ -1841,15 +1920,10 @@ TEST_P(EndToEndTest, 0ByteConnectionId) {
EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
EXPECT_EQ("200", client_->response_headers()->find(":status")->second);
- QuicConnection* client_connection =
- client_->client()->client_session()->connection();
+ QuicConnection* client_connection = GetClientConnection();
QuicPacketHeader* header =
QuicConnectionPeer::GetLastHeader(client_connection);
- if (!GetQuicRestartFlag(quic_do_not_override_connection_id)) {
- EXPECT_EQ(CONNECTION_ID_ABSENT, header->destination_connection_id_included);
- } else {
- EXPECT_EQ(CONNECTION_ID_ABSENT, header->source_connection_id_included);
- }
+ EXPECT_EQ(CONNECTION_ID_ABSENT, header->source_connection_id_included);
}
TEST_P(EndToEndTestWithTls, 8ByteConnectionId) {
@@ -1864,8 +1938,7 @@ TEST_P(EndToEndTestWithTls, 8ByteConnectionId) {
EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
EXPECT_EQ("200", client_->response_headers()->find(":status")->second);
- QuicConnection* client_connection =
- client_->client()->client_session()->connection();
+ QuicConnection* client_connection = GetClientConnection();
QuicPacketHeader* header =
QuicConnectionPeer::GetLastHeader(client_connection);
EXPECT_EQ(CONNECTION_ID_PRESENT, header->destination_connection_id_included);
@@ -1884,8 +1957,7 @@ TEST_P(EndToEndTestWithTls, 15ByteConnectionId) {
// Our server is permissive and allows for out of bounds values.
EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
EXPECT_EQ("200", client_->response_headers()->find(":status")->second);
- QuicConnection* client_connection =
- client_->client()->client_session()->connection();
+ QuicConnection* client_connection = GetClientConnection();
QuicPacketHeader* header =
QuicConnectionPeer::GetLastHeader(client_connection);
EXPECT_EQ(CONNECTION_ID_PRESENT, header->destination_connection_id_included);
@@ -1905,7 +1977,6 @@ TEST_P(EndToEndTestWithTls, ResetConnection) {
// TODO(nharper): Needs to get turned back to EndToEndTestWithTls
// when we figure out why the test doesn't work on chrome.
TEST_P(EndToEndTest, MaxStreamsUberTest) {
- SetQuicFlag(FLAGS_quic_headers_stream_id_in_v99, 0);
// Connect with lower fake packet loss than we'd like to test. Until
// b/10126687 is fixed, losing handshake packets is pretty brutal.
SetPacketLossPercentage(1);
@@ -1936,7 +2007,7 @@ TEST_P(EndToEndTestWithTls, StreamCancelErrorTest) {
EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
- QuicSession* session = client_->client()->client_session();
+ QuicSession* session = GetClientSession();
// Lose the request.
SetPacketLossPercentage(100);
EXPECT_LT(0, client_->SendRequest("/small_response"));
@@ -2006,14 +2077,13 @@ TEST_P(EndToEndTest, ConnectionMigrationClientPortChanged) {
int new_port =
client_->client()->network_helper()->GetLatestClientAddress().port();
QuicClientPeer::SetClientPort(client_->client(), new_port);
- QuicConnectionPeer::SetSelfAddress(
- client_->client()->client_session()->connection(),
- QuicSocketAddress(client_->client()
- ->client_session()
- ->connection()
- ->self_address()
- .host(),
- new_port));
+ QuicConnectionPeer::SetSelfAddress(GetClientConnection(),
+ QuicSocketAddress(client_->client()
+ ->client_session()
+ ->connection()
+ ->self_address()
+ .host(),
+ new_port));
// Register the new FD for epoll events.
int new_fd = client_->client()->GetLatestFD();
@@ -2086,9 +2156,8 @@ TEST_P(EndToEndTest, DifferentFlowControlWindows) {
->ReceivedInitialSessionFlowControlWindowBytes());
EXPECT_EQ(kServerStreamIFCW, QuicFlowControllerPeer::SendWindowOffset(
stream->flow_controller()));
- EXPECT_EQ(kServerSessionIFCW,
- QuicFlowControllerPeer::SendWindowOffset(
- client_->client()->client_session()->flow_controller()));
+ EXPECT_EQ(kServerSessionIFCW, QuicFlowControllerPeer::SendWindowOffset(
+ GetClientSession()->flow_controller()));
// Server should have the right values for client's receive window.
server_thread_->Pause();
@@ -2143,9 +2212,8 @@ TEST_P(EndToEndTest, NegotiatedServerInitialFlowControlWindow) {
->ReceivedInitialSessionFlowControlWindowBytes());
EXPECT_EQ(kExpectedStreamIFCW, QuicFlowControllerPeer::SendWindowOffset(
stream->flow_controller()));
- EXPECT_EQ(kExpectedSessionIFCW,
- QuicFlowControllerPeer::SendWindowOffset(
- client_->client()->client_session()->flow_controller()));
+ EXPECT_EQ(kExpectedSessionIFCW, QuicFlowControllerPeer::SendWindowOffset(
+ GetClientSession()->flow_controller()));
}
TEST_P(EndToEndTest, HeadersAndCryptoStreamsNoConnectionFlowControl) {
@@ -2166,12 +2234,12 @@ TEST_P(EndToEndTest, HeadersAndCryptoStreamsNoConnectionFlowControl) {
EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
server_thread_->WaitForCryptoHandshakeConfirmed();
- QuicCryptoStream* crypto_stream = QuicSessionPeer::GetMutableCryptoStream(
- client_->client()->client_session());
+ QuicCryptoStream* crypto_stream =
+ QuicSessionPeer::GetMutableCryptoStream(GetClientSession());
// In v47 and later, the crypto handshake (sent in CRYPTO frames) is not
// subject to flow control.
const QuicTransportVersion transport_version =
- client_->client()->client_session()->connection()->transport_version();
+ GetClientConnection()->transport_version();
if (!QuicVersionUsesCryptoFrames(transport_version)) {
EXPECT_LT(QuicFlowControllerPeer::SendWindowSize(
crypto_stream->flow_controller()),
@@ -2180,9 +2248,8 @@ TEST_P(EndToEndTest, HeadersAndCryptoStreamsNoConnectionFlowControl) {
// When stream type is enabled, control streams will send settings and
// contribute to flow control windows, so this expectation is no longer valid.
if (!VersionHasStreamType(transport_version)) {
- EXPECT_EQ(kSessionIFCW,
- QuicFlowControllerPeer::SendWindowSize(
- client_->client()->client_session()->flow_controller()));
+ EXPECT_EQ(kSessionIFCW, QuicFlowControllerPeer::SendWindowSize(
+ GetClientSession()->flow_controller()));
}
// Send a request with no body, and verify that the connection level window
@@ -2194,14 +2261,13 @@ TEST_P(EndToEndTest, HeadersAndCryptoStreamsNoConnectionFlowControl) {
return;
}
- QuicHeadersStream* headers_stream = QuicSpdySessionPeer::GetHeadersStream(
- client_->client()->client_session());
+ QuicHeadersStream* headers_stream =
+ QuicSpdySessionPeer::GetHeadersStream(GetClientSession());
EXPECT_LT(
QuicFlowControllerPeer::SendWindowSize(headers_stream->flow_controller()),
kStreamIFCW);
- EXPECT_EQ(kSessionIFCW,
- QuicFlowControllerPeer::SendWindowSize(
- client_->client()->client_session()->flow_controller()));
+ EXPECT_EQ(kSessionIFCW, QuicFlowControllerPeer::SendWindowSize(
+ GetClientSession()->flow_controller()));
// Server should be in a similar state: connection flow control window should
// not have any bytes marked as received.
@@ -2222,95 +2288,97 @@ TEST_P(EndToEndTest, FlowControlsSynced) {
EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
server_thread_->WaitForCryptoHandshakeConfirmed();
+ QuicSpdySession* const client_session = GetClientSession();
+ const QuicTransportVersion version =
+ client_session->connection()->transport_version();
+
+ if (VersionUsesQpack(version)) {
+ // Make sure that the client has received the initial SETTINGS frame, which
+ // is sent in the first packet on the control stream.
+ while (!QuicSpdySessionPeer::GetReceiveControlStream(client_session)) {
+ client_->client()->WaitForEvents();
+ }
+ }
+
+ // Make sure that all data sent by the client has been received by the server
+ // (and the ack received by the client).
+ while (client_session->HasUnackedStreamData()) {
+ client_->client()->WaitForEvents();
+ }
+
server_thread_->Pause();
- QuicSpdySession* const client_session = client_->client()->client_session();
- auto* server_session = static_cast<QuicSpdySession*>(GetServerSession());
-
- if (VersionHasStreamType(client_->client()
- ->client_session()
- ->connection()
- ->transport_version())) {
- // Settings frame will be sent through control streams, which contribute
- // to the session's flow controller. And due to the timing issue described
- // below, the settings frame might not be received.
- HttpEncoder encoder;
- SettingsFrame settings;
- settings.values[6] = kDefaultMaxUncompressedHeaderSize;
- std::unique_ptr<char[]> buffer;
- auto header_length = encoder.SerializeSettingsFrame(settings, &buffer);
+
+ QuicSpdySession* const server_session = GetServerSession();
+ ExpectFlowControlsSynced(client_session, server_session);
+
+ // Check control streams.
+ if (VersionUsesQpack(version)) {
+ ExpectFlowControlsSynced(
+ QuicSpdySessionPeer::GetReceiveControlStream(client_session),
+ QuicSpdySessionPeer::GetSendControlStream(server_session));
+ ExpectFlowControlsSynced(
+ QuicSpdySessionPeer::GetSendControlStream(client_session),
+ QuicSpdySessionPeer::GetReceiveControlStream(server_session));
+ }
+
+ // Check crypto stream.
+ if (!QuicVersionUsesCryptoFrames(version)) {
+ ExpectFlowControlsSynced(
+ QuicSessionPeer::GetMutableCryptoStream(client_session),
+ QuicSessionPeer::GetMutableCryptoStream(server_session));
+ }
+
+ // Check headers stream.
+ if (!VersionHasStreamType(version)) {
+ SpdyFramer spdy_framer(SpdyFramer::ENABLE_COMPRESSION);
+ SpdySettingsIR settings_frame;
+ settings_frame.AddSetting(SETTINGS_MAX_HEADER_LIST_SIZE,
+ kDefaultMaxUncompressedHeaderSize);
+ SpdySerializedFrame frame(spdy_framer.SerializeFrame(settings_frame));
+
+ QuicFlowController* client_header_stream_flow_controller =
+ QuicSpdySessionPeer::GetHeadersStream(client_session)
+ ->flow_controller();
+ QuicFlowController* server_header_stream_flow_controller =
+ QuicSpdySessionPeer::GetHeadersStream(server_session)
+ ->flow_controller();
+ // Both client and server are sending this SETTINGS frame, and the send
+ // window is consumed. But because of timing issue, the server may send or
+ // not send the frame, and the client may send/ not send / receive / not
+ // receive the frame.
+ // TODO(fayang): Rewrite this part because it is hacky.
QuicByteCount win_difference1 = QuicFlowControllerPeer::ReceiveWindowSize(
- server_session->flow_controller()) -
+ server_header_stream_flow_controller) -
QuicFlowControllerPeer::SendWindowSize(
- client_session->flow_controller());
+ client_header_stream_flow_controller);
+ if (win_difference1 != 0) {
+ EXPECT_EQ(frame.size(), win_difference1);
+ }
+
QuicByteCount win_difference2 = QuicFlowControllerPeer::ReceiveWindowSize(
- client_session->flow_controller()) -
+ client_header_stream_flow_controller) -
QuicFlowControllerPeer::SendWindowSize(
- server_session->flow_controller());
- EXPECT_TRUE(win_difference1 == 0 ||
- win_difference1 ==
- header_length +
- QuicDataWriter::GetVarInt62Len(kControlStream));
- EXPECT_TRUE(win_difference2 == 0 ||
- win_difference2 ==
- header_length +
- QuicDataWriter::GetVarInt62Len(kControlStream));
- // The test returns early because in this version, headers stream no longer
- // sends settings.
- return;
- }
+ server_header_stream_flow_controller);
+ if (win_difference2 != 0) {
+ EXPECT_EQ(frame.size(), win_difference2);
+ }
- ExpectFlowControlsSynced(client_session->flow_controller(),
- server_session->flow_controller());
- if (!QuicVersionUsesCryptoFrames(client_->client()
- ->client_session()
- ->connection()
- ->transport_version())) {
- ExpectFlowControlsSynced(
- QuicSessionPeer::GetMutableCryptoStream(client_session)
- ->flow_controller(),
- QuicSessionPeer::GetMutableCryptoStream(server_session)
- ->flow_controller());
- }
- SpdyFramer spdy_framer(SpdyFramer::ENABLE_COMPRESSION);
- SpdySettingsIR settings_frame;
- settings_frame.AddSetting(SETTINGS_MAX_HEADER_LIST_SIZE,
- kDefaultMaxUncompressedHeaderSize);
- SpdySerializedFrame frame(spdy_framer.SerializeFrame(settings_frame));
- QuicFlowController* client_header_stream_flow_controller =
- QuicSpdySessionPeer::GetHeadersStream(client_session)->flow_controller();
- QuicFlowController* server_header_stream_flow_controller =
- QuicSpdySessionPeer::GetHeadersStream(server_session)->flow_controller();
- // Both client and server are sending this SETTINGS frame, and the send
- // window is consumed. But because of timing issue, the server may send or
- // not send the frame, and the client may send/ not send / receive / not
- // receive the frame.
- // TODO(fayang): Rewrite this part because it is hacky.
- QuicByteCount win_difference1 = QuicFlowControllerPeer::ReceiveWindowSize(
- server_header_stream_flow_controller) -
- QuicFlowControllerPeer::SendWindowSize(
- client_header_stream_flow_controller);
- QuicByteCount win_difference2 = QuicFlowControllerPeer::ReceiveWindowSize(
- client_header_stream_flow_controller) -
- QuicFlowControllerPeer::SendWindowSize(
- server_header_stream_flow_controller);
- EXPECT_TRUE(win_difference1 == 0 || win_difference1 == frame.size());
- EXPECT_TRUE(win_difference2 == 0 || win_difference2 == frame.size());
-
- // Client *may* have received the SETTINGs frame.
- // TODO(fayang): Rewrite this part because it is hacky.
- float ratio1 = static_cast<float>(QuicFlowControllerPeer::ReceiveWindowSize(
- client_session->flow_controller())) /
- QuicFlowControllerPeer::ReceiveWindowSize(
- QuicSpdySessionPeer::GetHeadersStream(client_session)
- ->flow_controller());
- float ratio2 = static_cast<float>(QuicFlowControllerPeer::ReceiveWindowSize(
- client_session->flow_controller())) /
- (QuicFlowControllerPeer::ReceiveWindowSize(
- QuicSpdySessionPeer::GetHeadersStream(client_session)
- ->flow_controller()) +
- frame.size());
- EXPECT_TRUE(ratio1 == kSessionToStreamRatio ||
- ratio2 == kSessionToStreamRatio);
+ // Client *may* have received the SETTINGs frame.
+ // TODO(fayang): Rewrite this part because it is hacky.
+ float ratio1 = static_cast<float>(QuicFlowControllerPeer::ReceiveWindowSize(
+ client_session->flow_controller())) /
+ QuicFlowControllerPeer::ReceiveWindowSize(
+ QuicSpdySessionPeer::GetHeadersStream(client_session)
+ ->flow_controller());
+ float ratio2 = static_cast<float>(QuicFlowControllerPeer::ReceiveWindowSize(
+ client_session->flow_controller())) /
+ (QuicFlowControllerPeer::ReceiveWindowSize(
+ QuicSpdySessionPeer::GetHeadersStream(client_session)
+ ->flow_controller()) +
+ frame.size());
+ EXPECT_TRUE(ratio1 == kSessionToStreamRatio ||
+ ratio2 == kSessionToStreamRatio);
+ }
server_thread_->Resume();
}
@@ -2402,10 +2470,11 @@ TEST_P(EndToEndTest, AckNotifierWithPacketLossAndBlockedSocket) {
// Determine size of compressed headers.
NoopDecoderStreamErrorDelegate decoder_stream_error_delegate;
NoopQpackStreamSenderDelegate encoder_stream_sender_delegate;
- QpackEncoder qpack_encoder(&decoder_stream_error_delegate,
- &encoder_stream_sender_delegate);
+ QpackEncoder qpack_encoder(&decoder_stream_error_delegate);
+ qpack_encoder.set_qpack_stream_sender_delegate(
+ &encoder_stream_sender_delegate);
std::string encoded_headers =
- qpack_encoder.EncodeHeaderList(/* stream_id = */ 0, &headers);
+ qpack_encoder.EncodeHeaderList(/* stream_id = */ 0, headers);
header_size = encoded_headers.size();
}
@@ -2439,18 +2508,10 @@ TEST_P(EndToEndTestWithTls, ServerSendPublicReset) {
ASSERT_TRUE(Initialize());
EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
- QuicConnection* client_connection =
- client_->client()->client_session()->connection();
- if (SupportsIetfQuicWithTls(client_connection->version())) {
- // TLS handshake does not support stateless reset token yet.
- return;
- }
- QuicUint128 stateless_reset_token = 0;
- if (client_connection->version().handshake_protocol == PROTOCOL_QUIC_CRYPTO) {
- QuicConfig* config = client_->client()->session()->config();
- EXPECT_TRUE(config->HasReceivedStatelessResetToken());
- stateless_reset_token = config->ReceivedStatelessResetToken();
- }
+ QuicConnection* client_connection = GetClientConnection();
+ QuicConfig* config = client_->client()->session()->config();
+ EXPECT_TRUE(config->HasReceivedStatelessResetToken());
+ QuicUint128 stateless_reset_token = config->ReceivedStatelessResetToken();
// Send the public reset.
QuicConnectionId connection_id = client_connection->connection_id();
@@ -2485,18 +2546,10 @@ TEST_P(EndToEndTestWithTls, ServerSendPublicResetWithDifferentConnectionId) {
ASSERT_TRUE(Initialize());
EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
- QuicConnection* client_connection =
- client_->client()->client_session()->connection();
- if (SupportsIetfQuicWithTls(client_connection->version())) {
- // TLS handshake does not support stateless reset token yet.
- return;
- }
- QuicUint128 stateless_reset_token = 0;
- if (client_connection->version().handshake_protocol == PROTOCOL_QUIC_CRYPTO) {
- QuicConfig* config = client_->client()->session()->config();
- EXPECT_TRUE(config->HasReceivedStatelessResetToken());
- stateless_reset_token = config->ReceivedStatelessResetToken();
- }
+ QuicConnection* client_connection = GetClientConnection();
+ QuicConfig* config = client_->client()->session()->config();
+ EXPECT_TRUE(config->HasReceivedStatelessResetToken());
+ QuicUint128 stateless_reset_token = config->ReceivedStatelessResetToken();
// Send the public reset.
QuicConnectionId incorrect_connection_id = TestConnectionId(
TestConnectionIdToUInt64(client_connection->connection_id()) + 1);
@@ -2506,8 +2559,7 @@ TEST_P(EndToEndTestWithTls, ServerSendPublicResetWithDifferentConnectionId) {
Perspective::IS_SERVER, kQuicDefaultConnectionIdLength);
std::unique_ptr<QuicEncryptedPacket> packet;
testing::NiceMock<MockQuicConnectionDebugVisitor> visitor;
- client_->client()->client_session()->connection()->set_debug_visitor(
- &visitor);
+ GetClientConnection()->set_debug_visitor(&visitor);
if (VersionHasIetfInvariantHeader(client_connection->transport_version())) {
packet = framer.BuildIetfStatelessResetPacket(incorrect_connection_id,
stateless_reset_token);
@@ -2538,7 +2590,7 @@ TEST_P(EndToEndTestWithTls, ServerSendPublicResetWithDifferentConnectionId) {
EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
EXPECT_EQ("200", client_->response_headers()->find(":status")->second);
- client_->client()->client_session()->connection()->set_debug_visitor(nullptr);
+ GetClientConnection()->set_debug_visitor(nullptr);
}
// Send a public reset from the client for a different connection ID.
@@ -2548,9 +2600,7 @@ TEST_P(EndToEndTestWithTls, ClientSendPublicResetWithDifferentConnectionId) {
// Send the public reset.
QuicConnectionId incorrect_connection_id = TestConnectionId(
- TestConnectionIdToUInt64(
- client_->client()->client_session()->connection()->connection_id()) +
- 1);
+ TestConnectionIdToUInt64(GetClientConnection()->connection_id()) + 1);
QuicPublicResetPacket header;
header.connection_id = incorrect_connection_id;
QuicFramer framer(server_supported_versions_, QuicTime::Zero(),
@@ -2576,14 +2626,14 @@ TEST_P(EndToEndTestWithTls,
EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
// Send the version negotiation packet.
- QuicConnection* client_connection =
- client_->client()->client_session()->connection();
+ QuicConnection* client_connection = GetClientConnection();
QuicConnectionId incorrect_connection_id = TestConnectionId(
TestConnectionIdToUInt64(client_connection->connection_id()) + 1);
std::unique_ptr<QuicEncryptedPacket> packet(
QuicFramer::BuildVersionNegotiationPacket(
incorrect_connection_id, EmptyQuicConnectionId(),
VersionHasIetfInvariantHeader(client_connection->transport_version()),
+ client_connection->version().HasLengthPrefixedConnectionIds(),
server_supported_versions_));
testing::NiceMock<MockQuicConnectionDebugVisitor> visitor;
client_connection->set_debug_visitor(&visitor);
@@ -2698,9 +2748,9 @@ TEST_P(EndToEndTestWithTls, BadEncryptedData) {
EXPECT_EQ("200", client_->response_headers()->find(":status")->second);
std::unique_ptr<QuicEncryptedPacket> packet(ConstructEncryptedPacket(
- client_->client()->client_session()->connection()->connection_id(),
- EmptyQuicConnectionId(), false, false, 1, "At least 20 characters.",
- CONNECTION_ID_PRESENT, CONNECTION_ID_ABSENT, PACKET_4BYTE_PACKET_NUMBER));
+ GetClientConnection()->connection_id(), EmptyQuicConnectionId(), false,
+ false, 1, "At least 20 characters.", CONNECTION_ID_PRESENT,
+ CONNECTION_ID_ABSENT, PACKET_4BYTE_PACKET_NUMBER));
// Damage the encrypted data.
std::string damaged_packet(packet->data(), packet->length());
damaged_packet[30] ^= 0x01;
@@ -2741,7 +2791,7 @@ TEST_P(EndToEndTestWithTls, CanceledStreamDoesNotBecomeZombie) {
// Cancel the stream.
stream->Reset(QUIC_STREAM_CANCELLED);
- QuicSession* session = client_->client()->client_session();
+ QuicSession* session = GetClientSession();
// Verify canceled stream does not become zombie.
EXPECT_TRUE(QuicSessionPeer::zombie_streams(session).empty());
EXPECT_EQ(1u, QuicSessionPeer::closed_streams(session).size());
@@ -3008,7 +3058,6 @@ class EndToEndTestServerPush : public EndToEndTest {
const size_t kNumMaxStreams = 10;
EndToEndTestServerPush() : EndToEndTest() {
- SetQuicFlag(FLAGS_quic_headers_stream_id_in_v99, 0);
client_config_.SetMaxIncomingBidirectionalStreamsToSend(kNumMaxStreams);
server_config_.SetMaxIncomingBidirectionalStreamsToSend(kNumMaxStreams);
client_config_.SetMaxIncomingUnidirectionalStreamsToSend(kNumMaxStreams);
@@ -3086,12 +3135,19 @@ TEST_P(EndToEndTestServerPush, ServerPush) {
QUIC_DVLOG(1) << "send request for /push_example";
EXPECT_EQ(kBody, client_->SendSynchronousRequest(
"https://example.com/push_example"));
- QuicHeadersStream* headers_stream = QuicSpdySessionPeer::GetHeadersStream(
- client_->client()->client_session());
- QuicStreamSequencer* sequencer = QuicStreamPeer::sequencer(headers_stream);
- // Headers stream's sequencer buffer shouldn't be released because server push
- // hasn't finished yet.
- EXPECT_TRUE(QuicStreamSequencerPeer::IsUnderlyingBufferAllocated(sequencer));
+ QuicStreamSequencer* sequencer;
+ if (!VersionUsesQpack(client_->client()
+ ->client_session()
+ ->connection()
+ ->transport_version())) {
+ QuicHeadersStream* headers_stream =
+ QuicSpdySessionPeer::GetHeadersStream(GetClientSession());
+ sequencer = QuicStreamPeer::sequencer(headers_stream);
+ // Headers stream's sequencer buffer shouldn't be released because server
+ // push hasn't finished yet.
+ EXPECT_TRUE(
+ QuicStreamSequencerPeer::IsUnderlyingBufferAllocated(sequencer));
+ }
for (const std::string& url : push_urls) {
QUIC_DVLOG(1) << "send request for pushed stream on url " << url;
@@ -3101,7 +3157,13 @@ TEST_P(EndToEndTestServerPush, ServerPush) {
QUIC_DVLOG(1) << "response body " << response_body;
EXPECT_EQ(expected_body, response_body);
}
- EXPECT_FALSE(QuicStreamSequencerPeer::IsUnderlyingBufferAllocated(sequencer));
+ if (!VersionUsesQpack(client_->client()
+ ->client_session()
+ ->connection()
+ ->transport_version())) {
+ EXPECT_FALSE(
+ QuicStreamSequencerPeer::IsUnderlyingBufferAllocated(sequencer));
+ }
}
TEST_P(EndToEndTestServerPush, ServerPushUnderLimit) {
@@ -3342,10 +3404,8 @@ TEST_P(EndToEndTest, DISABLED_TestHugeResponseWithPacketLoss) {
client_.reset(client);
static QuicEpollEvent event(EPOLLOUT);
client_writer_->Initialize(
- QuicConnectionPeer::GetHelper(
- client_->client()->client_session()->connection()),
- QuicConnectionPeer::GetAlarmFactory(
- client_->client()->client_session()->connection()),
+ QuicConnectionPeer::GetHelper(GetClientConnection()),
+ QuicConnectionPeer::GetAlarmFactory(GetClientConnection()),
QuicMakeUnique<ClientDelegate>(client_->client()));
initialized_ = true;
ASSERT_TRUE(client_->client()->connected());
@@ -3362,8 +3422,7 @@ TEST_P(EndToEndTest, AgreeOnStopWaiting) {
ASSERT_TRUE(Initialize());
EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
- QuicConnection* client_connection =
- client_->client()->client_session()->connection();
+ QuicConnection* client_connection = GetClientConnection();
server_thread_->Pause();
QuicConnection* server_connection = GetServerConnection();
// Verify client and server connections agree on the value of
@@ -3381,8 +3440,7 @@ TEST_P(EndToEndTest, AgreeOnStopWaitingWithNoStopWaitingOption) {
ASSERT_TRUE(Initialize());
EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
- QuicConnection* client_connection =
- client_->client()->client_session()->connection();
+ QuicConnection* client_connection = GetClientConnection();
server_thread_->Pause();
QuicConnection* server_connection = GetServerConnection();
// Verify client and server connections agree on the value of
@@ -3397,8 +3455,14 @@ TEST_P(EndToEndTest, ReleaseHeadersStreamBufferWhenIdle) {
// PUSH_PROMISE, its headers stream's sequencer buffer should be released.
ASSERT_TRUE(Initialize());
client_->SendSynchronousRequest("/foo");
- QuicHeadersStream* headers_stream = QuicSpdySessionPeer::GetHeadersStream(
- client_->client()->client_session());
+ if (VersionUsesQpack(client_->client()
+ ->client_session()
+ ->connection()
+ ->transport_version())) {
+ return;
+ }
+ QuicHeadersStream* headers_stream =
+ QuicSpdySessionPeer::GetHeadersStream(GetClientSession());
QuicStreamSequencer* sequencer = QuicStreamPeer::sequencer(headers_stream);
EXPECT_FALSE(QuicStreamSequencerPeer::IsUnderlyingBufferAllocated(sequencer));
}
@@ -3444,8 +3508,7 @@ TEST_P(EndToEndTest, WindowUpdateInAck) {
ASSERT_TRUE(Initialize());
EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
WindowUpdateObserver observer;
- QuicConnection* client_connection =
- client_->client()->client_session()->connection();
+ QuicConnection* client_connection = GetClientConnection();
client_connection->set_debug_visitor(&observer);
// 100KB body.
std::string body(100 * 1024, 'a');
@@ -3462,7 +3525,7 @@ TEST_P(EndToEndTest, WindowUpdateInAck) {
EXPECT_EQ(0u, observer.num_ping_frames());
}
-TEST_P(EndToEndTest, SendStatelessResetTokenInShlo) {
+TEST_P(EndToEndTestWithTls, SendStatelessResetTokenInShlo) {
ASSERT_TRUE(Initialize());
EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
QuicConfig* config = client_->client()->session()->config();
@@ -3647,7 +3710,7 @@ TEST_P(EndToEndTest, RequestAndStreamRstInOnePacket) {
EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
client_->WaitForDelayedAcks();
- QuicSession* session = client_->client()->client_session();
+ QuicSession* session = GetClientSession();
const QuicPacketCount packets_sent_before =
session->connection()->GetStats().packets_sent;
@@ -3667,7 +3730,7 @@ TEST_P(EndToEndTest, RequestAndStreamRstInOnePacket) {
TEST_P(EndToEndTest, ResetStreamOnTtlExpires) {
ASSERT_TRUE(Initialize());
EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
- if (!client_->client()->client_session()->session_decides_what_to_write()) {
+ if (!GetClientSession()->session_decides_what_to_write()) {
return;
}
SetPacketLossPercentage(30);
@@ -3687,7 +3750,7 @@ TEST_P(EndToEndTest, ResetStreamOnTtlExpires) {
TEST_P(EndToEndTest, SendMessages) {
ASSERT_TRUE(Initialize());
EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
- QuicSession* client_session = client_->client()->client_session();
+ QuicSession* client_session = GetClientSession();
QuicConnection* client_connection = client_session->connection();
if (!VersionSupportsMessageFrames(client_connection->transport_version())) {
return;
@@ -3812,10 +3875,8 @@ TEST_P(EndToEndPacketReorderingTest, ReorderedConnectivityProbing) {
server_connection->GetStats().num_connectivity_probing_received);
server_thread_->Resume();
- QuicConnection* client_connection =
- client_->client()->client_session()->connection();
- EXPECT_EQ(1u,
- client_connection->GetStats().num_connectivity_probing_received);
+ EXPECT_EQ(
+ 1u, GetClientConnection()->GetStats().num_connectivity_probing_received);
}
TEST_P(EndToEndPacketReorderingTest, Buffer0RttRequest) {
@@ -3844,8 +3905,7 @@ TEST_P(EndToEndPacketReorderingTest, Buffer0RttRequest) {
client_->SendMessage(headers, "");
client_->WaitForResponse();
EXPECT_EQ(kBarResponseBody, client_->response_body());
- QuicConnectionStats client_stats =
- client_->client()->client_session()->connection()->GetStats();
+ QuicConnectionStats client_stats = GetClientConnection()->GetStats();
EXPECT_EQ(0u, client_stats.packets_lost);
if (ServerSendsVersionNegotiation()) {
EXPECT_EQ(2, client_->client()->GetNumSentClientHellos());
@@ -3864,7 +3924,7 @@ TEST_P(EndToEndTest, SimpleStopSendingTest) {
if (!VersionHasIetfQuicFrames(negotiated_version_.transport_version)) {
return;
}
- QuicSession* client_session = client_->client()->client_session();
+ QuicSession* client_session = GetClientSession();
ASSERT_NE(nullptr, client_session);
QuicConnection* client_connection = client_session->connection();
ASSERT_NE(nullptr, client_connection);
@@ -3884,7 +3944,7 @@ TEST_P(EndToEndTest, SimpleStopSendingTest) {
EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
client_->WaitForDelayedAcks();
- QuicSession* session = client_->client()->client_session();
+ QuicSession* session = GetClientSession();
const QuicPacketCount packets_sent_before =
session->connection()->GetStats().packets_sent;
@@ -4069,7 +4129,7 @@ TEST_P(EndToEndTest, TooBigStreamIdClosesConnection) {
headers[":authority"] = server_hostname_;
// Force the client to write with a stream ID that exceeds the limit.
- QuicSpdySession* session = client_->client()->client_session();
+ QuicSpdySession* session = GetClientSession();
QuicStreamIdManager* stream_id_manager =
QuicSessionPeer::v99_bidirectional_stream_id_manager(session);
QuicStreamCount max_number_of_streams =
@@ -4078,7 +4138,34 @@ TEST_P(EndToEndTest, TooBigStreamIdClosesConnection) {
session, GetNthClientInitiatedBidirectionalId(max_number_of_streams + 1));
client_->SendCustomSynchronousRequest(headers, body);
EXPECT_EQ(QUIC_STREAM_CONNECTION_ERROR, client_->stream_error());
- EXPECT_EQ(QUIC_INVALID_STREAM_ID, client_->connection_error());
+ EXPECT_EQ(QUIC_INVALID_STREAM_ID, GetClientSession()->error());
+ EXPECT_EQ(IETF_QUIC_TRANSPORT_CONNECTION_CLOSE,
+ GetClientSession()->close_type());
+ EXPECT_TRUE(
+ IS_IETF_STREAM_FRAME(GetClientSession()->transport_close_frame_type()));
+}
+
+TEST_P(EndToEndTest, TestMaxPushId) {
+ // Has to be before version test, see EndToEndTest::TearDown()
+ ASSERT_TRUE(Initialize());
+ if (!VersionHasIetfQuicFrames(negotiated_version_.transport_version)) {
+ // Only runs for IETF QUIC.
+ return;
+ }
+
+ EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+ static_cast<QuicSpdySession*>(client_->client()->session())
+ ->set_max_allowed_push_id(kMaxQuicStreamId);
+
+ client_->SendSynchronousRequest("/foo");
+
+ EXPECT_EQ(kMaxQuicStreamId,
+ static_cast<QuicSpdySession*>(client_->client()->session())
+ ->max_allowed_push_id());
+
+ EXPECT_EQ(
+ kMaxQuicStreamId,
+ static_cast<QuicSpdySession*>(GetServerSession())->max_allowed_push_id());
}
} // namespace
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 2641790a847..9c2c6b58fc7 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
@@ -7,6 +7,8 @@
#include <cstdint>
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+
namespace quic {
// Unidirectional stream types.
@@ -18,14 +20,25 @@ const uint64_t kServerPushStream = 0x01;
const uint64_t kQpackEncoderStream = 0x02;
const uint64_t kQpackDecoderStream = 0x03;
-// Settings identifiers.
-
+// HTTP/3 and QPACK settings identifiers.
// https://quicwg.org/base-drafts/draft-ietf-quic-http.html#settings-parameters
-const uint64_t kSettingsMaxHeaderListSize = 0x06;
-const uint64_t kSettingsNumPlaceholders = 0x09;
// https://quicwg.org/base-drafts/draft-ietf-quic-qpack.html#configuration
-const uint64_t kSettingsQpackMaxTableCapacity = 0x01;
-const uint64_t kSettingsQpackBlockedStream = 0x07;
+enum Http3AndQpackSettingsIdentifiers : uint64_t {
+ // Same value as spdy::SETTINGS_HEADER_TABLE_SIZE.
+ SETTINGS_QPACK_MAX_TABLE_CAPACITY = 0x01,
+ // Same value as spdy::SETTINGS_MAX_HEADER_LIST_SIZE.
+ SETTINGS_MAX_HEADER_LIST_SIZE = 0x06,
+ SETTINGS_QPACK_BLOCKED_STREAMS = 0x07,
+ SETTINGS_NUM_PLACEHOLDERS = 0x09,
+};
+
+// Default maximum dynamic table capacity, communicated via
+// SETTINGS_QPACK_MAX_TABLE_CAPACITY.
+const QuicByteCount kDefaultQpackMaxDynamicTableCapacity = 64 * 1024; // 64 KB
+
+// Default limit on number of blocked streams, communicated via
+// SETTINGS_QPACK_BLOCKED_STREAMS.
+const uint64_t kDefaultMaximumBlockedStreams = 100;
} // namespace quic
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 f8de0835c74..c9519fe49a4 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
@@ -23,6 +23,8 @@ HttpDecoder::HttpDecoder(Visitor* visitor)
remaining_frame_length_(0),
current_type_field_length_(0),
remaining_type_field_length_(0),
+ current_push_id_length_(0),
+ remaining_push_id_length_(0),
error_(QUIC_NO_ERROR),
error_detail_("") {
DCHECK(visitor_);
@@ -124,33 +126,31 @@ bool HttpDecoder::ReadFrameLength(QuicDataReader* reader) {
}
if (current_frame_length_ > MaxFrameLength(current_frame_type_)) {
- // TODO(bnc): Signal HTTP_EXCESSIVE_LOAD or similar to peer.
- RaiseError(QUIC_INTERNAL_ERROR, "Frame is too large");
- visitor_->OnError(this);
+ // TODO(b/124216424): Use HTTP_EXCESSIVE_LOAD.
+ RaiseError(QUIC_INVALID_FRAME_DATA, "Frame is too large");
return false;
}
// Calling the following visitor methods does not require parsing of any
// frame payload.
bool continue_processing = true;
- auto frame_meta = Http3FrameLengths(
- current_length_field_length_ + current_type_field_length_,
- current_frame_length_);
+ const QuicByteCount header_length =
+ current_length_field_length_ + current_type_field_length_;
switch (current_frame_type_) {
case static_cast<uint64_t>(HttpFrameType::DATA):
- continue_processing = visitor_->OnDataFrameStart(frame_meta);
+ continue_processing = visitor_->OnDataFrameStart(header_length);
break;
case static_cast<uint64_t>(HttpFrameType::HEADERS):
- continue_processing = visitor_->OnHeadersFrameStart(frame_meta);
+ continue_processing = visitor_->OnHeadersFrameStart(header_length);
break;
case static_cast<uint64_t>(HttpFrameType::PRIORITY):
- continue_processing = visitor_->OnPriorityFrameStart(frame_meta);
+ continue_processing = visitor_->OnPriorityFrameStart(header_length);
break;
case static_cast<uint64_t>(HttpFrameType::CANCEL_PUSH):
break;
case static_cast<uint64_t>(HttpFrameType::SETTINGS):
- continue_processing = visitor_->OnSettingsFrameStart(frame_meta);
+ continue_processing = visitor_->OnSettingsFrameStart(header_length);
break;
case static_cast<uint64_t>(HttpFrameType::PUSH_PROMISE):
break;
@@ -162,7 +162,7 @@ bool HttpDecoder::ReadFrameLength(QuicDataReader* reader) {
break;
default:
continue_processing =
- visitor_->OnUnknownFrameStart(current_frame_type_, frame_meta);
+ visitor_->OnUnknownFrameStart(current_frame_type_, header_length);
break;
}
@@ -216,23 +216,57 @@ bool HttpDecoder::ReadFramePayload(QuicDataReader* reader) {
break;
}
case static_cast<uint64_t>(HttpFrameType::PUSH_PROMISE): {
+ PushId push_id;
if (current_frame_length_ == remaining_frame_length_) {
- QuicByteCount bytes_remaining = reader->BytesRemaining();
- PushId push_id;
- // TODO(rch): Handle partial delivery of this field.
- if (!reader->ReadVarInt62(&push_id)) {
- RaiseError(QUIC_INTERNAL_ERROR, "Unable to read push_id");
+ // A new Push Promise frame just arrived.
+ DCHECK_EQ(0u, current_push_id_length_);
+ current_push_id_length_ = reader->PeekVarInt62Length();
+ if (current_push_id_length_ > remaining_frame_length_) {
+ RaiseError(QUIC_INVALID_FRAME_DATA, "PUSH_PROMISE frame malformed.");
return false;
}
- remaining_frame_length_ -= bytes_remaining - reader->BytesRemaining();
+ if (current_push_id_length_ > reader->BytesRemaining()) {
+ // Not all bytes of push id is present yet, buffer push id.
+ DCHECK_EQ(0u, remaining_push_id_length_);
+ remaining_push_id_length_ = current_push_id_length_;
+ BufferPushId(reader);
+ break;
+ }
+ bool success = reader->ReadVarInt62(&push_id);
+ DCHECK(success);
+ remaining_frame_length_ -= current_push_id_length_;
if (!visitor_->OnPushPromiseFrameStart(
- push_id, Http3FrameLengths(current_length_field_length_ +
- current_type_field_length_,
- current_frame_length_))) {
+ push_id,
+ current_length_field_length_ + current_type_field_length_,
+ current_push_id_length_)) {
continue_processing = false;
+ current_push_id_length_ = 0;
+ break;
+ }
+ current_push_id_length_ = 0;
+ } else if (remaining_push_id_length_ > 0) {
+ // Waiting for more bytes on push id.
+ BufferPushId(reader);
+ if (remaining_push_id_length_ != 0) {
break;
}
+ QuicDataReader push_id_reader(push_id_buffer_.data(),
+ current_push_id_length_);
+
+ bool success = push_id_reader.ReadVarInt62(&push_id);
+ DCHECK(success);
+ if (!visitor_->OnPushPromiseFrameStart(
+ push_id,
+ current_length_field_length_ + current_type_field_length_,
+ current_push_id_length_)) {
+ continue_processing = false;
+ current_push_id_length_ = 0;
+ break;
+ }
+ current_push_id_length_ = 0;
}
+
+ // Read Push Promise headers.
DCHECK_LT(remaining_frame_length_, current_frame_length_);
QuicByteCount bytes_to_read = std::min<QuicByteCount>(
remaining_frame_length_, reader->BytesRemaining());
@@ -252,7 +286,6 @@ bool HttpDecoder::ReadFramePayload(QuicDataReader* reader) {
break;
}
case static_cast<uint64_t>(HttpFrameType::MAX_PUSH_ID): {
- // TODO(rch): Handle partial delivery.
BufferFramePayload(reader);
break;
}
@@ -306,11 +339,16 @@ bool HttpDecoder::FinishParsing() {
break;
}
case static_cast<uint64_t>(HttpFrameType::CANCEL_PUSH): {
- // TODO(rch): Handle partial delivery.
CancelPushFrame frame;
QuicDataReader reader(buffer_.data(), current_frame_length_);
if (!reader.ReadVarInt62(&frame.push_id)) {
- RaiseError(QUIC_INTERNAL_ERROR, "Unable to read push_id");
+ // TODO(b/124216424): Use HTTP_MALFORMED_FRAME.
+ RaiseError(QUIC_INVALID_FRAME_DATA, "Unable to read push_id");
+ return false;
+ }
+ if (!reader.IsDoneReading()) {
+ RaiseError(QUIC_INVALID_FRAME_DATA,
+ "Superfluous data in CANCEL_PUSH frame.");
return false;
}
continue_processing = visitor_->OnCancelPushFrame(frame);
@@ -330,7 +368,6 @@ bool HttpDecoder::FinishParsing() {
break;
}
case static_cast<uint64_t>(HttpFrameType::GOAWAY): {
- // TODO(bnc): Handle partial delivery.
QuicDataReader reader(buffer_.data(), current_frame_length_);
GoAwayFrame frame;
static_assert(!std::is_same<decltype(frame.stream_id), uint64_t>::value,
@@ -339,7 +376,13 @@ bool HttpDecoder::FinishParsing() {
"QuicStreamId from uint32_t to uint64_t.");
uint64_t stream_id;
if (!reader.ReadVarInt62(&stream_id)) {
- RaiseError(QUIC_INTERNAL_ERROR, "Unable to read GOAWAY stream_id");
+ // TODO(b/124216424): Use HTTP_MALFORMED_FRAME.
+ RaiseError(QUIC_INVALID_FRAME_DATA, "Unable to read GOAWAY stream_id");
+ return false;
+ }
+ if (!reader.IsDoneReading()) {
+ RaiseError(QUIC_INVALID_FRAME_DATA,
+ "Superfluous data in GOAWAY frame.");
return false;
}
frame.stream_id = static_cast<QuicStreamId>(stream_id);
@@ -347,22 +390,32 @@ bool HttpDecoder::FinishParsing() {
break;
}
case static_cast<uint64_t>(HttpFrameType::MAX_PUSH_ID): {
- // TODO(bnc): Handle partial delivery.
QuicDataReader reader(buffer_.data(), current_frame_length_);
MaxPushIdFrame frame;
if (!reader.ReadVarInt62(&frame.push_id)) {
- RaiseError(QUIC_INTERNAL_ERROR, "Unable to read push_id");
+ // TODO(b/124216424): Use HTTP_MALFORMED_FRAME.
+ RaiseError(QUIC_INVALID_FRAME_DATA, "Unable to read push_id");
+ return false;
+ }
+ if (!reader.IsDoneReading()) {
+ RaiseError(QUIC_INVALID_FRAME_DATA,
+ "Superfluous data in MAX_PUSH_ID frame.");
return false;
}
continue_processing = visitor_->OnMaxPushIdFrame(frame);
break;
}
case static_cast<uint64_t>(HttpFrameType::DUPLICATE_PUSH): {
- // TODO(bnc): Handle partial delivery.
QuicDataReader reader(buffer_.data(), current_frame_length_);
DuplicatePushFrame frame;
if (!reader.ReadVarInt62(&frame.push_id)) {
- RaiseError(QUIC_INTERNAL_ERROR, "Unable to read push_id");
+ // TODO(b/124216424): Use HTTP_MALFORMED_FRAME.
+ RaiseError(QUIC_INVALID_FRAME_DATA, "Unable to read push_id");
+ return false;
+ }
+ if (!reader.IsDoneReading()) {
+ RaiseError(QUIC_INVALID_FRAME_DATA,
+ "Superfluous data in DUPLICATE_PUSH frame.");
return false;
}
continue_processing = visitor_->OnDuplicatePushFrame(frame);
@@ -409,9 +462,6 @@ void HttpDecoder::BufferFramePayload(QuicDataReader* reader) {
}
void HttpDecoder::BufferFrameLength(QuicDataReader* reader) {
- if (current_length_field_length_ == remaining_length_field_length_) {
- length_buffer_.fill(0);
- }
QuicByteCount bytes_to_read = std::min<QuicByteCount>(
remaining_length_field_length_, reader->BytesRemaining());
bool success =
@@ -423,9 +473,6 @@ void HttpDecoder::BufferFrameLength(QuicDataReader* reader) {
}
void HttpDecoder::BufferFrameType(QuicDataReader* reader) {
- if (current_type_field_length_ == remaining_type_field_length_) {
- type_buffer_.fill(0);
- }
QuicByteCount bytes_to_read = std::min<QuicByteCount>(
remaining_type_field_length_, reader->BytesRemaining());
bool success =
@@ -436,10 +483,24 @@ void HttpDecoder::BufferFrameType(QuicDataReader* reader) {
remaining_type_field_length_ -= bytes_to_read;
}
+void HttpDecoder::BufferPushId(QuicDataReader* reader) {
+ DCHECK_LE(remaining_push_id_length_, current_frame_length_);
+ QuicByteCount bytes_to_read = std::min<QuicByteCount>(
+ reader->BytesRemaining(), remaining_push_id_length_);
+ bool success =
+ reader->ReadBytes(push_id_buffer_.data() + current_push_id_length_ -
+ remaining_push_id_length_,
+ bytes_to_read);
+ DCHECK(success);
+ remaining_push_id_length_ -= bytes_to_read;
+ remaining_frame_length_ -= bytes_to_read;
+}
+
void HttpDecoder::RaiseError(QuicErrorCode error, std::string error_detail) {
state_ = STATE_ERROR;
error_ = error;
error_detail_ = std::move(error_detail);
+ visitor_->OnError(this);
}
bool HttpDecoder::ParsePriorityFrame(QuicDataReader* reader,
@@ -459,7 +520,6 @@ bool HttpDecoder::ParsePriorityFrame(QuicDataReader* reader,
// TODO(bnc): Close connection with HTTP_MALFORMED_FRAME
// if lowest three bits are not all zero.
- // TODO(b/137359636): Handle partial delivery.
if (frame->prioritized_type != ROOT_OF_TREE &&
!reader->ReadVarInt62(&frame->prioritized_element_id)) {
// TODO(b/124216424): Use HTTP_MALFORMED_FRAME.
@@ -477,12 +537,12 @@ bool HttpDecoder::ParsePriorityFrame(QuicDataReader* reader,
if (!reader->ReadUInt8(&frame->weight)) {
// TODO(b/124216424): Use HTTP_MALFORMED_FRAME.
RaiseError(QUIC_INVALID_FRAME_DATA,
- "Unable to read priority frame weight.");
+ "Unable to read PRIORITY frame weight.");
return false;
}
if (!reader->IsDoneReading()) {
// TODO(b/124216424): Use HTTP_MALFORMED_FRAME.
- RaiseError(QUIC_INVALID_FRAME_DATA, "Superfluous data in priority frame.");
+ RaiseError(QUIC_INVALID_FRAME_DATA, "Superfluous data in PRIORITY frame.");
return false;
}
return true;
@@ -491,19 +551,26 @@ bool HttpDecoder::ParsePriorityFrame(QuicDataReader* reader,
bool HttpDecoder::ParseSettingsFrame(QuicDataReader* reader,
SettingsFrame* frame) {
while (!reader->IsDoneReading()) {
- // TODO(bnc): Handle partial delivery of both fields.
uint64_t id;
if (!reader->ReadVarInt62(&id)) {
- RaiseError(QUIC_INTERNAL_ERROR,
+ // TODO(b/124216424): Use HTTP_MALFORMED_FRAME.
+ RaiseError(QUIC_INVALID_FRAME_DATA,
"Unable to read settings frame identifier");
return false;
}
uint64_t content;
if (!reader->ReadVarInt62(&content)) {
- RaiseError(QUIC_INTERNAL_ERROR, "Unable to read settings frame content");
+ // TODO(b/124216424): Use HTTP_MALFORMED_FRAME.
+ RaiseError(QUIC_INVALID_FRAME_DATA,
+ "Unable to read settings frame content");
+ return false;
+ }
+ auto result = frame->values.insert({id, content});
+ if (!result.second) {
+ // TODO(b/124216424): Use HTTP_SETTINGS_ERROR.
+ RaiseError(QUIC_INVALID_FRAME_DATA, "Duplicate SETTINGS identifier.");
return false;
}
- frame->values[id] = content;
}
return true;
}
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 99c4d100701..30ebadc49ef 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
@@ -5,8 +5,11 @@
#ifndef QUICHE_QUIC_CORE_HTTP_HTTP_DECODER_H_
#define QUICHE_QUIC_CORE_HTTP_HTTP_DECODER_H_
+#include <cstdint>
+
#include "net/third_party/quiche/src/quic/core/http/http_frames.h"
#include "net/third_party/quiche/src/quic/core/quic_error_codes.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
@@ -20,22 +23,6 @@ class HttpDecoderPeer;
class QuicDataReader;
-// Struct that stores meta data of an HTTP/3 frame.
-// |header_length| is frame header length in bytes.
-// |payload_length| is frame payload length in bytes.
-struct QUIC_EXPORT_PRIVATE Http3FrameLengths {
- Http3FrameLengths(QuicByteCount header, QuicByteCount payload)
- : header_length(header), payload_length(payload) {}
-
- bool operator==(const Http3FrameLengths& other) const {
- return (header_length == other.header_length) &&
- (payload_length == other.payload_length);
- }
-
- QuicByteCount header_length;
- QuicByteCount payload_length;
-};
-
// A class for decoding the HTTP frames that are exchanged in an HTTP over QUIC
// session.
class QUIC_EXPORT_PRIVATE HttpDecoder {
@@ -49,10 +36,13 @@ class QUIC_EXPORT_PRIVATE HttpDecoder {
// All the following methods return true to continue decoding,
// and false to pause it.
+ // On*FrameStart() methods are called after the frame header is completely
+ // processed. At that point it is safe to consume
+ // |frame_length.header_length| bytes.
// Called when a PRIORITY frame has been received.
// |frame_length| contains PRIORITY frame length and payload length.
- virtual bool OnPriorityFrameStart(Http3FrameLengths frame_length) = 0;
+ virtual bool OnPriorityFrameStart(QuicByteCount header_length) = 0;
// Called when a PRIORITY frame has been successfully parsed.
virtual bool OnPriorityFrame(const PriorityFrame& frame) = 0;
@@ -67,7 +57,7 @@ class QUIC_EXPORT_PRIVATE HttpDecoder {
virtual bool OnGoAwayFrame(const GoAwayFrame& frame) = 0;
// Called when a SETTINGS frame has been received.
- virtual bool OnSettingsFrameStart(Http3FrameLengths frame_length) = 0;
+ virtual bool OnSettingsFrameStart(QuicByteCount header_length) = 0;
// Called when a SETTINGS frame has been successfully parsed.
virtual bool OnSettingsFrame(const SettingsFrame& frame) = 0;
@@ -77,7 +67,7 @@ class QUIC_EXPORT_PRIVATE HttpDecoder {
// Called when a DATA frame has been received.
// |frame_length| contains DATA frame length and payload length.
- virtual bool OnDataFrameStart(Http3FrameLengths frame_length) = 0;
+ virtual bool OnDataFrameStart(QuicByteCount header_length) = 0;
// Called when part of the payload of a DATA frame has been read. May be
// called multiple times for a single frame. |payload| is guaranteed to be
// non-empty.
@@ -87,7 +77,7 @@ class QUIC_EXPORT_PRIVATE HttpDecoder {
// Called when a HEADERS frame has been received.
// |frame_length| contains HEADERS frame length and payload length.
- virtual bool OnHeadersFrameStart(Http3FrameLengths frame_length) = 0;
+ virtual bool OnHeadersFrameStart(QuicByteCount header_length) = 0;
// Called when part of the payload of a HEADERS frame has been read. May be
// called multiple times for a single frame. |payload| is guaranteed to be
// non-empty.
@@ -98,7 +88,8 @@ class QUIC_EXPORT_PRIVATE HttpDecoder {
// Called when a PUSH_PROMISE frame has been received for |push_id|.
virtual bool OnPushPromiseFrameStart(PushId push_id,
- Http3FrameLengths frame_length) = 0;
+ QuicByteCount header_length,
+ QuicByteCount push_id_length) = 0;
// Called when part of the payload of a PUSH_PROMISE frame has been read.
// May be called multiple times for a single frame. |payload| is guaranteed
// to be non-empty.
@@ -110,7 +101,7 @@ class QUIC_EXPORT_PRIVATE HttpDecoder {
// Frame type might be reserved, Visitor must make sure to ignore.
// |frame_length| contains frame length and payload length.
virtual bool OnUnknownFrameStart(uint64_t frame_type,
- Http3FrameLengths frame_length) = 0;
+ QuicByteCount header_length) = 0;
// Called when part of the payload of the unknown frame has been read. May
// be called multiple times for a single frame. |payload| is guaranteed to
// be non-empty.
@@ -181,6 +172,10 @@ class QUIC_EXPORT_PRIVATE HttpDecoder {
// Buffers any remaining frame type field from |reader| into |type_buffer_|.
void BufferFrameType(QuicDataReader* reader);
+ // Buffers at most |remaining_push_id_length_| from |reader| to
+ // |push_id_buffer_|.
+ void BufferPushId(QuicDataReader* reader);
+
// Sets |error_| and |error_detail_| accordingly.
void RaiseError(QuicErrorCode error, std::string error_detail);
@@ -211,6 +206,10 @@ class QUIC_EXPORT_PRIVATE HttpDecoder {
QuicByteCount current_type_field_length_;
// Remaining length that's needed for the frame's type field.
QuicByteCount remaining_type_field_length_;
+ // Length of PUSH_PROMISE frame's push id.
+ QuicByteCount current_push_id_length_;
+ // Remaining length that's needed for PUSH_PROMISE frame's push id field.
+ QuicByteCount remaining_push_id_length_;
// Last error.
QuicErrorCode error_;
// The issue which caused |error_|
@@ -221,6 +220,8 @@ class QUIC_EXPORT_PRIVATE HttpDecoder {
std::array<char, sizeof(uint64_t)> length_buffer_;
// Remaining unparsed type field data.
std::array<char, sizeof(uint64_t)> type_buffer_;
+ // Remaining unparsed push id data.
+ std::array<char, sizeof(uint64_t)> push_id_buffer_;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/http_decoder_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/http_decoder_test.cc
index 635268bb368..6090cadee06 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
@@ -34,29 +34,31 @@ class MockVisitor : public HttpDecoder::Visitor {
// Called if an error is detected.
MOCK_METHOD1(OnError, void(HttpDecoder* decoder));
- MOCK_METHOD1(OnPriorityFrameStart, bool(Http3FrameLengths frame_lengths));
+ MOCK_METHOD1(OnPriorityFrameStart, bool(QuicByteCount header_length));
MOCK_METHOD1(OnPriorityFrame, bool(const PriorityFrame& frame));
MOCK_METHOD1(OnCancelPushFrame, bool(const CancelPushFrame& frame));
MOCK_METHOD1(OnMaxPushIdFrame, bool(const MaxPushIdFrame& frame));
MOCK_METHOD1(OnGoAwayFrame, bool(const GoAwayFrame& frame));
- MOCK_METHOD1(OnSettingsFrameStart, bool(Http3FrameLengths frame_lengths));
+ MOCK_METHOD1(OnSettingsFrameStart, bool(QuicByteCount header_length));
MOCK_METHOD1(OnSettingsFrame, bool(const SettingsFrame& frame));
MOCK_METHOD1(OnDuplicatePushFrame, bool(const DuplicatePushFrame& frame));
- MOCK_METHOD1(OnDataFrameStart, bool(Http3FrameLengths frame_lengths));
+ MOCK_METHOD1(OnDataFrameStart, bool(QuicByteCount header_length));
MOCK_METHOD1(OnDataFramePayload, bool(QuicStringPiece payload));
MOCK_METHOD0(OnDataFrameEnd, bool());
- MOCK_METHOD1(OnHeadersFrameStart, bool(Http3FrameLengths frame_lengths));
+ MOCK_METHOD1(OnHeadersFrameStart, bool(QuicByteCount header_length));
MOCK_METHOD1(OnHeadersFramePayload, bool(QuicStringPiece payload));
MOCK_METHOD0(OnHeadersFrameEnd, bool());
- MOCK_METHOD2(OnPushPromiseFrameStart,
- bool(PushId push_id, Http3FrameLengths frame_lengths));
+ MOCK_METHOD3(OnPushPromiseFrameStart,
+ bool(PushId push_id,
+ QuicByteCount header_length,
+ QuicByteCount push_id_length));
MOCK_METHOD1(OnPushPromiseFramePayload, bool(QuicStringPiece payload));
MOCK_METHOD0(OnPushPromiseFrameEnd, bool());
- MOCK_METHOD2(OnUnknownFrameStart, bool(uint64_t, Http3FrameLengths));
+ MOCK_METHOD2(OnUnknownFrameStart, bool(uint64_t, QuicByteCount));
MOCK_METHOD1(OnUnknownFramePayload, bool(QuicStringPiece));
MOCK_METHOD0(OnUnknownFrameEnd, bool());
};
@@ -78,7 +80,7 @@ class HttpDecoderTest : public QuicTest {
ON_CALL(visitor_, OnHeadersFrameStart(_)).WillByDefault(Return(true));
ON_CALL(visitor_, OnHeadersFramePayload(_)).WillByDefault(Return(true));
ON_CALL(visitor_, OnHeadersFrameEnd()).WillByDefault(Return(true));
- ON_CALL(visitor_, OnPushPromiseFrameStart(_, _))
+ ON_CALL(visitor_, OnPushPromiseFrameStart(_, _, _))
.WillByDefault(Return(true));
ON_CALL(visitor_, OnPushPromiseFramePayload(_)).WillByDefault(Return(true));
ON_CALL(visitor_, OnPushPromiseFrameEnd()).WillByDefault(Return(true));
@@ -156,9 +158,7 @@ TEST_F(HttpDecoderTest, UnknownFrame) {
writer.WriteStringPiece(data);
}
- EXPECT_CALL(visitor_, OnUnknownFrameStart(
- frame_type, Http3FrameLengths(header_length,
- payload_length)));
+ EXPECT_CALL(visitor_, OnUnknownFrameStart(frame_type, header_length));
if (payload_length > 0) {
EXPECT_CALL(visitor_, OnUnknownFramePayload(Eq(data)));
}
@@ -202,19 +202,27 @@ TEST_F(HttpDecoderTest, CancelPush) {
TEST_F(HttpDecoderTest, PushPromiseFrame) {
InSequence s;
- std::string input =
- "\x05" // type (PUSH_PROMISE)
- "\x08" // length
- "\x01" // Push Id
- "Headers"; // Header Block
+ std::string input(
+ "\x05" // type (PUSH PROMISE)
+ "\x0f" // length
+ "\xC0"
+ "\x00"
+ "\x00"
+ "\x00"
+ "\x00"
+ "\x00"
+ "\x01"
+ "\x01" // push id 257.
+ "Headers",
+ 17);
// Visitor pauses processing.
- EXPECT_CALL(visitor_, OnPushPromiseFrameStart(1, Http3FrameLengths(2, 8)))
+ EXPECT_CALL(visitor_, OnPushPromiseFrameStart(257, 2, 8))
.WillOnce(Return(false));
QuicStringPiece remaining_input(input);
QuicByteCount processed_bytes =
ProcessInputWithGarbageAppended(remaining_input);
- EXPECT_EQ(3u, processed_bytes);
+ EXPECT_EQ(10u, processed_bytes);
remaining_input = remaining_input.substr(processed_bytes);
EXPECT_CALL(visitor_, OnPushPromiseFramePayload(QuicStringPiece("Headers")))
@@ -228,7 +236,7 @@ TEST_F(HttpDecoderTest, PushPromiseFrame) {
EXPECT_EQ("", decoder_.error_detail());
// Process the full frame.
- EXPECT_CALL(visitor_, OnPushPromiseFrameStart(1, Http3FrameLengths(2, 8)));
+ EXPECT_CALL(visitor_, OnPushPromiseFrameStart(257, 2, 8));
EXPECT_CALL(visitor_, OnPushPromiseFramePayload(QuicStringPiece("Headers")));
EXPECT_CALL(visitor_, OnPushPromiseFrameEnd());
EXPECT_EQ(input.size(), ProcessInput(input));
@@ -236,7 +244,7 @@ TEST_F(HttpDecoderTest, PushPromiseFrame) {
EXPECT_EQ("", decoder_.error_detail());
// Process the frame incrementally.
- EXPECT_CALL(visitor_, OnPushPromiseFrameStart(1, Http3FrameLengths(2, 8)));
+ EXPECT_CALL(visitor_, OnPushPromiseFrameStart(257, 2, 8));
EXPECT_CALL(visitor_, OnPushPromiseFramePayload(QuicStringPiece("H")));
EXPECT_CALL(visitor_, OnPushPromiseFramePayload(QuicStringPiece("e")));
EXPECT_CALL(visitor_, OnPushPromiseFramePayload(QuicStringPiece("a")));
@@ -248,6 +256,15 @@ TEST_F(HttpDecoderTest, PushPromiseFrame) {
ProcessInputCharByChar(input);
EXPECT_EQ(QUIC_NO_ERROR, decoder_.error());
EXPECT_EQ("", decoder_.error_detail());
+
+ // Process push id incrementally and append headers with last byte of push id.
+ EXPECT_CALL(visitor_, OnPushPromiseFrameStart(257, 2, 8));
+ EXPECT_CALL(visitor_, OnPushPromiseFramePayload(QuicStringPiece("Headers")));
+ EXPECT_CALL(visitor_, OnPushPromiseFrameEnd());
+ ProcessInputCharByChar(input.substr(0, 9));
+ EXPECT_EQ(8u, ProcessInput(input.substr(9)));
+ EXPECT_EQ(QUIC_NO_ERROR, decoder_.error());
+ EXPECT_EQ("", decoder_.error_detail());
}
TEST_F(HttpDecoderTest, MaxPushId) {
@@ -323,8 +340,7 @@ TEST_F(HttpDecoderTest, PriorityFrame) {
frame.weight = 0xFF;
// Visitor pauses processing.
- EXPECT_CALL(visitor_, OnPriorityFrameStart(Http3FrameLengths(2, 4)))
- .WillOnce(Return(false));
+ EXPECT_CALL(visitor_, OnPriorityFrameStart(2)).WillOnce(Return(false));
QuicStringPiece remaining_input(input);
QuicByteCount processed_bytes =
ProcessInputWithGarbageAppended(remaining_input);
@@ -338,14 +354,14 @@ TEST_F(HttpDecoderTest, PriorityFrame) {
EXPECT_EQ("", decoder_.error_detail());
// Process the full frame.
- EXPECT_CALL(visitor_, OnPriorityFrameStart(Http3FrameLengths(2, 4)));
+ EXPECT_CALL(visitor_, OnPriorityFrameStart(2));
EXPECT_CALL(visitor_, OnPriorityFrame(frame));
EXPECT_EQ(input.size(), ProcessInput(input));
EXPECT_EQ(QUIC_NO_ERROR, decoder_.error());
EXPECT_EQ("", decoder_.error_detail());
// Process the frame incrementally.
- EXPECT_CALL(visitor_, OnPriorityFrameStart(Http3FrameLengths(2, 4)));
+ EXPECT_CALL(visitor_, OnPriorityFrameStart(2));
EXPECT_CALL(visitor_, OnPriorityFrame(frame));
ProcessInputCharByChar(input);
EXPECT_EQ(QUIC_NO_ERROR, decoder_.error());
@@ -362,7 +378,7 @@ TEST_F(HttpDecoderTest, PriorityFrame) {
frame2.exclusive = true;
frame2.weight = 0xFF;
- EXPECT_CALL(visitor_, OnPriorityFrameStart(Http3FrameLengths(2, 2)));
+ EXPECT_CALL(visitor_, OnPriorityFrameStart(2));
EXPECT_CALL(visitor_, OnPriorityFrame(frame2));
EXPECT_EQ(input2.size(), ProcessInput(input2));
EXPECT_EQ(QUIC_NO_ERROR, decoder_.error());
@@ -389,11 +405,11 @@ TEST_F(HttpDecoderTest, CorruptPriorityFrame) {
{payload1, 0, "Unable to read PRIORITY frame flags."},
{payload1, 1, "Unable to read prioritized_element_id."},
{payload1, 2, "Unable to read element_dependency_id."},
- {payload1, 3, "Unable to read priority frame weight."},
- {payload1, 5, "Superfluous data in priority frame."},
+ {payload1, 3, "Unable to read PRIORITY frame weight."},
+ {payload1, 5, "Superfluous data in PRIORITY frame."},
{payload2, 0, "Unable to read PRIORITY frame flags."},
- {payload2, 1, "Unable to read priority frame weight."},
- {payload2, 3, "Superfluous data in priority frame."},
+ {payload2, 1, "Unable to read PRIORITY frame weight."},
+ {payload2, 3, "Superfluous data in PRIORITY frame."},
};
for (const auto& test_data : kTestData) {
@@ -404,8 +420,8 @@ TEST_F(HttpDecoderTest, CorruptPriorityFrame) {
input.append(test_data.payload, test_data.payload_length);
HttpDecoder decoder(&visitor_);
- EXPECT_CALL(visitor_, OnPriorityFrameStart(Http3FrameLengths(
- header_length, test_data.payload_length)));
+ EXPECT_CALL(visitor_, OnPriorityFrameStart(header_length));
+ EXPECT_CALL(visitor_, OnError(&decoder));
QuicByteCount processed_bytes =
decoder.ProcessInput(input.data(), input.size());
@@ -435,8 +451,7 @@ TEST_F(HttpDecoderTest, SettingsFrame) {
// Visitor pauses processing.
QuicStringPiece remaining_input(input);
- EXPECT_CALL(visitor_, OnSettingsFrameStart(Http3FrameLengths(2, 7)))
- .WillOnce(Return(false));
+ EXPECT_CALL(visitor_, OnSettingsFrameStart(2)).WillOnce(Return(false));
QuicByteCount processed_bytes =
ProcessInputWithGarbageAppended(remaining_input);
EXPECT_EQ(2u, processed_bytes);
@@ -449,20 +464,73 @@ TEST_F(HttpDecoderTest, SettingsFrame) {
EXPECT_EQ("", decoder_.error_detail());
// Process the full frame.
- EXPECT_CALL(visitor_, OnSettingsFrameStart(Http3FrameLengths(2, 7)));
+ EXPECT_CALL(visitor_, OnSettingsFrameStart(2));
EXPECT_CALL(visitor_, OnSettingsFrame(frame));
EXPECT_EQ(input.size(), ProcessInput(input));
EXPECT_EQ(QUIC_NO_ERROR, decoder_.error());
EXPECT_EQ("", decoder_.error_detail());
// Process the frame incrementally.
- EXPECT_CALL(visitor_, OnSettingsFrameStart(Http3FrameLengths(2, 7)));
+ EXPECT_CALL(visitor_, OnSettingsFrameStart(2));
EXPECT_CALL(visitor_, OnSettingsFrame(frame));
ProcessInputCharByChar(input);
EXPECT_EQ(QUIC_NO_ERROR, decoder_.error());
EXPECT_EQ("", decoder_.error_detail());
}
+TEST_F(HttpDecoderTest, CorruptSettingsFrame) {
+ const char* const kPayload =
+ "\x42\x11" // two-byte id
+ "\x80\x22\x33\x44" // four-byte value
+ "\x58\x39" // two-byte id
+ "\xf0\x22\x33\x44\x55\x66\x77\x88"; // eight-byte value
+ struct {
+ size_t payload_length;
+ const char* const error_message;
+ } kTestData[] = {
+ {1, "Unable to read settings frame identifier"},
+ {5, "Unable to read settings frame content"},
+ {7, "Unable to read settings frame identifier"},
+ {12, "Unable to read settings frame content"},
+ };
+
+ for (const auto& test_data : kTestData) {
+ std::string input;
+ input.push_back(4u); // type SETTINGS
+ input.push_back(test_data.payload_length);
+ const size_t header_length = input.size();
+ input.append(kPayload, test_data.payload_length);
+
+ HttpDecoder decoder(&visitor_);
+ EXPECT_CALL(visitor_, OnSettingsFrameStart(header_length));
+ EXPECT_CALL(visitor_, OnError(&decoder));
+
+ QuicByteCount processed_bytes =
+ decoder.ProcessInput(input.data(), input.size());
+ EXPECT_EQ(input.size(), processed_bytes);
+ EXPECT_EQ(QUIC_INVALID_FRAME_DATA, decoder.error());
+ EXPECT_EQ(test_data.error_message, decoder.error_detail());
+ }
+}
+
+TEST_F(HttpDecoderTest, DuplicateSettingsIdentifier) {
+ std::string input =
+ "\x04" // type (SETTINGS)
+ "\x04" // length
+ "\x01" // identifier
+ "\x01" // content
+ "\x01" // identifier
+ "\x02"; // content
+
+ EXPECT_CALL(visitor_, OnSettingsFrameStart(2));
+ EXPECT_CALL(visitor_, OnError(&decoder_));
+
+ EXPECT_EQ(input.size(), ProcessInput(input));
+
+ EXPECT_EQ(QUIC_INVALID_FRAME_DATA, decoder_.error());
+ EXPECT_EQ("Duplicate SETTINGS identifier.", decoder_.error_detail());
+}
+
TEST_F(HttpDecoderTest, DataFrame) {
InSequence s;
std::string input(
@@ -472,8 +540,7 @@ TEST_F(HttpDecoderTest, DataFrame) {
7);
// Visitor pauses processing.
- EXPECT_CALL(visitor_, OnDataFrameStart(Http3FrameLengths(2, 5)))
- .WillOnce(Return(false));
+ EXPECT_CALL(visitor_, OnDataFrameStart(2)).WillOnce(Return(false));
QuicStringPiece remaining_input(input);
QuicByteCount processed_bytes =
ProcessInputWithGarbageAppended(remaining_input);
@@ -491,7 +558,7 @@ TEST_F(HttpDecoderTest, DataFrame) {
EXPECT_EQ("", decoder_.error_detail());
// Process the full frame.
- EXPECT_CALL(visitor_, OnDataFrameStart(Http3FrameLengths(2, 5)));
+ EXPECT_CALL(visitor_, OnDataFrameStart(2));
EXPECT_CALL(visitor_, OnDataFramePayload(QuicStringPiece("Data!")));
EXPECT_CALL(visitor_, OnDataFrameEnd());
EXPECT_EQ(input.size(), ProcessInput(input));
@@ -499,7 +566,7 @@ TEST_F(HttpDecoderTest, DataFrame) {
EXPECT_EQ("", decoder_.error_detail());
// Process the frame incrementally.
- EXPECT_CALL(visitor_, OnDataFrameStart(Http3FrameLengths(2, 5)));
+ EXPECT_CALL(visitor_, OnDataFrameStart(2));
EXPECT_CALL(visitor_, OnDataFramePayload(QuicStringPiece("D")));
EXPECT_CALL(visitor_, OnDataFramePayload(QuicStringPiece("a")));
EXPECT_CALL(visitor_, OnDataFramePayload(QuicStringPiece("t")));
@@ -526,7 +593,7 @@ TEST_F(HttpDecoderTest, FrameHeaderPartialDelivery) {
EXPECT_EQ("", decoder_.error_detail());
// Send the rest of the header.
- EXPECT_CALL(visitor_, OnDataFrameStart(Http3FrameLengths(3, 2048)));
+ EXPECT_CALL(visitor_, OnDataFrameStart(3));
EXPECT_EQ(header_length - 1,
decoder_.ProcessInput(header.data() + 1, header_length - 1));
EXPECT_EQ(QUIC_NO_ERROR, decoder_.error());
@@ -544,22 +611,20 @@ TEST_F(HttpDecoderTest, PartialDeliveryOfLargeFrameType) {
// Use a reserved type that takes four bytes as a varint.
const uint64_t frame_type = 0x1f * 0x222 + 0x21;
const QuicByteCount payload_length = 0;
- const QuicByteCount total_length =
+ const QuicByteCount header_length =
QuicDataWriter::GetVarInt62Len(frame_type) +
QuicDataWriter::GetVarInt62Len(payload_length);
- auto input = QuicMakeUnique<char[]>(total_length);
- QuicDataWriter writer(total_length, input.get());
+ auto input = QuicMakeUnique<char[]>(header_length);
+ QuicDataWriter writer(header_length, input.get());
writer.WriteVarInt62(frame_type);
writer.WriteVarInt62(payload_length);
- EXPECT_CALL(visitor_,
- OnUnknownFrameStart(
- frame_type, Http3FrameLengths(total_length, payload_length)));
+ EXPECT_CALL(visitor_, OnUnknownFrameStart(frame_type, header_length));
EXPECT_CALL(visitor_, OnUnknownFrameEnd());
auto raw_input = input.get();
- for (uint64_t i = 0; i < total_length; ++i) {
+ for (uint64_t i = 0; i < header_length; ++i) {
char c = raw_input[i];
EXPECT_EQ(1u, decoder_.ProcessInput(&c, 1));
}
@@ -604,8 +669,7 @@ TEST_F(HttpDecoderTest, HeadersFrame) {
"Headers"; // headers
// Visitor pauses processing.
- EXPECT_CALL(visitor_, OnHeadersFrameStart(Http3FrameLengths(2, 7)))
- .WillOnce(Return(false));
+ EXPECT_CALL(visitor_, OnHeadersFrameStart(2)).WillOnce(Return(false));
QuicStringPiece remaining_input(input);
QuicByteCount processed_bytes =
ProcessInputWithGarbageAppended(remaining_input);
@@ -623,7 +687,7 @@ TEST_F(HttpDecoderTest, HeadersFrame) {
EXPECT_EQ("", decoder_.error_detail());
// Process the full frame.
- EXPECT_CALL(visitor_, OnHeadersFrameStart(Http3FrameLengths(2, 7)));
+ EXPECT_CALL(visitor_, OnHeadersFrameStart(2));
EXPECT_CALL(visitor_, OnHeadersFramePayload(QuicStringPiece("Headers")));
EXPECT_CALL(visitor_, OnHeadersFrameEnd());
EXPECT_EQ(input.size(), ProcessInput(input));
@@ -631,7 +695,7 @@ TEST_F(HttpDecoderTest, HeadersFrame) {
EXPECT_EQ("", decoder_.error_detail());
// Process the frame incrementally.
- EXPECT_CALL(visitor_, OnHeadersFrameStart(Http3FrameLengths(2, 7)));
+ EXPECT_CALL(visitor_, OnHeadersFrameStart(2));
EXPECT_CALL(visitor_, OnHeadersFramePayload(QuicStringPiece("H")));
EXPECT_CALL(visitor_, OnHeadersFramePayload(QuicStringPiece("e")));
EXPECT_CALL(visitor_, OnHeadersFramePayload(QuicStringPiece("a")));
@@ -653,8 +717,7 @@ TEST_F(HttpDecoderTest, EmptyDataFrame) {
2);
// Visitor pauses processing.
- EXPECT_CALL(visitor_, OnDataFrameStart(Http3FrameLengths(2, 0)))
- .WillOnce(Return(false));
+ EXPECT_CALL(visitor_, OnDataFrameStart(2)).WillOnce(Return(false));
EXPECT_EQ(input.size(), ProcessInputWithGarbageAppended(input));
EXPECT_CALL(visitor_, OnDataFrameEnd()).WillOnce(Return(false));
@@ -663,14 +726,14 @@ TEST_F(HttpDecoderTest, EmptyDataFrame) {
EXPECT_EQ("", decoder_.error_detail());
// Process the full frame.
- EXPECT_CALL(visitor_, OnDataFrameStart(Http3FrameLengths(2, 0)));
+ EXPECT_CALL(visitor_, OnDataFrameStart(2));
EXPECT_CALL(visitor_, OnDataFrameEnd());
EXPECT_EQ(input.size(), ProcessInput(input));
EXPECT_EQ(QUIC_NO_ERROR, decoder_.error());
EXPECT_EQ("", decoder_.error_detail());
// Process the frame incrementally.
- EXPECT_CALL(visitor_, OnDataFrameStart(Http3FrameLengths(2, 0)));
+ EXPECT_CALL(visitor_, OnDataFrameStart(2));
EXPECT_CALL(visitor_, OnDataFrameEnd());
ProcessInputCharByChar(input);
EXPECT_EQ(QUIC_NO_ERROR, decoder_.error());
@@ -685,8 +748,7 @@ TEST_F(HttpDecoderTest, EmptyHeadersFrame) {
2);
// Visitor pauses processing.
- EXPECT_CALL(visitor_, OnHeadersFrameStart(Http3FrameLengths(2, 0)))
- .WillOnce(Return(false));
+ EXPECT_CALL(visitor_, OnHeadersFrameStart(2)).WillOnce(Return(false));
EXPECT_EQ(input.size(), ProcessInputWithGarbageAppended(input));
EXPECT_CALL(visitor_, OnHeadersFrameEnd()).WillOnce(Return(false));
@@ -695,14 +757,14 @@ TEST_F(HttpDecoderTest, EmptyHeadersFrame) {
EXPECT_EQ("", decoder_.error_detail());
// Process the full frame.
- EXPECT_CALL(visitor_, OnHeadersFrameStart(Http3FrameLengths(2, 0)));
+ EXPECT_CALL(visitor_, OnHeadersFrameStart(2));
EXPECT_CALL(visitor_, OnHeadersFrameEnd());
EXPECT_EQ(input.size(), ProcessInput(input));
EXPECT_EQ(QUIC_NO_ERROR, decoder_.error());
EXPECT_EQ("", decoder_.error_detail());
// Process the frame incrementally.
- EXPECT_CALL(visitor_, OnHeadersFrameStart(Http3FrameLengths(2, 0)));
+ EXPECT_CALL(visitor_, OnHeadersFrameStart(2));
EXPECT_CALL(visitor_, OnHeadersFrameEnd());
ProcessInputCharByChar(input);
EXPECT_EQ(QUIC_NO_ERROR, decoder_.error());
@@ -717,7 +779,7 @@ TEST_F(HttpDecoderTest, PushPromiseFrameNoHeaders) {
"\x01"; // Push Id
// Visitor pauses processing.
- EXPECT_CALL(visitor_, OnPushPromiseFrameStart(1, Http3FrameLengths(2, 1)))
+ EXPECT_CALL(visitor_, OnPushPromiseFrameStart(1, 2, 1))
.WillOnce(Return(false));
EXPECT_EQ(input.size(), ProcessInputWithGarbageAppended(input));
@@ -727,14 +789,14 @@ TEST_F(HttpDecoderTest, PushPromiseFrameNoHeaders) {
EXPECT_EQ("", decoder_.error_detail());
// Process the full frame.
- EXPECT_CALL(visitor_, OnPushPromiseFrameStart(1, Http3FrameLengths(2, 1)));
+ EXPECT_CALL(visitor_, OnPushPromiseFrameStart(1, 2, 1));
EXPECT_CALL(visitor_, OnPushPromiseFrameEnd());
EXPECT_EQ(input.size(), ProcessInput(input));
EXPECT_EQ(QUIC_NO_ERROR, decoder_.error());
EXPECT_EQ("", decoder_.error_detail());
// Process the frame incrementally.
- EXPECT_CALL(visitor_, OnPushPromiseFrameStart(1, Http3FrameLengths(2, 1)));
+ EXPECT_CALL(visitor_, OnPushPromiseFrameStart(1, 2, 1));
EXPECT_CALL(visitor_, OnPushPromiseFrameEnd());
ProcessInputCharByChar(input);
EXPECT_EQ(QUIC_NO_ERROR, decoder_.error());
@@ -749,7 +811,7 @@ TEST_F(HttpDecoderTest, MalformedFrameWithOverlyLargePayload) {
// Process the full frame.
EXPECT_CALL(visitor_, OnError(&decoder_));
EXPECT_EQ(2u, ProcessInput(input));
- EXPECT_EQ(QUIC_INTERNAL_ERROR, decoder_.error());
+ EXPECT_EQ(QUIC_INVALID_FRAME_DATA, decoder_.error());
EXPECT_EQ("Frame is too large", decoder_.error_detail());
}
@@ -764,7 +826,7 @@ TEST_F(HttpDecoderTest, MalformedSettingsFrame) {
writer.WriteStringPiece("Malformed payload");
EXPECT_CALL(visitor_, OnError(&decoder_));
EXPECT_EQ(5u, decoder_.ProcessInput(input, QUIC_ARRAYSIZE(input)));
- EXPECT_EQ(QUIC_INTERNAL_ERROR, decoder_.error());
+ EXPECT_EQ(QUIC_INVALID_FRAME_DATA, decoder_.error());
EXPECT_EQ("Frame is too large", decoder_.error_detail());
}
@@ -780,7 +842,7 @@ TEST_F(HttpDecoderTest, HeadersPausedThenData) {
16);
// Visitor pauses processing, maybe because header decompression is blocked.
- EXPECT_CALL(visitor_, OnHeadersFrameStart(Http3FrameLengths(2, 7)));
+ EXPECT_CALL(visitor_, OnHeadersFrameStart(2));
EXPECT_CALL(visitor_, OnHeadersFramePayload(QuicStringPiece("Headers")));
EXPECT_CALL(visitor_, OnHeadersFrameEnd()).WillOnce(Return(false));
QuicStringPiece remaining_input(input);
@@ -790,7 +852,7 @@ TEST_F(HttpDecoderTest, HeadersPausedThenData) {
remaining_input = remaining_input.substr(processed_bytes);
// Process DATA frame.
- EXPECT_CALL(visitor_, OnDataFrameStart(Http3FrameLengths(2, 5)));
+ EXPECT_CALL(visitor_, OnDataFrameStart(2));
EXPECT_CALL(visitor_, OnDataFramePayload(QuicStringPiece("Data!")));
EXPECT_CALL(visitor_, OnDataFrameEnd());
@@ -801,6 +863,77 @@ TEST_F(HttpDecoderTest, HeadersPausedThenData) {
EXPECT_EQ("", decoder_.error_detail());
}
+TEST_F(HttpDecoderTest, CorruptFrame) {
+ InSequence s;
+
+ struct {
+ const char* const input;
+ const char* const error_message;
+ } kTestData[] = {{"\x03" // type (CANCEL_PUSH)
+ "\x01" // length
+ "\x40", // first byte of two-byte varint push id
+ "Unable to read push_id"},
+ {"\x03" // type (CANCEL_PUSH)
+ "\x04" // length
+ "\x05" // valid push id
+ "foo", // superfluous data
+ "Superfluous data in CANCEL_PUSH frame."},
+ {"\x05" // type (PUSH_PROMISE)
+ "\x01" // length
+ "\x40", // first byte of two-byte varint push id
+ "PUSH_PROMISE frame malformed."},
+ {"\x0D" // type (MAX_PUSH_ID)
+ "\x01" // length
+ "\x40", // first byte of two-byte varint push id
+ "Unable to read push_id"},
+ {"\x0D" // type (MAX_PUSH_ID)
+ "\x04" // length
+ "\x05" // valid push id
+ "foo", // superfluous data
+ "Superfluous data in MAX_PUSH_ID frame."},
+ {"\x0E" // type (DUPLICATE_PUSH)
+ "\x01" // length
+ "\x40", // first byte of two-byte varint push id
+ "Unable to read push_id"},
+ {"\x0E" // type (DUPLICATE_PUSH)
+ "\x04" // length
+ "\x05" // valid push id
+ "foo", // superfluous data
+ "Superfluous data in DUPLICATE_PUSH frame."},
+ {"\x07" // type (GOAWAY)
+ "\x01" // length
+ "\x40", // first byte of two-byte varint stream id
+ "Unable to read GOAWAY stream_id"},
+ {"\x07" // type (GOAWAY)
+ "\x04" // length
+ "\x05" // valid stream id
+ "foo", // superfluous data
+ "Superfluous data in GOAWAY frame."}};
+
+ for (const auto& test_data : kTestData) {
+ {
+ HttpDecoder decoder(&visitor_);
+ EXPECT_CALL(visitor_, OnError(&decoder));
+
+ QuicStringPiece input(test_data.input);
+ decoder.ProcessInput(input.data(), input.size());
+ EXPECT_EQ(QUIC_INVALID_FRAME_DATA, decoder.error());
+ EXPECT_EQ(test_data.error_message, decoder.error_detail());
+ }
+ {
+ HttpDecoder decoder(&visitor_);
+ EXPECT_CALL(visitor_, OnError(&decoder));
+
+ QuicStringPiece input(test_data.input);
+ for (auto c : input) {
+ decoder.ProcessInput(&c, 1);
+ }
+ EXPECT_EQ(QUIC_INVALID_FRAME_DATA, decoder.error());
+ EXPECT_EQ(test_data.error_message, decoder.error_detail());
+ }
+ }
+} // namespace test
+
} // namespace test
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_headers_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_headers_stream_test.cc
index ebfa6cc7e3a..2035d47a4ff 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_headers_stream_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_headers_stream_test.cc
@@ -166,6 +166,9 @@ std::vector<TestParams> GetTestParams() {
std::vector<TestParams> params;
ParsedQuicVersionVector all_supported_versions = AllSupportedVersions();
for (size_t i = 0; i < all_supported_versions.size(); ++i) {
+ if (VersionUsesQpack(all_supported_versions[i].transport_version)) {
+ continue;
+ }
for (Perspective p : {Perspective::IS_SERVER, Perspective::IS_CLIENT}) {
params.emplace_back(all_supported_versions[i], p);
}
@@ -284,7 +287,8 @@ class QuicHeadersStreamTest : public QuicTestWithParam<TestParams> {
_, _, NO_FIN))
.WillOnce(WithArgs<2>(Invoke(this, &QuicHeadersStreamTest::SaveIov)));
QuicSpdySessionPeer::WriteHeadersOnHeadersStream(
- &session_, stream_id, headers_.Clone(), fin, priority, nullptr);
+ &session_, stream_id, headers_.Clone(), fin,
+ spdy::SpdyStreamPrecedence(priority), nullptr);
// Parse the outgoing data and check that it matches was was written.
if (is_request) {
@@ -377,10 +381,6 @@ TEST_P(QuicHeadersStreamTest, StreamId) {
}
TEST_P(QuicHeadersStreamTest, WriteHeaders) {
- if (VersionUsesQpack(transport_version())) {
- return;
- }
-
for (QuicStreamId stream_id = client_id_1_; stream_id < client_id_3_;
stream_id += next_stream_id_) {
for (bool fin : {false, true}) {
@@ -397,9 +397,8 @@ TEST_P(QuicHeadersStreamTest, WriteHeaders) {
}
TEST_P(QuicHeadersStreamTest, WritePushPromises) {
- if (GetParam().version.DoesNotHaveHeadersStream()) {
- return;
- }
+ session_.set_max_allowed_push_id(kMaxQuicStreamId);
+
for (QuicStreamId stream_id = client_id_1_; stream_id < client_id_3_;
stream_id += next_stream_id_) {
QuicStreamId promised_stream_id = NextPromisedStreamId();
@@ -435,10 +434,6 @@ TEST_P(QuicHeadersStreamTest, WritePushPromises) {
}
TEST_P(QuicHeadersStreamTest, ProcessRawData) {
- if (VersionUsesQpack(transport_version())) {
- return;
- }
-
for (QuicStreamId stream_id = client_id_1_; stream_id < client_id_3_;
stream_id += next_stream_id_) {
for (bool fin : {false, true}) {
@@ -451,7 +446,8 @@ TEST_P(QuicHeadersStreamTest, ProcessRawData) {
headers_frame.set_has_priority(true);
headers_frame.set_weight(Spdy3PriorityToHttp2Weight(0));
frame = framer_->SerializeFrame(headers_frame);
- EXPECT_CALL(session_, OnStreamHeadersPriority(stream_id, 0));
+ EXPECT_CALL(session_, OnStreamHeadersPriority(
+ stream_id, spdy::SpdyStreamPrecedence(0)));
} else {
SpdyHeadersIR headers_frame(stream_id, headers_.Clone());
headers_frame.set_fin(fin);
@@ -471,9 +467,6 @@ TEST_P(QuicHeadersStreamTest, ProcessRawData) {
}
TEST_P(QuicHeadersStreamTest, ProcessPushPromise) {
- if (GetParam().version.DoesNotHaveHeadersStream()) {
- return;
- }
if (perspective() == Perspective::IS_SERVER) {
return;
}
@@ -512,9 +505,6 @@ TEST_P(QuicHeadersStreamTest, ProcessPushPromise) {
}
TEST_P(QuicHeadersStreamTest, ProcessPriorityFrame) {
- if (GetParam().version.DoesNotHaveHeadersStream()) {
- return;
- }
QuicStreamId parent_stream_id = 0;
for (SpdyPriority priority = 0; priority < 7; ++priority) {
for (QuicStreamId stream_id = client_id_1_; stream_id < client_id_3_;
@@ -536,7 +526,10 @@ TEST_P(QuicHeadersStreamTest, ProcessPriorityFrame) {
.WillRepeatedly(InvokeWithoutArgs(
this, &QuicHeadersStreamTest::TearDownLocalConnectionState));
} else {
- EXPECT_CALL(session_, OnPriorityFrame(stream_id, priority)).Times(1);
+ EXPECT_CALL(
+ session_,
+ OnPriorityFrame(stream_id, spdy::SpdyStreamPrecedence(priority)))
+ .Times(1);
}
stream_frame_.data_buffer = frame.data();
stream_frame_.data_length = frame.size();
@@ -566,10 +559,6 @@ TEST_P(QuicHeadersStreamTest, ProcessPushPromiseDisabledSetting) {
}
TEST_P(QuicHeadersStreamTest, ProcessLargeRawData) {
- if (VersionUsesQpack(transport_version())) {
- return;
- }
-
// We want to create a frame that is more than the SPDY Framer's max control
// frame size, which is 16K, but less than the HPACK decoders max decode
// buffer size, which is 32K.
@@ -588,7 +577,8 @@ TEST_P(QuicHeadersStreamTest, ProcessLargeRawData) {
headers_frame.set_has_priority(true);
headers_frame.set_weight(Spdy3PriorityToHttp2Weight(0));
frame = framer_->SerializeFrame(headers_frame);
- EXPECT_CALL(session_, OnStreamHeadersPriority(stream_id, 0));
+ EXPECT_CALL(session_, OnStreamHeadersPriority(
+ stream_id, spdy::SpdyStreamPrecedence(0)));
} else {
SpdyHeadersIR headers_frame(stream_id, headers_.Clone());
headers_frame.set_fin(fin);
@@ -743,10 +733,6 @@ TEST_P(QuicHeadersStreamTest, NoConnectionLevelFlowControl) {
}
TEST_P(QuicHeadersStreamTest, HpackDecoderDebugVisitor) {
- if (VersionUsesQpack(transport_version())) {
- return;
- }
-
auto hpack_decoder_visitor =
QuicMakeUnique<StrictMock<MockQuicHpackDebugVisitor>>();
{
@@ -778,7 +764,8 @@ TEST_P(QuicHeadersStreamTest, HpackDecoderDebugVisitor) {
headers_frame.set_has_priority(true);
headers_frame.set_weight(Spdy3PriorityToHttp2Weight(0));
frame = framer_->SerializeFrame(headers_frame);
- EXPECT_CALL(session_, OnStreamHeadersPriority(stream_id, 0));
+ EXPECT_CALL(session_, OnStreamHeadersPriority(
+ stream_id, spdy::SpdyStreamPrecedence(0)));
} else {
SpdyHeadersIR headers_frame(stream_id, headers_.Clone());
headers_frame.set_fin(fin);
@@ -799,10 +786,6 @@ TEST_P(QuicHeadersStreamTest, HpackDecoderDebugVisitor) {
}
TEST_P(QuicHeadersStreamTest, HpackEncoderDebugVisitor) {
- if (VersionUsesQpack(transport_version())) {
- return;
- }
-
auto hpack_encoder_visitor =
QuicMakeUnique<StrictMock<MockQuicHpackDebugVisitor>>();
if (perspective() == Perspective::IS_SERVER) {
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 93fae3a0111..0ff9e38baf6 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
@@ -27,14 +27,14 @@ class QuicReceiveControlStream::HttpDecoderVisitor
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
}
- bool OnPriorityFrameStart(Http3FrameLengths frame_lengths) override {
+ bool OnPriorityFrameStart(QuicByteCount header_length) override {
if (stream_->session()->perspective() == Perspective::IS_CLIENT) {
stream_->session()->connection()->CloseConnection(
QUIC_HTTP_DECODER_ERROR, "Server must not send Priority frames.",
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
return false;
}
- return stream_->OnPriorityFrameStart(frame_lengths);
+ return stream_->OnPriorityFrameStart(header_length);
}
bool OnPriorityFrame(const PriorityFrame& frame) override {
@@ -52,7 +52,13 @@ class QuicReceiveControlStream::HttpDecoderVisitor
return false;
}
- bool OnMaxPushIdFrame(const MaxPushIdFrame& /*frame*/) override {
+ bool OnMaxPushIdFrame(const MaxPushIdFrame& frame) override {
+ if (stream_->session()->perspective() == Perspective::IS_SERVER) {
+ QuicSpdySession* spdy_session =
+ static_cast<QuicSpdySession*>(stream_->session());
+ spdy_session->set_max_allowed_push_id(frame.push_id);
+ return true;
+ }
CloseConnectionOnWrongFrame("Max Push Id");
return false;
}
@@ -62,8 +68,8 @@ class QuicReceiveControlStream::HttpDecoderVisitor
return false;
}
- bool OnSettingsFrameStart(Http3FrameLengths frame_lengths) override {
- return stream_->OnSettingsFrameStart(frame_lengths);
+ bool OnSettingsFrameStart(QuicByteCount header_length) override {
+ return stream_->OnSettingsFrameStart(header_length);
}
bool OnSettingsFrame(const SettingsFrame& frame) override {
@@ -75,7 +81,7 @@ class QuicReceiveControlStream::HttpDecoderVisitor
return false;
}
- bool OnDataFrameStart(Http3FrameLengths /*frame_lengths*/) override {
+ bool OnDataFrameStart(QuicByteCount /*header_length*/) override {
CloseConnectionOnWrongFrame("Data");
return false;
}
@@ -90,7 +96,7 @@ class QuicReceiveControlStream::HttpDecoderVisitor
return false;
}
- bool OnHeadersFrameStart(Http3FrameLengths /*frame_length*/) override {
+ bool OnHeadersFrameStart(QuicByteCount /*frame_length*/) override {
CloseConnectionOnWrongFrame("Headers");
return false;
}
@@ -106,7 +112,8 @@ class QuicReceiveControlStream::HttpDecoderVisitor
}
bool OnPushPromiseFrameStart(PushId /*push_id*/,
- Http3FrameLengths /*frame_length*/) override {
+ QuicByteCount /*frame_length*/,
+ QuicByteCount /*push_id_length*/) override {
CloseConnectionOnWrongFrame("Push Promise");
return false;
}
@@ -122,7 +129,7 @@ class QuicReceiveControlStream::HttpDecoderVisitor
}
bool OnUnknownFrameStart(uint64_t /* frame_type */,
- Http3FrameLengths /* frame_length */) override {
+ QuicByteCount /* frame_length */) override {
// Ignore unknown frame types.
return true;
}
@@ -138,11 +145,11 @@ class QuicReceiveControlStream::HttpDecoderVisitor
}
private:
- void CloseConnectionOnWrongFrame(std::string frame_type) {
+ void CloseConnectionOnWrongFrame(QuicStringPiece frame_type) {
// TODO(renjietang): Change to HTTP/3 error type.
stream_->session()->connection()->CloseConnection(
QUIC_HTTP_DECODER_ERROR,
- frame_type + " frame received on control stream",
+ QuicStrCat(frame_type, " frame received on control stream"),
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
}
@@ -189,7 +196,7 @@ void QuicReceiveControlStream::OnDataAvailable() {
}
bool QuicReceiveControlStream::OnSettingsFrameStart(
- Http3FrameLengths /* frame_lengths */) {
+ QuicByteCount /* header_length */) {
if (settings_frame_received_) {
// TODO(renjietang): Change error code to HTTP_UNEXPECTED_FRAME.
session()->connection()->CloseConnection(
@@ -207,24 +214,14 @@ bool QuicReceiveControlStream::OnSettingsFrame(const SettingsFrame& settings) {
QUIC_DVLOG(1) << "Control Stream " << id()
<< " received settings frame: " << settings;
QuicSpdySession* spdy_session = static_cast<QuicSpdySession*>(session());
- for (auto& it : settings.values) {
- uint64_t setting_id = it.first;
- switch (setting_id) {
- case kSettingsMaxHeaderListSize:
- spdy_session->set_max_outbound_header_list_size(it.second);
- break;
- case kSettingsNumPlaceholders:
- // TODO: Support placeholder setting
- break;
- default:
- break;
- }
+ for (const auto& setting : settings.values) {
+ spdy_session->OnSetting(setting.first, setting.second);
}
return true;
}
bool QuicReceiveControlStream::OnPriorityFrameStart(
- Http3FrameLengths /* frame_lengths */) {
+ QuicByteCount /* header_length */) {
DCHECK_EQ(Perspective::IS_SERVER, session()->perspective());
return true;
}
@@ -237,7 +234,7 @@ bool QuicReceiveControlStream::OnPriorityFrame(const PriorityFrame& priority) {
// that the server is not permitted to open. In that case, simply drop the
// frame.
if (stream) {
- stream->SetPriority(priority.weight);
+ stream->SetPriority(spdy::SpdyStreamPrecedence(priority.weight));
}
return true;
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream.h b/chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream.h
index f83b980b8b4..84217ce8fd2 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream.h
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream.h
@@ -7,6 +7,7 @@
#include "net/third_party/quiche/src/quic/core/http/http_decoder.h"
#include "net/third_party/quiche/src/quic/core/quic_stream.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
namespace quic {
@@ -35,9 +36,9 @@ class QUIC_EXPORT_PRIVATE QuicReceiveControlStream : public QuicStream {
class HttpDecoderVisitor;
// Called from HttpDecoderVisitor.
- bool OnSettingsFrameStart(Http3FrameLengths frame_lengths);
+ bool OnSettingsFrameStart(QuicByteCount header_length);
bool OnSettingsFrame(const SettingsFrame& settings);
- bool OnPriorityFrameStart(Http3FrameLengths frame_lengths);
+ bool OnPriorityFrameStart(QuicByteCount header_length);
// TODO(renjietang): Decode Priority in HTTP/3 style.
bool OnPriorityFrame(const PriorityFrame& priority);
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream_test.cc
index aaf60e9770e..e305102344f 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream_test.cc
@@ -68,13 +68,19 @@ class QuicReceiveControlStreamTest : public QuicTestWithParam<TestParams> {
SupportedVersions(GetParam().version))),
session_(connection_) {
session_.Initialize();
- auto pending = QuicMakeUnique<PendingStream>(
- QuicUtils::GetFirstUnidirectionalStreamId(
- GetParam().version.transport_version,
- QuicUtils::InvertPerspective(perspective())),
- &session_);
+ QuicStreamId id = perspective() == Perspective::IS_SERVER
+ ? GetNthClientInitiatedUnidirectionalStreamId(
+ session_.transport_version(), 3)
+ : GetNthServerInitiatedUnidirectionalStreamId(
+ session_.transport_version(), 3);
+ char type[] = {kControlStream};
+
+ QuicStreamFrame data1(id, false, 0, QuicStringPiece(type, 1));
+ session_.OnStreamFrame(data1);
+
receive_control_stream_ =
- QuicMakeUnique<QuicReceiveControlStream>(pending.get());
+ QuicSpdySessionPeer::GetReceiveControlStream(&session_);
+
stream_ = new TestStream(GetNthClientInitiatedBidirectionalStreamId(
GetParam().version.transport_version, 0),
&session_);
@@ -100,7 +106,7 @@ class QuicReceiveControlStreamTest : public QuicTestWithParam<TestParams> {
}
QuicStreamOffset NumBytesConsumed() {
- return QuicStreamPeer::sequencer(receive_control_stream_.get())
+ return QuicStreamPeer::sequencer(receive_control_stream_)
->NumBytesConsumed();
}
@@ -108,7 +114,7 @@ class QuicReceiveControlStreamTest : public QuicTestWithParam<TestParams> {
MockAlarmFactory alarm_factory_;
StrictMock<MockQuicConnection>* connection_;
StrictMock<MockQuicSpdySession> session_;
- std::unique_ptr<QuicReceiveControlStream> receive_control_stream_;
+ QuicReceiveControlStream* receive_control_stream_;
TestStream* stream_;
};
@@ -128,10 +134,9 @@ TEST_P(QuicReceiveControlStreamTest, ResetControlStream) {
TEST_P(QuicReceiveControlStreamTest, ReceiveSettings) {
SettingsFrame settings;
settings.values[3] = 2;
- settings.values[kSettingsMaxHeaderListSize] = 5;
+ settings.values[SETTINGS_MAX_HEADER_LIST_SIZE] = 5;
std::string data = EncodeSettings(settings);
- QuicStreamFrame frame(receive_control_stream_->id(), false, 0,
- QuicStringPiece(data));
+ QuicStreamFrame frame(receive_control_stream_->id(), false, 1, data);
EXPECT_NE(5u, session_.max_outbound_header_list_size());
receive_control_stream_->OnStreamFrame(frame);
EXPECT_EQ(5u, session_.max_outbound_header_list_size());
@@ -148,15 +153,15 @@ TEST_P(QuicReceiveControlStreamTest, ReceiveSettingsTwice) {
std::string settings_frame = EncodeSettings(settings);
- EXPECT_EQ(0u, NumBytesConsumed());
+ EXPECT_EQ(1u, NumBytesConsumed());
// Receive first SETTINGS frame.
receive_control_stream_->OnStreamFrame(
QuicStreamFrame(receive_control_stream_->id(), /* fin = */ false,
- /* offset = */ 0, settings_frame));
+ /* offset = */ 1, settings_frame));
// First SETTINGS frame is consumed.
- EXPECT_EQ(settings_frame.size(), NumBytesConsumed());
+ EXPECT_EQ(settings_frame.size() + 1, NumBytesConsumed());
// Second SETTINGS frame causes the connection to be closed.
EXPECT_CALL(*connection_,
@@ -168,28 +173,26 @@ TEST_P(QuicReceiveControlStreamTest, ReceiveSettingsTwice) {
EXPECT_CALL(session_, OnConnectionClosed(_, _));
// Receive second SETTINGS frame.
- receive_control_stream_->OnStreamFrame(
- QuicStreamFrame(receive_control_stream_->id(), /* fin = */ false,
- /* offset = */ settings_frame.size(), settings_frame));
+ receive_control_stream_->OnStreamFrame(QuicStreamFrame(
+ receive_control_stream_->id(), /* fin = */ false,
+ /* offset = */ settings_frame.size() + 1, settings_frame));
// Frame header of second SETTINGS frame is consumed, but not frame payload.
QuicByteCount settings_frame_header_length = 2;
- EXPECT_EQ(settings_frame.size() + settings_frame_header_length,
+ EXPECT_EQ(settings_frame.size() + settings_frame_header_length + 1,
NumBytesConsumed());
}
TEST_P(QuicReceiveControlStreamTest, ReceiveSettingsFragments) {
SettingsFrame settings;
settings.values[3] = 2;
- settings.values[kSettingsMaxHeaderListSize] = 5;
+ settings.values[SETTINGS_MAX_HEADER_LIST_SIZE] = 5;
std::string data = EncodeSettings(settings);
std::string data1 = data.substr(0, 1);
std::string data2 = data.substr(1, data.length() - 1);
- QuicStreamFrame frame(receive_control_stream_->id(), false, 0,
- QuicStringPiece(data.data(), 1));
- QuicStreamFrame frame2(receive_control_stream_->id(), false, 1,
- QuicStringPiece(data.data() + 1, data.length() - 1));
+ QuicStreamFrame frame(receive_control_stream_->id(), false, 1, data1);
+ QuicStreamFrame frame2(receive_control_stream_->id(), false, 2, data2);
EXPECT_NE(5u, session_.max_outbound_header_list_size());
receive_control_stream_->OnStreamFrame(frame);
receive_control_stream_->OnStreamFrame(frame2);
@@ -204,8 +207,7 @@ TEST_P(QuicReceiveControlStreamTest, ReceiveWrongFrame) {
QuicByteCount header_length = encoder.SerializeGoAwayFrame(goaway, &buffer);
std::string data = std::string(buffer.get(), header_length);
- QuicStreamFrame frame(receive_control_stream_->id(), false, 0,
- QuicStringPiece(data));
+ QuicStreamFrame frame(receive_control_stream_->id(), false, 1, data);
EXPECT_CALL(*connection_, CloseConnection(QUIC_HTTP_DECODER_ERROR, _, _));
receive_control_stream_->OnStreamFrame(frame);
}
@@ -220,12 +222,12 @@ TEST_P(QuicReceiveControlStreamTest, ReceivePriorityFrame) {
frame.prioritized_element_id = stream_->id();
frame.weight = 1;
std::string serialized_frame = PriorityFrame(frame);
- QuicStreamFrame data(receive_control_stream_->id(), false, 0,
- QuicStringPiece(serialized_frame));
+ QuicStreamFrame data(receive_control_stream_->id(), false, 1,
+ serialized_frame);
- EXPECT_EQ(3u, stream_->priority());
+ EXPECT_EQ(3u, stream_->precedence().spdy3_priority());
receive_control_stream_->OnStreamFrame(data);
- EXPECT_EQ(1u, stream_->priority());
+ EXPECT_EQ(1u, stream_->precedence().spdy3_priority());
}
TEST_P(QuicReceiveControlStreamTest, PushPromiseOnControlStreamShouldClose) {
@@ -236,7 +238,7 @@ TEST_P(QuicReceiveControlStreamTest, PushPromiseOnControlStreamShouldClose) {
HttpEncoder encoder;
uint64_t length =
encoder.SerializePushPromiseFrameWithOnlyPushId(push_promise, &buffer);
- QuicStreamFrame frame(receive_control_stream_->id(), false, 0, buffer.get(),
+ QuicStreamFrame frame(receive_control_stream_->id(), false, 1, buffer.get(),
length);
// TODO(lassey) Check for HTTP_WRONG_STREAM error code.
EXPECT_CALL(*connection_, CloseConnection(QUIC_HTTP_DECODER_ERROR, _, _))
@@ -251,13 +253,13 @@ TEST_P(QuicReceiveControlStreamTest, ConsumeUnknownFrame) {
"03" // payload length
"666f6f"); // payload "foo"
- EXPECT_EQ(0u, NumBytesConsumed());
+ EXPECT_EQ(1u, NumBytesConsumed());
receive_control_stream_->OnStreamFrame(
QuicStreamFrame(receive_control_stream_->id(), /* fin = */ false,
- /* offset = */ 0, unknown_frame));
+ /* offset = */ 1, unknown_frame));
- EXPECT_EQ(unknown_frame.size(), NumBytesConsumed());
+ EXPECT_EQ(unknown_frame.size() + 1, NumBytesConsumed());
}
} // namespace
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 348f63d808c..507380d6c19 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
@@ -13,9 +13,12 @@ namespace quic {
QuicSendControlStream::QuicSendControlStream(
QuicStreamId id,
QuicSession* session,
+ uint64_t qpack_maximum_dynamic_table_capacity,
uint64_t max_inbound_header_list_size)
: QuicStream(id, session, /*is_static = */ true, WRITE_UNIDIRECTIONAL),
settings_sent_(false),
+ qpack_maximum_dynamic_table_capacity_(
+ qpack_maximum_dynamic_table_capacity),
max_inbound_header_list_size_(max_inbound_header_list_size) {}
void QuicSendControlStream::OnStreamReset(const QuicRstStreamFrame& /*frame*/) {
@@ -26,7 +29,7 @@ void QuicSendControlStream::OnStreamReset(const QuicRstStreamFrame& /*frame*/) {
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
}
-void QuicSendControlStream::SendSettingsFrame() {
+void QuicSendControlStream::MaybeSendSettingsFrame() {
if (settings_sent_) {
return;
}
@@ -40,7 +43,11 @@ void QuicSendControlStream::SendSettingsFrame() {
nullptr);
SettingsFrame settings;
- settings.values[kSettingsMaxHeaderListSize] = max_inbound_header_list_size_;
+ settings.values[SETTINGS_MAX_HEADER_LIST_SIZE] =
+ max_inbound_header_list_size_;
+ settings.values[SETTINGS_QPACK_MAX_TABLE_CAPACITY] =
+ qpack_maximum_dynamic_table_capacity_;
+
std::unique_ptr<char[]> buffer;
QuicByteCount frame_length =
encoder_.SerializeSettingsFrame(settings, &buffer);
@@ -53,9 +60,7 @@ void QuicSendControlStream::SendSettingsFrame() {
void QuicSendControlStream::WritePriority(const PriorityFrame& priority) {
QuicConnection::ScopedPacketFlusher flusher(session()->connection());
- if (!settings_sent_) {
- SendSettingsFrame();
- }
+ MaybeSendSettingsFrame();
std::unique_ptr<char[]> buffer;
QuicByteCount frame_length =
encoder_.SerializePriorityFrame(priority, &buffer);
@@ -64,4 +69,16 @@ void QuicSendControlStream::WritePriority(const PriorityFrame& priority) {
nullptr);
}
+void QuicSendControlStream::SendMaxPushIdFrame(PushId max_push_id) {
+ QuicConnection::ScopedPacketFlusher flusher(session()->connection());
+
+ MaybeSendSettingsFrame();
+ MaxPushIdFrame frame;
+ frame.push_id = max_push_id;
+ std::unique_ptr<char[]> buffer;
+ QuicByteCount frame_length = encoder_.SerializeMaxPushIdFrame(frame, &buffer);
+ WriteOrBufferData(QuicStringPiece(buffer.get(), frame_length),
+ /*fin = */ false, nullptr);
+}
+
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.h b/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.h
index 566bcc8f6f1..2e8959b0f4d 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
@@ -19,9 +19,10 @@ class QUIC_EXPORT_PRIVATE QuicSendControlStream : public QuicStream {
public:
// |session| can't be nullptr, and the ownership is not passed. The stream can
// only be accessed through the session.
- explicit QuicSendControlStream(QuicStreamId id,
- QuicSession* session,
- uint64_t max_inbound_header_list_size);
+ QuicSendControlStream(QuicStreamId id,
+ QuicSession* session,
+ uint64_t qpack_maximum_dynamic_table_capacity,
+ uint64_t max_inbound_header_list_size);
QuicSendControlStream(const QuicSendControlStream&) = delete;
QuicSendControlStream& operator=(const QuicSendControlStream&) = delete;
~QuicSendControlStream() override = default;
@@ -30,9 +31,12 @@ class QUIC_EXPORT_PRIVATE QuicSendControlStream : public QuicStream {
// closed before connection.
void OnStreamReset(const QuicRstStreamFrame& frame) override;
- // Consult the Spdy session to construct Settings frame and sends it on this
- // stream. Settings frame must be the first frame sent on this stream.
- void SendSettingsFrame();
+ // Send SETTINGS frame if it hasn't been sent yet. Settings frame must be the
+ // first frame sent on this stream.
+ void MaybeSendSettingsFrame();
+
+ // Construct a MAX_PUSH_ID frame and send it on this stream.
+ void SendMaxPushIdFrame(PushId max_push_id);
// Send |Priority| on this stream. It must be sent after settings.
void WritePriority(const PriorityFrame& priority);
@@ -46,7 +50,9 @@ class QUIC_EXPORT_PRIVATE QuicSendControlStream : public QuicStream {
// Track if a settings frame is already sent.
bool settings_sent_;
- // Max inbound header list size that will send as setting.
+ // SETTINGS_QPACK_MAX_TABLE_CAPACITY value to send.
+ const uint64_t qpack_maximum_dynamic_table_capacity_;
+ // SETTINGS_MAX_HEADER_LIST_SIZE value to send.
const uint64_t max_inbound_header_list_size_;
};
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 7c0ee125366..49cc0ede0b3 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
@@ -4,6 +4,7 @@
#include "net/third_party/quiche/src/quic/core/http/quic_send_control_stream.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_spdy_session_peer.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
@@ -11,6 +12,7 @@ namespace quic {
namespace test {
namespace {
+
using ::testing::_;
using ::testing::Invoke;
using ::testing::StrictMock;
@@ -53,14 +55,15 @@ class QuicSendControlStreamTest : public QuicTestWithParam<TestParams> {
perspective(),
SupportedVersions(GetParam().version))),
session_(connection_) {
- session_.Initialize();
- send_control_stream_ = QuicMakeUnique<QuicSendControlStream>(
- QuicSpdySessionPeer::GetNextOutgoingUnidirectionalStreamId(&session_),
- &session_, /* max_inbound_header_list_size = */ 100);
ON_CALL(session_, WritevData(_, _, _, _, _))
.WillByDefault(Invoke(MockQuicSession::ConsumeData));
}
+ void Initialize() {
+ session_.Initialize();
+ send_control_stream_ = QuicSpdySessionPeer::GetSendControlStream(&session_);
+ }
+
Perspective perspective() const { return GetParam().perspective; }
MockQuicConnectionHelper helper_;
@@ -68,27 +71,76 @@ class QuicSendControlStreamTest : public QuicTestWithParam<TestParams> {
StrictMock<MockQuicConnection>* connection_;
StrictMock<MockQuicSpdySession> session_;
HttpEncoder encoder_;
- std::unique_ptr<QuicSendControlStream> send_control_stream_;
+ QuicSendControlStream* send_control_stream_;
};
INSTANTIATE_TEST_SUITE_P(Tests,
QuicSendControlStreamTest,
::testing::ValuesIn(GetTestParams()));
-TEST_P(QuicSendControlStreamTest, WriteSettingsOnlyForOnce) {
+TEST_P(QuicSendControlStreamTest, WriteSettings) {
if (GetParam().version.handshake_protocol == PROTOCOL_TLS1_3) {
// TODO(nharper, b/112643533): Figure out why this test fails when TLS is
// enabled and fix it.
return;
}
+
+ session_.set_qpack_maximum_dynamic_table_capacity(255);
+ session_.set_max_inbound_header_list_size(1024);
+
+ Initialize();
+ testing::InSequence s;
+
+ std::string expected_write_data = QuicTextUtils::HexDecode(
+ "00" // stream type: control stream
+ "04" // frame type: SETTINGS frame
+ "06" // frame length
+ "01" // SETTINGS_QPACK_MAX_TABLE_CAPACITY
+ "40ff" // 255
+ "06" // SETTINGS_MAX_HEADER_LIST_SIZE
+ "4400"); // 1024
+
+ auto buffer = QuicMakeUnique<char[]>(expected_write_data.size());
+ QuicDataWriter writer(expected_write_data.size(), buffer.get());
+
+ // A lambda to save and consume stream data when QuicSession::WritevData() is
+ // called.
+ auto save_write_data = [&writer](QuicStream* stream, QuicStreamId /*id*/,
+ size_t write_length, QuicStreamOffset offset,
+ StreamSendingState /*state*/) {
+ stream->WriteStreamData(offset, write_length, &writer);
+ return QuicConsumedData(/* bytes_consumed = */ write_length,
+ /* fin_consumed = */ false);
+ };
+
+ EXPECT_CALL(session_, WritevData(send_control_stream_, _, 1, _, _))
+ .WillOnce(Invoke(save_write_data));
+ EXPECT_CALL(session_, WritevData(send_control_stream_, _,
+ expected_write_data.size() - 1, _, _))
+ .WillOnce(Invoke(save_write_data));
+
+ send_control_stream_->MaybeSendSettingsFrame();
+ EXPECT_EQ(expected_write_data,
+ QuicStringPiece(writer.data(), writer.length()));
+}
+
+TEST_P(QuicSendControlStreamTest, WriteSettingsOnlyOnce) {
+ if (GetParam().version.handshake_protocol == PROTOCOL_TLS1_3) {
+ // TODO(nharper, b/112643533): Figure out why this test fails when TLS is
+ // enabled and fix it.
+ return;
+ }
+
+ Initialize();
testing::InSequence s;
- EXPECT_CALL(session_, WritevData(_, _, 1, _, _));
- EXPECT_CALL(session_, WritevData(_, _, _, _, _));
- send_control_stream_->SendSettingsFrame();
+ EXPECT_CALL(session_, WritevData(send_control_stream_, _, 1, _, _));
+ EXPECT_CALL(session_, WritevData(send_control_stream_, _, _, _, _));
+ send_control_stream_->MaybeSendSettingsFrame();
- // No data should be written the sencond time SendSettingsFrame() is called.
- send_control_stream_->SendSettingsFrame();
+ // No data should be written the sencond time MaybeSendSettingsFrame() is
+ // called.
+ send_control_stream_->MaybeSendSettingsFrame();
}
TEST_P(QuicSendControlStreamTest, WritePriorityBeforeSettings) {
@@ -98,20 +150,21 @@ TEST_P(QuicSendControlStreamTest, WritePriorityBeforeSettings) {
return;
}
+ Initialize();
testing::InSequence s;
// The first write will trigger the control stream to write stream type and a
// Settings frame before the Priority frame.
- EXPECT_CALL(session_, WritevData(_, send_control_stream_->id(), _, _, _))
- .Times(3);
+ EXPECT_CALL(session_, WritevData(send_control_stream_, _, _, _, _)).Times(3);
PriorityFrame frame;
send_control_stream_->WritePriority(frame);
- EXPECT_CALL(session_, WritevData(_, send_control_stream_->id(), _, _, _));
+ EXPECT_CALL(session_, WritevData(send_control_stream_, _, _, _, _));
send_control_stream_->WritePriority(frame);
}
TEST_P(QuicSendControlStreamTest, ResetControlStream) {
+ Initialize();
QuicRstStreamFrame rst_frame(kInvalidControlFrameId,
send_control_stream_->id(),
QUIC_STREAM_CANCELLED, 1234);
@@ -120,6 +173,7 @@ TEST_P(QuicSendControlStreamTest, ResetControlStream) {
}
TEST_P(QuicSendControlStreamTest, ReceiveDataOnSendControlStream) {
+ Initialize();
QuicStreamFrame frame(send_control_stream_->id(), false, 0, "test");
EXPECT_CALL(
*connection_,
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 0041c85baf6..2236d42dfb9 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
@@ -474,6 +474,11 @@ class MockQuicCryptoServerStream : public QuicCryptoServerStream {
};
TEST_P(QuicServerSessionBaseTest, BandwidthEstimates) {
+ if (GetParam().handshake_protocol == PROTOCOL_TLS1_3) {
+ // TODO(nharper, b/112643533): Figure out why this test fails when TLS is
+ // enabled and fix it.
+ return;
+ }
// Test that bandwidth estimate updates are sent to the client, only when
// bandwidth resumption is enabled, the bandwidth estimate has changed
// sufficiently, enough time has passed,
@@ -493,17 +498,22 @@ TEST_P(QuicServerSessionBaseTest, BandwidthEstimates) {
const std::string serving_region = "not a real region";
session_->set_serving_region(serving_region);
- session_->UnregisterStreamPriority(
- QuicUtils::GetHeadersStreamId(connection_->transport_version()),
- /*is_static=*/true);
+ if (!VersionUsesQpack(transport_version())) {
+ session_->UnregisterStreamPriority(
+ QuicUtils::GetHeadersStreamId(connection_->transport_version()),
+ /*is_static=*/true);
+ }
QuicServerSessionBasePeer::SetCryptoStream(session_.get(), nullptr);
MockQuicCryptoServerStream* crypto_stream =
new MockQuicCryptoServerStream(&crypto_config_, &compressed_certs_cache_,
session_.get(), &stream_helper_);
QuicServerSessionBasePeer::SetCryptoStream(session_.get(), crypto_stream);
- session_->RegisterStreamPriority(
- QuicUtils::GetHeadersStreamId(connection_->transport_version()),
- /*is_static=*/true, QuicStream::kDefaultPriority);
+ if (!VersionUsesQpack(transport_version())) {
+ session_->RegisterStreamPriority(
+ QuicUtils::GetHeadersStreamId(connection_->transport_version()),
+ /*is_static=*/true,
+ spdy::SpdyStreamPrecedence(QuicStream::kDefaultPriority));
+ }
// Set some initial bandwidth values.
QuicSentPacketManager* sent_packet_manager =
@@ -521,8 +531,14 @@ TEST_P(QuicServerSessionBaseTest, BandwidthEstimates) {
&bandwidth_recorder, max_bandwidth_estimate_kbytes_per_second,
max_bandwidth_estimate_timestamp);
// Queue up some pending data.
- session_->MarkConnectionLevelWriteBlocked(
- QuicUtils::GetHeadersStreamId(connection_->transport_version()));
+ if (!VersionUsesQpack(transport_version())) {
+ session_->MarkConnectionLevelWriteBlocked(
+ QuicUtils::GetHeadersStreamId(connection_->transport_version()));
+ } else {
+ session_->MarkConnectionLevelWriteBlocked(
+ QuicUtils::GetFirstUnidirectionalStreamId(
+ connection_->transport_version(), Perspective::IS_SERVER));
+ }
EXPECT_TRUE(session_->HasDataToWrite());
// There will be no update sent yet - not enough time has passed.
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.cc
index f27411aec34..a2a9aaebd87 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.cc
@@ -24,8 +24,7 @@ QuicSpdyClientSessionBase::QuicSpdyClientSessionBase(
: QuicSpdySession(connection, nullptr, config, supported_versions),
push_promise_index_(push_promise_index),
largest_promised_stream_id_(
- QuicUtils::GetInvalidStreamId(connection->transport_version())),
- max_allowed_push_id_(0) {}
+ QuicUtils::GetInvalidStreamId(connection->transport_version())) {}
QuicSpdyClientSessionBase::~QuicSpdyClientSessionBase() {
// all promised streams for this session
@@ -43,6 +42,10 @@ void QuicSpdyClientSessionBase::OnConfigNegotiated() {
void QuicSpdyClientSessionBase::OnCryptoHandshakeEvent(
CryptoHandshakeEvent event) {
QuicSpdySession::OnCryptoHandshakeEvent(event);
+ if (event == HANDSHAKE_CONFIRMED && max_allowed_push_id() > 0 &&
+ VersionHasIetfQuicFrames(connection()->transport_version())) {
+ SendMaxPushId(max_allowed_push_id());
+ }
}
void QuicSpdyClientSessionBase::OnInitialHeadersComplete(
@@ -96,6 +99,7 @@ void QuicSpdyClientSessionBase::OnPromiseHeaderList(
QUIC_INVALID_STREAM_ID,
"Received push stream id higher than MAX_PUSH_ID.",
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return;
}
largest_promised_stream_id_ = promised_stream_id;
@@ -192,8 +196,12 @@ void QuicSpdyClientSessionBase::DeletePromised(
push_promise_index_->promised_by_url()->erase(promised->url());
// Since promised_by_id_ contains the unique_ptr, this will destroy
// promised.
+ // ToDo: Consider implementing logic to send a new MAX_PUSH_ID frame to allow
+ // another stream to be promised.
promised_by_id_.erase(promised->id());
- headers_stream()->MaybeReleaseSequencerBuffer();
+ if (!VersionUsesQpack(connection()->transport_version())) {
+ headers_stream()->MaybeReleaseSequencerBuffer();
+ }
}
void QuicSpdyClientSessionBase::OnPushStreamTimedOut(
@@ -211,16 +219,13 @@ void QuicSpdyClientSessionBase::ResetPromised(
void QuicSpdyClientSessionBase::CloseStreamInner(QuicStreamId stream_id,
bool locally_reset) {
QuicSpdySession::CloseStreamInner(stream_id, locally_reset);
- headers_stream()->MaybeReleaseSequencerBuffer();
+ if (!VersionUsesQpack(connection()->transport_version())) {
+ headers_stream()->MaybeReleaseSequencerBuffer();
+ }
}
bool QuicSpdyClientSessionBase::ShouldReleaseHeadersStreamSequencerBuffer() {
return !HasActiveRequestStreams() && promised_by_id_.empty();
}
-void QuicSpdyClientSessionBase::set_max_allowed_push_id(
- QuicStreamId max_allowed_push_id) {
- max_allowed_push_id_ = max_allowed_push_id;
-}
-
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.h b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.h
index 98b85899c40..aec5e75947f 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.h
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.h
@@ -111,10 +111,6 @@ class QUIC_EXPORT_PRIVATE QuicSpdyClientSessionBase
// Returns true if there are no active requests and no promised streams.
bool ShouldReleaseHeadersStreamSequencerBuffer() override;
- void set_max_allowed_push_id(QuicStreamId max_allowed_push_id);
-
- QuicStreamId max_allowed_push_id() { return max_allowed_push_id_; }
-
size_t get_max_promises() const {
return max_open_incoming_unidirectional_streams() *
kMaxPromisedStreamsMultiplier;
@@ -138,7 +134,6 @@ class QUIC_EXPORT_PRIVATE QuicSpdyClientSessionBase
QuicClientPushPromiseIndex* push_promise_index_;
QuicPromisedByIdMap promised_by_id_;
QuicStreamId largest_promised_stream_id_;
- QuicStreamId max_allowed_push_id_;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_test.cc
index 070acdfa6e3..3601873df57 100644
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_test.cc
@@ -31,6 +31,7 @@
using spdy::SpdyHeaderBlock;
using testing::_;
using testing::AnyNumber;
+using testing::AtMost;
using testing::Invoke;
using testing::Truly;
@@ -155,7 +156,8 @@ class QuicSpdyClientSessionTest : public QuicTestWithParam<ParsedQuicVersion> {
QuicConfig config = DefaultQuicConfig();
if (VersionHasIetfQuicFrames(connection_->transport_version())) {
config.SetMaxIncomingUnidirectionalStreamsToSend(
- server_max_incoming_streams);
+ server_max_incoming_streams +
+ session_->num_expected_unidirectional_static_streams());
config.SetMaxIncomingBidirectionalStreamsToSend(
server_max_incoming_streams);
} else {
@@ -243,9 +245,6 @@ TEST_P(QuicSpdyClientSessionTest, MaxNumStreamsWithNoFinOrRst) {
EXPECT_CALL(*connection_, OnStreamReset(_, _)).Times(AnyNumber());
uint32_t kServerMaxIncomingStreams = 1;
- if (VersionLacksHeadersStream(GetParam().transport_version)) {
- kServerMaxIncomingStreams = 0;
- }
CompleteCryptoHandshake(kServerMaxIncomingStreams);
QuicSpdyClientStream* stream = session_->CreateOutgoingBidirectionalStream();
@@ -261,22 +260,9 @@ TEST_P(QuicSpdyClientSessionTest, MaxNumStreamsWithNoFinOrRst) {
EXPECT_FALSE(stream);
if (VersionHasIetfQuicFrames(GetParam().transport_version)) {
- if (VersionLacksHeadersStream(GetParam().transport_version)) {
- EXPECT_EQ(1u,
- QuicSessionPeer::v99_bidirectional_stream_id_manager(&*session_)
- ->outgoing_stream_count());
-
- } else {
- // Ensure that we have/have had 3 open streams, crypto, header, and the
- // 1 test stream. Primary purpose of this is to fail when crypto
- // no longer uses a normal stream. Some above constants will then need
- // to be changed.
- EXPECT_EQ(QuicSessionPeer::v99_bidirectional_stream_id_manager(&*session_)
- ->outgoing_static_stream_count() +
- 1,
- QuicSessionPeer::v99_bidirectional_stream_id_manager(&*session_)
- ->outgoing_stream_count());
- }
+ EXPECT_EQ(1u,
+ QuicSessionPeer::v99_bidirectional_stream_id_manager(&*session_)
+ ->outgoing_stream_count());
}
}
@@ -291,9 +277,6 @@ TEST_P(QuicSpdyClientSessionTest, MaxNumStreamsWithRst) {
EXPECT_CALL(*connection_, OnStreamReset(_, _)).Times(AnyNumber());
uint32_t kServerMaxIncomingStreams = 1;
- if (VersionLacksHeadersStream(GetParam().transport_version)) {
- kServerMaxIncomingStreams = 0;
- }
CompleteCryptoHandshake(kServerMaxIncomingStreams);
QuicSpdyClientStream* stream = session_->CreateOutgoingBidirectionalStream();
@@ -310,26 +293,15 @@ TEST_P(QuicSpdyClientSessionTest, MaxNumStreamsWithRst) {
// In V99 the stream limit increases only if we get a MAX_STREAMS
// frame; pretend we got one.
- // Note that this is to be the second stream created, hence
- // the stream count is 3 (the two streams created as a part of
- // the test plus the header stream, internally created).
- QuicMaxStreamsFrame frame(
- 0,
- QuicSessionPeer::v99_bidirectional_stream_id_manager(&*session_)
- ->outgoing_static_stream_count() +
- 2,
- /*unidirectional=*/false);
+ QuicMaxStreamsFrame frame(0, 2,
+ /*unidirectional=*/false);
session_->OnMaxStreamsFrame(frame);
}
stream = session_->CreateOutgoingBidirectionalStream();
EXPECT_NE(nullptr, stream);
if (VersionHasIetfQuicFrames(GetParam().transport_version)) {
- // Ensure that we have/have had three open streams: two test streams and the
- // header stream.
- QuicStreamCount expected_stream_count = 3;
- if (VersionLacksHeadersStream(GetParam().transport_version)) {
- expected_stream_count = 2;
- }
+ // Ensure that we have 2 total streams, 1 open and 1 closed.
+ QuicStreamCount expected_stream_count = 2;
EXPECT_EQ(expected_stream_count,
QuicSessionPeer::v99_bidirectional_stream_id_manager(&*session_)
->outgoing_stream_count());
@@ -348,9 +320,6 @@ TEST_P(QuicSpdyClientSessionTest, ResetAndTrailers) {
// the client should result in all outstanding stream state being tidied up
// (including flow control, and number of available outgoing streams).
uint32_t kServerMaxIncomingStreams = 1;
- if (VersionLacksHeadersStream(GetParam().transport_version)) {
- kServerMaxIncomingStreams = 0;
- }
CompleteCryptoHandshake(kServerMaxIncomingStreams);
QuicSpdyClientStream* stream = session_->CreateOutgoingBidirectionalStream();
@@ -396,27 +365,16 @@ TEST_P(QuicSpdyClientSessionTest, ResetAndTrailers) {
// be able to create a new outgoing stream.
EXPECT_EQ(0u, session_->GetNumOpenOutgoingStreams());
if (VersionHasIetfQuicFrames(GetParam().transport_version)) {
- // Note that this is to be the second stream created, hence
- // the stream count is 3 (the two streams created as a part of
- // the test plus the header stream, internally created).
- QuicMaxStreamsFrame frame(
- 0,
- QuicSessionPeer::v99_bidirectional_stream_id_manager(&*session_)
- ->outgoing_static_stream_count() +
- 2,
- /*unidirectional=*/false);
+ QuicMaxStreamsFrame frame(0, 2,
+ /*unidirectional=*/false);
session_->OnMaxStreamsFrame(frame);
}
stream = session_->CreateOutgoingBidirectionalStream();
EXPECT_NE(nullptr, stream);
if (VersionHasIetfQuicFrames(GetParam().transport_version)) {
- // Ensure that we have/have had three open streams: two test streams and the
- // header stream.
- QuicStreamCount expected_stream_count = 3;
- if (VersionLacksHeadersStream(GetParam().transport_version)) {
- expected_stream_count = 2;
- }
+ // Ensure that we have 2 open streams.
+ QuicStreamCount expected_stream_count = 2;
EXPECT_EQ(expected_stream_count,
QuicSessionPeer::v99_bidirectional_stream_id_manager(&*session_)
->outgoing_stream_count());
@@ -458,10 +416,24 @@ TEST_P(QuicSpdyClientSessionTest, OnStreamHeaderListWithStaticStream) {
trailers.OnHeader(kFinalOffsetHeaderKey, "0");
trailers.OnHeaderBlockEnd(0, 0);
- EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(1);
- session_->OnStreamHeaderList(
- QuicUtils::GetHeadersStreamId(connection_->transport_version()),
- /*fin=*/false, 0, trailers);
+ // Initialize H/3 control stream.
+ QuicStreamId id;
+ if (VersionUsesQpack(connection_->transport_version())) {
+ id = GetNthServerInitiatedUnidirectionalStreamId(
+ connection_->transport_version(), 3);
+ char type[] = {0x00};
+
+ QuicStreamFrame data1(id, false, 0, QuicStringPiece(type, 1));
+ session_->OnStreamFrame(data1);
+ } else {
+ id = QuicUtils::GetHeadersStreamId(connection_->transport_version());
+ }
+
+ EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA,
+ "stream is static", _))
+ .Times(1);
+ session_->OnStreamHeaderList(id,
+ /*fin=*/false, 0, trailers);
}
TEST_P(QuicSpdyClientSessionTest, OnPromiseHeaderListWithStaticStream) {
@@ -474,10 +446,22 @@ TEST_P(QuicSpdyClientSessionTest, OnPromiseHeaderListWithStaticStream) {
trailers.OnHeader(kFinalOffsetHeaderKey, "0");
trailers.OnHeaderBlockEnd(0, 0);
- EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(1);
- session_->OnPromiseHeaderList(
- QuicUtils::GetHeadersStreamId(connection_->transport_version()),
- promised_stream_id_, 0, trailers);
+ // Initialize H/3 control stream.
+ QuicStreamId id;
+ if (VersionUsesQpack(connection_->transport_version())) {
+ id = GetNthServerInitiatedUnidirectionalStreamId(
+ connection_->transport_version(), 3);
+ char type[] = {0x00};
+
+ QuicStreamFrame data1(id, false, 0, QuicStringPiece(type, 1));
+ session_->OnStreamFrame(data1);
+ } else {
+ id = QuicUtils::GetHeadersStreamId(connection_->transport_version());
+ }
+ EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA,
+ "stream is static", _))
+ .Times(1);
+ session_->OnPromiseHeaderList(id, promised_stream_id_, 0, trailers);
}
TEST_P(QuicSpdyClientSessionTest, GoAwayReceived) {
@@ -521,10 +505,7 @@ TEST_P(QuicSpdyClientSessionTest, InvalidPacketReceived) {
QuicReceivedPacket valid_packet(buf, 2, QuicTime::Zero(), false);
// Close connection shouldn't be called.
EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0);
- if (connection_->transport_version() > QUIC_VERSION_44) {
- // Illegal fixed bit value.
- EXPECT_CALL(*connection_, OnError(_)).Times(1);
- }
+ EXPECT_CALL(*connection_, OnError(_)).Times(AtMost(1));
session_->ProcessUdpPacket(client_address, server_address, valid_packet);
// Verify that a non-decryptable packet doesn't close the connection.
@@ -533,10 +514,6 @@ TEST_P(QuicSpdyClientSessionTest, InvalidPacketReceived) {
ParsedQuicVersionVector versions = SupportedVersions(GetParam());
QuicConnectionId destination_connection_id = EmptyQuicConnectionId();
QuicConnectionId source_connection_id = connection_id;
- if (!GetQuicRestartFlag(quic_do_not_override_connection_id)) {
- destination_connection_id = connection_id;
- source_connection_id = EmptyQuicConnectionId();
- }
std::unique_ptr<QuicEncryptedPacket> packet(ConstructEncryptedPacket(
destination_connection_id, source_connection_id, false, false, 100,
"data", CONNECTION_ID_ABSENT, CONNECTION_ID_ABSENT,
@@ -602,6 +579,9 @@ TEST_P(QuicSpdyClientSessionTest, PushPromiseOnPromiseHeaders) {
// Initialize crypto before the client session will create a stream.
CompleteCryptoHandshake();
+ session_->set_max_allowed_push_id(GetNthServerInitiatedUnidirectionalStreamId(
+ connection_->transport_version(), 10));
+
MockQuicSpdyClientStream* stream = static_cast<MockQuicSpdyClientStream*>(
session_->CreateOutgoingBidirectionalStream());
@@ -661,6 +641,9 @@ TEST_P(QuicSpdyClientSessionTest, PushPromiseOutOfOrder) {
// Initialize crypto before the client session will create a stream.
CompleteCryptoHandshake();
+ session_->set_max_allowed_push_id(GetNthServerInitiatedUnidirectionalStreamId(
+ connection_->transport_version(), 10));
+
MockQuicSpdyClientStream* stream = static_cast<MockQuicSpdyClientStream*>(
session_->CreateOutgoingBidirectionalStream());
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 e306062ba75..719b3dcb7a3 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
@@ -12,12 +12,14 @@
#include "net/third_party/quiche/src/quic/core/http/http_constants.h"
#include "net/third_party/quiche/src/quic/core/http/quic_headers_stream.h"
#include "net/third_party/quiche/src/quic/core/quic_utils.h"
+#include "net/third_party/quiche/src/quic/core/quic_versions.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_fallthrough.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_stack_trace.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
#include "net/third_party/quiche/src/spdy/core/http2_frame_decoder_adapter.h"
@@ -26,9 +28,6 @@ using http2::Http2DecoderAdapter;
using spdy::HpackEntry;
using spdy::HpackHeaderTable;
using spdy::Http2WeightToSpdy3Priority;
-using spdy::SETTINGS_ENABLE_PUSH;
-using spdy::SETTINGS_HEADER_TABLE_SIZE;
-using spdy::SETTINGS_MAX_HEADER_LIST_SIZE;
using spdy::Spdy3PriorityToHttp2Weight;
using spdy::SpdyErrorCode;
using spdy::SpdyFramer;
@@ -52,7 +51,7 @@ namespace quic {
namespace {
-// TODO(renjietang): remove this once HTTP/3 error codes are adopted.
+// TODO(b/124216424): remove this once HTTP/3 error codes are adopted.
const uint16_t kHttpUnknownStreamType = 0x0D;
class HeaderTableDebugVisitor : public HpackHeaderTable::DebugVisitorInterface {
@@ -97,10 +96,12 @@ class QuicSpdySession::SpdyFramerVisitor
SpdyHeadersHandlerInterface* OnHeaderFrameStart(
SpdyStreamId /* stream_id */) override {
+ DCHECK(!VersionUsesQpack(session_->transport_version()));
return &header_list_;
}
void OnHeaderFrameEnd(SpdyStreamId /* stream_id */) override {
+ DCHECK(!VersionUsesQpack(session_->transport_version()));
if (session_->IsConnected()) {
session_->OnHeaderList(header_list_);
}
@@ -110,6 +111,7 @@ class QuicSpdySession::SpdyFramerVisitor
void OnStreamFrameData(SpdyStreamId /*stream_id*/,
const char* /*data*/,
size_t /*len*/) override {
+ DCHECK(!VersionUsesQpack(session_->transport_version()));
CloseConnection("SPDY DATA frame received.",
QUIC_INVALID_HEADERS_STREAM_DATA);
}
@@ -142,6 +144,7 @@ class QuicSpdySession::SpdyFramerVisitor
void OnDataFrameHeader(SpdyStreamId /*stream_id*/,
size_t /*length*/,
bool /*fin*/) override {
+ DCHECK(!VersionUsesQpack(session_->transport_version()));
CloseConnection("SPDY DATA frame received.",
QUIC_INVALID_HEADERS_STREAM_DATA);
}
@@ -153,39 +156,13 @@ class QuicSpdySession::SpdyFramerVisitor
}
void OnSetting(SpdySettingsId id, uint32_t value) override {
- switch (id) {
- case SETTINGS_HEADER_TABLE_SIZE:
- session_->UpdateHeaderEncoderTableSize(value);
- break;
- case SETTINGS_ENABLE_PUSH:
- if (session_->perspective() == Perspective::IS_SERVER) {
- // See rfc7540, Section 6.5.2.
- if (value > 1) {
- CloseConnection(
- QuicStrCat("Invalid value for SETTINGS_ENABLE_PUSH: ", value),
- QUIC_INVALID_HEADERS_STREAM_DATA);
- return;
- }
- session_->UpdateEnableServerPush(value > 0);
- break;
- } else {
- CloseConnection(
- QuicStrCat("Unsupported field of HTTP/2 SETTINGS frame: ", id),
- QUIC_INVALID_HEADERS_STREAM_DATA);
- }
- break;
- // TODO(fayang): Need to support SETTINGS_MAX_HEADER_LIST_SIZE when
- // clients are actually sending it.
- case SETTINGS_MAX_HEADER_LIST_SIZE:
- break;
- default:
- CloseConnection(
- QuicStrCat("Unsupported field of HTTP/2 SETTINGS frame: ", id),
- QUIC_INVALID_HEADERS_STREAM_DATA);
- }
+ DCHECK(!VersionUsesQpack(session_->transport_version()));
+ session_->OnSetting(id, value);
}
- void OnSettingsEnd() override {}
+ void OnSettingsEnd() override {
+ DCHECK(!VersionUsesQpack(session_->transport_version()));
+ }
void OnPing(SpdyPingId /*unique_id*/, bool /*is_ack*/) override {
CloseConnection("SPDY PING frame received.",
@@ -201,8 +178,8 @@ class QuicSpdySession::SpdyFramerVisitor
void OnHeaders(SpdyStreamId stream_id,
bool has_priority,
int weight,
- SpdyStreamId /*parent_stream_id*/,
- bool /*exclusive*/,
+ SpdyStreamId parent_stream_id,
+ bool exclusive,
bool fin,
bool /*end*/) override {
if (!session_->IsConnected()) {
@@ -215,11 +192,23 @@ class QuicSpdySession::SpdyFramerVisitor
return;
}
- // TODO(mpw): avoid down-conversion and plumb SpdyStreamPrecedence through
- // QuicHeadersStream.
+ QUIC_BUG_IF(session_->destruction_indicator() != 123456789)
+ << "QuicSpdyStream use after free. "
+ << session_->destruction_indicator() << QuicStackTrace();
+
+ if (session_->use_http2_priority_write_scheduler()) {
+ session_->OnHeaders(
+ stream_id, has_priority,
+ spdy::SpdyStreamPrecedence(parent_stream_id, weight, exclusive), fin);
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_use_http2_priority_write_scheduler, 1,
+ 3);
+ return;
+ }
+
SpdyPriority priority =
has_priority ? Http2WeightToSpdy3Priority(weight) : 0;
- session_->OnHeaders(stream_id, has_priority, priority, fin);
+ session_->OnHeaders(stream_id, has_priority,
+ spdy::SpdyStreamPrecedence(priority), fin);
}
void OnWindowUpdate(SpdyStreamId /*stream_id*/,
@@ -231,6 +220,7 @@ class QuicSpdySession::SpdyFramerVisitor
void OnPushPromise(SpdyStreamId stream_id,
SpdyStreamId promised_stream_id,
bool /*end*/) override {
+ DCHECK(!VersionUsesQpack(session_->transport_version()));
if (!session_->supports_push_promise()) {
CloseConnection("PUSH_PROMISE not supported.",
QUIC_INVALID_HEADERS_STREAM_DATA);
@@ -245,9 +235,10 @@ class QuicSpdySession::SpdyFramerVisitor
void OnContinuation(SpdyStreamId /*stream_id*/, bool /*end*/) override {}
void OnPriority(SpdyStreamId stream_id,
- SpdyStreamId /*parent_id*/,
+ SpdyStreamId parent_id,
int weight,
- bool /*exclusive*/) override {
+ bool exclusive) override {
+ DCHECK(!VersionUsesQpack(session_->transport_version()));
if (session_->connection()->transport_version() <= QUIC_VERSION_39) {
CloseConnection("SPDY PRIORITY frame received.",
QUIC_INVALID_HEADERS_STREAM_DATA);
@@ -256,10 +247,15 @@ class QuicSpdySession::SpdyFramerVisitor
if (!session_->IsConnected()) {
return;
}
- // TODO (wangyix): implement real HTTP/2 weights and dependencies instead of
- // converting to SpdyPriority.
+ if (session_->use_http2_priority_write_scheduler()) {
+ session_->OnPriority(
+ stream_id, spdy::SpdyStreamPrecedence(parent_id, weight, exclusive));
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_use_http2_priority_write_scheduler, 2,
+ 3);
+ return;
+ }
SpdyPriority priority = Http2WeightToSpdy3Priority(weight);
- session_->OnPriority(stream_id, priority);
+ session_->OnPriority(stream_id, spdy::SpdyStreamPrecedence(priority));
}
bool OnUnknownFrame(SpdyStreamId /*stream_id*/,
@@ -315,7 +311,21 @@ QuicSpdySession::QuicSpdySession(
QuicSession::Visitor* visitor,
const QuicConfig& config,
const ParsedQuicVersionVector& supported_versions)
- : QuicSession(connection, visitor, config, supported_versions),
+ : QuicSession(connection,
+ visitor,
+ config,
+ supported_versions,
+ /*num_expected_unidirectional_static_streams = */
+ VersionUsesQpack(connection->transport_version()) ? 3 : 0),
+ send_control_stream_(nullptr),
+ receive_control_stream_(nullptr),
+ qpack_encoder_receive_stream_(nullptr),
+ qpack_decoder_receive_stream_(nullptr),
+ qpack_encoder_send_stream_(nullptr),
+ qpack_decoder_send_stream_(nullptr),
+ qpack_maximum_dynamic_table_capacity_(
+ kDefaultQpackMaxDynamicTableCapacity),
+ qpack_maximum_blocked_streams_(kDefaultMaximumBlockedStreams),
max_inbound_header_list_size_(kDefaultMaxUncompressedHeaderSize),
max_outbound_header_list_size_(kDefaultMaxUncompressedHeaderSize),
server_push_enabled_(true),
@@ -325,16 +335,20 @@ QuicSpdySession::QuicSpdySession(
QuicUtils::GetInvalidStreamId(connection->transport_version())),
fin_(false),
frame_len_(0),
- uncompressed_frame_len_(0),
supports_push_promise_(perspective() == Perspective::IS_CLIENT),
spdy_framer_(SpdyFramer::ENABLE_COMPRESSION),
- spdy_framer_visitor_(new SpdyFramerVisitor(this)) {
+ spdy_framer_visitor_(new SpdyFramerVisitor(this)),
+ max_allowed_push_id_(0),
+ destruction_indicator_(123456789) {
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());
}
QuicSpdySession::~QuicSpdySession() {
+ QUIC_BUG_IF(destruction_indicator_ != 123456789)
+ << "QuicSpdyStream use after free. " << destruction_indicator_
+ << QuicStackTrace();
// Set the streams' session pointers in closed and dynamic stream lists
// to null to avoid subsequent use of this session.
for (auto& stream : *closed_streams()) {
@@ -348,12 +362,13 @@ QuicSpdySession::~QuicSpdySession() {
static_cast<QuicSpdyStream*>(kv.second.get())->ClearSession();
}
}
+ destruction_indicator_ = 987654321;
}
void QuicSpdySession::Initialize() {
QuicSession::Initialize();
- if (!connection()->version().DoesNotHaveHeadersStream()) {
+ if (!VersionUsesQpack(connection()->transport_version())) {
if (perspective() == Perspective::IS_SERVER) {
set_largest_peer_created_stream_id(
QuicUtils::GetHeadersStreamId(connection()->transport_version()));
@@ -362,34 +377,22 @@ void QuicSpdySession::Initialize() {
DCHECK_EQ(headers_stream_id, QuicUtils::GetHeadersStreamId(
connection()->transport_version()));
}
- }
+ auto headers_stream = QuicMakeUnique<QuicHeadersStream>((this));
+ DCHECK_EQ(QuicUtils::GetHeadersStreamId(connection()->transport_version()),
+ headers_stream->id());
- if (VersionUsesQpack(connection()->transport_version())) {
- qpack_encoder_ =
- QuicMakeUnique<QpackEncoder>(this, &encoder_stream_sender_delegate_);
+ headers_stream_ = headers_stream.get();
+ RegisterStaticStream(std::move(headers_stream));
+ } else {
+ ConfigureMaxIncomingDynamicStreamsToSend(
+ config()->GetMaxIncomingUnidirectionalStreamsToSend());
+ qpack_encoder_ = QuicMakeUnique<QpackEncoder>(this);
qpack_decoder_ =
- QuicMakeUnique<QpackDecoder>(this, &decoder_stream_sender_delegate_);
- // TODO(b/112770235): Send SETTINGS_QPACK_MAX_TABLE_CAPACITY with value
- // kDefaultQpackMaxDynamicTableCapacity.
- qpack_decoder_->SetMaximumDynamicTableCapacity(
- kDefaultQpackMaxDynamicTableCapacity);
- }
-
- auto headers_stream = QuicMakeUnique<QuicHeadersStream>((this));
- DCHECK_EQ(QuicUtils::GetHeadersStreamId(connection()->transport_version()),
- headers_stream->id());
-
- headers_stream_ = headers_stream.get();
- RegisterStaticStream(std::move(headers_stream),
- /*stream_already_counted = */ false);
-
- if (VersionHasStreamType(connection()->transport_version())) {
- auto send_control = QuicMakeUnique<QuicSendControlStream>(
- GetNextOutgoingUnidirectionalStreamId(), this,
- max_inbound_header_list_size_);
- send_control_stream_ = send_control.get();
- RegisterStaticStream(std::move(send_control),
- /*stream_already_counted = */ false);
+ QuicMakeUnique<QpackDecoder>(qpack_maximum_dynamic_table_capacity_,
+ qpack_maximum_blocked_streams_, this);
+ MaybeInitializeHttp3UnidirectionalStreams();
+ // TODO(b/112770235): Send SETTINGS_QPACK_BLOCKED_STREAMS with value
+ // qpack_maximum_blocked_streams_.
}
spdy_framer_visitor_->set_max_header_list_size(max_inbound_header_list_size_);
@@ -413,14 +416,15 @@ void QuicSpdySession::OnEncoderStreamError(QuicStringPiece /*error_message*/) {
QUIC_NOTREACHED();
}
-void QuicSpdySession::OnStreamHeadersPriority(QuicStreamId stream_id,
- SpdyPriority priority) {
+void QuicSpdySession::OnStreamHeadersPriority(
+ QuicStreamId stream_id,
+ const spdy::SpdyStreamPrecedence& precedence) {
QuicSpdyStream* stream = GetSpdyDataStream(stream_id);
if (!stream) {
// It's quite possible to receive headers after a stream has been reset.
return;
}
- stream->OnStreamHeadersPriority(priority);
+ stream->OnStreamHeadersPriority(precedence);
}
void QuicSpdySession::OnStreamHeaderList(QuicStreamId stream_id,
@@ -461,18 +465,22 @@ void QuicSpdySession::OnStreamHeaderList(QuicStreamId stream_id,
stream->OnStreamHeaderList(fin, frame_len, header_list);
}
-void QuicSpdySession::OnPriorityFrame(QuicStreamId stream_id,
- SpdyPriority priority) {
+void QuicSpdySession::OnPriorityFrame(
+ QuicStreamId stream_id,
+ const spdy::SpdyStreamPrecedence& precedence) {
QuicSpdyStream* stream = GetSpdyDataStream(stream_id);
if (!stream) {
// It's quite possible to receive a PRIORITY frame after a stream has been
// reset.
return;
}
- stream->OnPriorityFrame(priority);
+ stream->OnPriorityFrame(precedence);
}
size_t QuicSpdySession::ProcessHeaderData(const struct iovec& iov) {
+ QUIC_BUG_IF(destruction_indicator_ != 123456789)
+ << "QuicSpdyStream use after free. " << destruction_indicator_
+ << QuicStackTrace();
return h2_deframer_.ProcessInput(static_cast<char*>(iov.iov_base),
iov.iov_len);
}
@@ -481,13 +489,14 @@ size_t QuicSpdySession::WriteHeadersOnHeadersStream(
QuicStreamId id,
SpdyHeaderBlock headers,
bool fin,
- SpdyPriority priority,
+ const spdy::SpdyStreamPrecedence& precedence,
QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) {
DCHECK(!VersionUsesQpack(connection()->transport_version()));
return WriteHeadersOnHeadersStreamImpl(
id, std::move(headers), fin,
- /* parent_stream_id = */ 0, Spdy3PriorityToHttp2Weight(priority),
+ /* parent_stream_id = */ 0,
+ Spdy3PriorityToHttp2Weight(precedence.spdy3_priority()),
/* exclusive = */ false, std::move(ack_listener));
}
@@ -495,6 +504,7 @@ size_t QuicSpdySession::WritePriority(QuicStreamId id,
QuicStreamId parent_stream_id,
int weight,
bool exclusive) {
+ DCHECK(!VersionUsesQpack(connection()->transport_version()));
if (connection()->transport_version() <= QUIC_VERSION_39) {
return 0;
}
@@ -510,6 +520,8 @@ void QuicSpdySession::WriteH3Priority(const PriorityFrame& priority) {
DCHECK(perspective() == Perspective::IS_CLIENT)
<< "Server must not send priority";
+ QuicConnection::ScopedPacketFlusher flusher(connection());
+ SendMaxHeaderListSize(max_inbound_header_list_size_);
send_control_stream_->WritePriority(priority);
}
@@ -521,22 +533,51 @@ void QuicSpdySession::WritePushPromise(QuicStreamId original_stream_id,
return;
}
- SpdyPushPromiseIR push_promise(original_stream_id, promised_stream_id,
- std::move(headers));
- // PUSH_PROMISE must not be the last frame sent out, at least followed by
- // response headers.
- push_promise.set_fin(false);
+ if (VersionHasIetfQuicFrames(connection()->transport_version()) &&
+ promised_stream_id > max_allowed_push_id()) {
+ QUIC_BUG
+ << "Server shouldn't send push id higher than client's MAX_PUSH_ID.";
+ return;
+ }
+
+ if (!VersionHasStreamType(connection()->transport_version())) {
+ SpdyPushPromiseIR push_promise(original_stream_id, promised_stream_id,
+ std::move(headers));
+ // PUSH_PROMISE must not be the last frame sent out, at least followed by
+ // response headers.
+ push_promise.set_fin(false);
- SpdySerializedFrame frame(spdy_framer_.SerializeFrame(push_promise));
- headers_stream()->WriteOrBufferData(
- QuicStringPiece(frame.data(), frame.size()), false, nullptr);
+ SpdySerializedFrame frame(spdy_framer_.SerializeFrame(push_promise));
+ headers_stream()->WriteOrBufferData(
+ QuicStringPiece(frame.data(), frame.size()), false, nullptr);
+ return;
+ }
+
+ // Encode header list.
+ std::string encoded_headers =
+ qpack_encoder_->EncodeHeaderList(original_stream_id, headers);
+ PushPromiseFrame frame;
+ frame.push_id = promised_stream_id;
+ frame.headers = encoded_headers;
+ QuicSpdyStream* stream = GetSpdyDataStream(original_stream_id);
+ stream->WritePushPromise(frame);
}
void QuicSpdySession::SendMaxHeaderListSize(size_t value) {
if (VersionHasStreamType(connection()->transport_version())) {
- send_control_stream_->SendSettingsFrame();
+ QuicConnection::ScopedPacketFlusher flusher(connection());
+ send_control_stream_->MaybeSendSettingsFrame();
+ // TODO(renjietang): Remove this once stream id manager can take dynamically
+ // created HTTP/3 unidirectional streams.
+ qpack_encoder_send_stream_->MaybeSendStreamType();
+ qpack_decoder_send_stream_->MaybeSendStreamType();
return;
}
+ if (GetQuicReloadableFlag(quic_do_not_send_settings)) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_do_not_send_settings);
+ return;
+ }
+
SpdySettingsIR settings_frame;
settings_frame.AddSetting(SETTINGS_MAX_HEADER_LIST_SIZE, value);
@@ -582,6 +623,10 @@ QuicSpdyStream* QuicSpdySession::GetSpdyDataStream(
void QuicSpdySession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) {
QuicSession::OnCryptoHandshakeEvent(event);
+ if (VersionUsesQpack(transport_version()) && event == HANDSHAKE_CONFIRMED) {
+ SendMaxHeaderListSize(max_inbound_header_list_size_);
+ return;
+ }
if (event == HANDSHAKE_CONFIRMED && config()->SupportMaxHeaderListSize()) {
SendMaxHeaderListSize(max_inbound_header_list_size_);
}
@@ -589,9 +634,10 @@ void QuicSpdySession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) {
// True if there are open HTTP requests.
bool QuicSpdySession::ShouldKeepConnectionAlive() const {
- // Change to check if there are open HTTP requests.
- // When IETF QUIC control and QPACK streams are used, those will need to be
- // subtracted from this count to ensure only request streams are counted.
+ if (GetQuicReloadableFlag(quic_aggressive_connection_aliveness)) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_aggressive_connection_aliveness);
+ return GetNumActiveStreams() > 0;
+ }
return GetNumOpenDynamicStreams() > 0;
}
@@ -639,13 +685,104 @@ void QuicSpdySession::OnPromiseHeaderList(
ConnectionCloseBehavior::SILENT_CLOSE);
}
+void QuicSpdySession::OnSetting(uint64_t id, uint64_t value) {
+ if (VersionHasStreamType(connection()->transport_version())) {
+ // SETTINGS frame received on the control stream.
+ switch (id) {
+ case SETTINGS_QPACK_MAX_TABLE_CAPACITY:
+ QUIC_DVLOG(1)
+ << "SETTINGS_QPACK_MAX_TABLE_CAPACITY received with value "
+ << value;
+ // Communicate |value| to encoder, because it is used for encoding
+ // Required Insert Count.
+ qpack_encoder_->SetMaximumDynamicTableCapacity(value);
+ // However, limit the dynamic table capacity to
+ // |qpack_maximum_dynamic_table_capacity_|.
+ qpack_encoder_->SetDynamicTableCapacity(
+ std::min(value, qpack_maximum_dynamic_table_capacity_));
+ break;
+ case SETTINGS_MAX_HEADER_LIST_SIZE:
+ QUIC_DVLOG(1) << "SETTINGS_MAX_HEADER_LIST_SIZE received with value "
+ << value;
+ max_outbound_header_list_size_ = value;
+ break;
+ case SETTINGS_QPACK_BLOCKED_STREAMS:
+ QUIC_DVLOG(1) << "SETTINGS_QPACK_BLOCKED_STREAMS received with value "
+ << value;
+ qpack_encoder_->SetMaximumBlockedStreams(value);
+ break;
+ case SETTINGS_NUM_PLACEHOLDERS:
+ QUIC_DVLOG(1) << "SETTINGS_NUM_PLACEHOLDERS received with value "
+ << value;
+ // TODO: Support placeholder setting.
+ break;
+ default:
+ QUIC_DVLOG(1) << "Unknown setting identifier " << id
+ << " received with value " << value;
+ // Ignore unknown settings.
+ break;
+ }
+ return;
+ }
+
+ // SETTINGS frame received on the headers stream.
+ switch (id) {
+ case spdy::SETTINGS_HEADER_TABLE_SIZE:
+ QUIC_DVLOG(1) << "SETTINGS_HEADER_TABLE_SIZE received with value "
+ << value;
+ spdy_framer_.UpdateHeaderEncoderTableSize(value);
+ break;
+ case spdy::SETTINGS_ENABLE_PUSH:
+ if (perspective() == Perspective::IS_SERVER) {
+ // See rfc7540, Section 6.5.2.
+ if (value > 1) {
+ QUIC_DLOG(ERROR) << "Invalid value " << value
+ << " received for SETTINGS_ENABLE_PUSH.";
+ if (IsConnected()) {
+ CloseConnectionWithDetails(
+ QUIC_INVALID_HEADERS_STREAM_DATA,
+ QuicStrCat("Invalid value for SETTINGS_ENABLE_PUSH: ", value));
+ }
+ return;
+ }
+ QUIC_DVLOG(1) << "SETTINGS_ENABLE_PUSH received with value " << value;
+ server_push_enabled_ = value;
+ break;
+ } else {
+ QUIC_DLOG(ERROR)
+ << "Invalid SETTINGS_ENABLE_PUSH received by client with value "
+ << value;
+ if (IsConnected()) {
+ CloseConnectionWithDetails(
+ QUIC_INVALID_HEADERS_STREAM_DATA,
+ QuicStrCat("Unsupported field of HTTP/2 SETTINGS frame: ", id));
+ }
+ }
+ break;
+ // TODO(fayang): Need to support SETTINGS_MAX_HEADER_LIST_SIZE when
+ // clients are actually sending it.
+ case spdy::SETTINGS_MAX_HEADER_LIST_SIZE:
+ QUIC_DVLOG(1) << "SETTINGS_MAX_HEADER_LIST_SIZE received with value "
+ << value;
+ break;
+ default:
+ QUIC_DLOG(ERROR) << "Unknown setting identifier " << id
+ << " received with value " << value;
+ if (IsConnected()) {
+ CloseConnectionWithDetails(
+ QUIC_INVALID_HEADERS_STREAM_DATA,
+ QuicStrCat("Unsupported field of HTTP/2 SETTINGS frame: ", id));
+ }
+ }
+}
+
bool QuicSpdySession::ShouldReleaseHeadersStreamSequencerBuffer() {
return false;
}
void QuicSpdySession::OnHeaders(SpdyStreamId stream_id,
bool has_priority,
- SpdyPriority priority,
+ const spdy::SpdyStreamPrecedence& precedence,
bool fin) {
if (has_priority) {
if (perspective() == Perspective::IS_CLIENT) {
@@ -653,7 +790,7 @@ void QuicSpdySession::OnHeaders(SpdyStreamId stream_id,
"Server must not send priorities.");
return;
}
- OnStreamHeadersPriority(stream_id, priority);
+ OnStreamHeadersPriority(stream_id, precedence);
} else {
if (perspective() == Perspective::IS_SERVER) {
CloseConnectionWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA,
@@ -682,18 +819,23 @@ void QuicSpdySession::OnPushPromise(SpdyStreamId stream_id,
// TODO (wangyix): Why is SpdyStreamId used instead of QuicStreamId?
// This occurs in many places in this file.
void QuicSpdySession::OnPriority(SpdyStreamId stream_id,
- SpdyPriority priority) {
+ const spdy::SpdyStreamPrecedence& precedence) {
if (perspective() == Perspective::IS_CLIENT) {
CloseConnectionWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA,
"Server must not send PRIORITY frames.");
return;
}
- OnPriorityFrame(stream_id, priority);
+ OnPriorityFrame(stream_id, precedence);
}
void QuicSpdySession::OnHeaderList(const QuicHeaderList& header_list) {
QUIC_DVLOG(1) << "Received header list for stream " << stream_id_ << ": "
<< header_list.DebugString();
+ // This code path is only executed for push promise in IETF QUIC.
+ if (VersionUsesQpack(connection()->transport_version())) {
+ DCHECK(promised_stream_id_ !=
+ QuicUtils::GetInvalidStreamId(connection()->transport_version()));
+ }
if (promised_stream_id_ ==
QuicUtils::GetInvalidStreamId(connection()->transport_version())) {
OnStreamHeaderList(stream_id_, fin_, frame_len_, header_list);
@@ -707,7 +849,6 @@ void QuicSpdySession::OnHeaderList(const QuicHeaderList& header_list) {
stream_id_ = QuicUtils::GetInvalidStreamId(connection()->transport_version());
fin_ = false;
frame_len_ = 0;
- uncompressed_frame_len_ = 0;
}
void QuicSpdySession::OnCompressedFrameSize(size_t frame_len) {
@@ -728,14 +869,6 @@ void QuicSpdySession::SetHpackDecoderDebugVisitor(
connection()->helper()->GetClock(), std::move(visitor)));
}
-void QuicSpdySession::UpdateHeaderEncoderTableSize(uint32_t value) {
- spdy_framer_.UpdateHeaderEncoderTableSize(value);
-}
-
-void QuicSpdySession::UpdateEnableServerPush(bool value) {
- set_server_push_enabled(value);
-}
-
void QuicSpdySession::CloseConnectionWithDetails(QuicErrorCode error,
const std::string& details) {
connection()->CloseConnection(
@@ -743,9 +876,14 @@ void QuicSpdySession::CloseConnectionWithDetails(QuicErrorCode error,
}
bool QuicSpdySession::HasActiveRequestStreams() const {
- // In the case where session is destructed by calling
- // stream_map().clear(), we will have incorrect accounting here.
- // TODO(renjietang): Modify destructors and make this a DCHECK.
+ if (GetQuicReloadableFlag(quic_active_streams_never_negative)) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_active_streams_never_negative);
+ DCHECK(static_cast<size_t>(stream_map().size()) >=
+ num_incoming_static_streams() + num_outgoing_static_streams());
+ return stream_map().size() - num_incoming_static_streams() -
+ num_outgoing_static_streams() >
+ 0;
+ }
if (static_cast<size_t>(stream_map().size()) >
num_incoming_static_streams() + num_outgoing_static_streams()) {
return stream_map().size() - num_incoming_static_streams() -
@@ -768,17 +906,27 @@ bool QuicSpdySession::ProcessPendingStream(PendingStream* pending) {
uint8_t stream_type_length = reader.PeekVarInt62Length();
uint64_t stream_type = 0;
if (!reader.ReadVarInt62(&stream_type)) {
+ if (pending->sequencer()->NumBytesBuffered() ==
+ pending->sequencer()->close_offset()) {
+ // Stream received FIN but there are not enough bytes for stream type.
+ // Mark all bytes consumed in order to close stream.
+ pending->MarkConsumed(pending->sequencer()->close_offset());
+ }
return false;
}
pending->MarkConsumed(stream_type_length);
switch (stream_type) {
case kControlStream: { // HTTP/3 control stream.
+ if (receive_control_stream_) {
+ CloseConnectionOnDuplicateHttp3UnidirectionalStreams("Control");
+ return false;
+ }
auto receive_stream = QuicMakeUnique<QuicReceiveControlStream>(pending);
receive_control_stream_ = receive_stream.get();
- RegisterStaticStream(std::move(receive_stream),
- /*stream_already_counted = */ true);
+ RegisterStaticStream(std::move(receive_stream));
receive_control_stream_->SetUnblocked();
+ QUIC_DVLOG(1) << "Receive Control stream is created";
return true;
}
case kServerPushStream: { // Push Stream.
@@ -786,16 +934,105 @@ bool QuicSpdySession::ProcessPendingStream(PendingStream* pending) {
stream->SetUnblocked();
return true;
}
- case kQpackEncoderStream: // QPACK encoder stream.
- // TODO(bnc): Create QPACK encoder stream.
- break;
- case kQpackDecoderStream: // QPACK decoder stream.
- // TODO(bnc): Create QPACK decoder stream.
- break;
+ case kQpackEncoderStream: { // QPACK encoder stream.
+ if (qpack_encoder_receive_stream_) {
+ CloseConnectionOnDuplicateHttp3UnidirectionalStreams("QPACK encoder");
+ return false;
+ }
+ auto encoder_receive = QuicMakeUnique<QpackReceiveStream>(
+ pending, qpack_decoder_->encoder_stream_receiver());
+ qpack_encoder_receive_stream_ = encoder_receive.get();
+ RegisterStaticStream(std::move(encoder_receive));
+ qpack_encoder_receive_stream_->SetUnblocked();
+ QUIC_DVLOG(1) << "Receive QPACK Encoder stream is created";
+ return true;
+ }
+ case kQpackDecoderStream: { // QPACK decoder stream.
+ if (qpack_decoder_receive_stream_) {
+ CloseConnectionOnDuplicateHttp3UnidirectionalStreams("QPACK decoder");
+ return false;
+ }
+ auto decoder_receive = QuicMakeUnique<QpackReceiveStream>(
+ pending, qpack_encoder_->decoder_stream_receiver());
+ qpack_decoder_receive_stream_ = decoder_receive.get();
+ RegisterStaticStream(std::move(decoder_receive));
+ qpack_decoder_receive_stream_->SetUnblocked();
+ QUIC_DVLOG(1) << "Receive Qpack Decoder stream is created";
+ return true;
+ }
default:
SendStopSending(kHttpUnknownStreamType, pending->id());
+ pending->StopReading();
}
return false;
}
+void QuicSpdySession::MaybeInitializeHttp3UnidirectionalStreams() {
+ DCHECK(VersionHasStreamType(connection()->transport_version()));
+ if (!send_control_stream_ && CanOpenNextOutgoingUnidirectionalStream()) {
+ auto send_control = QuicMakeUnique<QuicSendControlStream>(
+ GetNextOutgoingUnidirectionalStreamId(), this,
+ qpack_maximum_dynamic_table_capacity_, max_inbound_header_list_size_);
+ send_control_stream_ = send_control.get();
+ RegisterStaticStream(std::move(send_control));
+ }
+
+ if (!qpack_decoder_send_stream_ &&
+ CanOpenNextOutgoingUnidirectionalStream()) {
+ auto decoder_send = QuicMakeUnique<QpackSendStream>(
+ GetNextOutgoingUnidirectionalStreamId(), this, kQpackDecoderStream);
+ qpack_decoder_send_stream_ = decoder_send.get();
+ RegisterStaticStream(std::move(decoder_send));
+ qpack_decoder_->set_qpack_stream_sender_delegate(
+ qpack_decoder_send_stream_);
+ }
+
+ if (!qpack_encoder_send_stream_ &&
+ CanOpenNextOutgoingUnidirectionalStream()) {
+ auto encoder_send = QuicMakeUnique<QpackSendStream>(
+ GetNextOutgoingUnidirectionalStreamId(), this, kQpackEncoderStream);
+ qpack_encoder_send_stream_ = encoder_send.get();
+ RegisterStaticStream(std::move(encoder_send));
+ qpack_encoder_->set_qpack_stream_sender_delegate(
+ qpack_encoder_send_stream_);
+ }
+}
+
+void QuicSpdySession::OnCanCreateNewOutgoingStream(bool unidirectional) {
+ if (unidirectional &&
+ VersionHasStreamType(connection()->transport_version())) {
+ MaybeInitializeHttp3UnidirectionalStreams();
+ }
+}
+
+void QuicSpdySession::set_max_allowed_push_id(
+ QuicStreamId max_allowed_push_id) {
+ if (VersionHasIetfQuicFrames(connection()->transport_version()) &&
+ perspective() == Perspective::IS_SERVER &&
+ max_allowed_push_id > max_allowed_push_id_) {
+ OnCanCreateNewOutgoingStream(true);
+ }
+
+ max_allowed_push_id_ = max_allowed_push_id;
+
+ if (VersionHasIetfQuicFrames(connection()->transport_version()) &&
+ perspective() == Perspective::IS_CLIENT && IsHandshakeConfirmed()) {
+ SendMaxPushId(max_allowed_push_id);
+ }
+}
+
+void QuicSpdySession::SendMaxPushId(QuicStreamId max_allowed_push_id) {
+ DCHECK(VersionHasStreamType(connection()->transport_version()));
+ send_control_stream_->SendMaxPushIdFrame(max_allowed_push_id);
+}
+
+void QuicSpdySession::CloseConnectionOnDuplicateHttp3UnidirectionalStreams(
+ QuicStringPiece type) {
+ QUIC_PEER_BUG << QuicStrCat("Received a duplicate ", type,
+ " stream: Closing connection.");
+ // TODO(b/124216424): Change to HTTP_STREAM_CREATION_ERROR.
+ CloseConnectionWithDetails(QUIC_INVALID_STREAM_ID,
+ QuicStrCat(type, " stream is received twice."));
+}
+
} // namespace quic
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 aa2c27d067f..0ee36327f26 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
@@ -18,6 +18,8 @@
#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender.h"
#include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h"
#include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.h"
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_receive_stream.h"
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_send_stream.h"
#include "net/third_party/quiche/src/quic/core/qpack/qpack_utils.h"
#include "net/third_party/quiche/src/quic/core/quic_session.h"
#include "net/third_party/quiche/src/quic/core/quic_versions.h"
@@ -50,7 +52,7 @@ class QUIC_EXPORT_PRIVATE QuicHpackDebugVisitor {
virtual void OnUseEntry(QuicTime::Delta elapsed) = 0;
};
-// A QUIC session with a headers stream.
+// A QUIC session for HTTP.
class QUIC_EXPORT_PRIVATE QuicSpdySession
: public QuicSession,
public QpackEncoder::DecoderStreamErrorDelegate,
@@ -76,8 +78,9 @@ 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,
- spdy::SpdyPriority priority);
+ virtual void OnStreamHeadersPriority(
+ 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
@@ -98,7 +101,7 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession
// Called by |headers_stream_| when a PRIORITY frame has been received for a
// stream. This method will only be called for server streams.
virtual void OnPriorityFrame(QuicStreamId stream_id,
- spdy::SpdyPriority priority);
+ const spdy::SpdyStreamPrecedence& precedence);
// Sends contents of |iov| to h2_deframer_, returns number of bytes processed.
size_t ProcessHeaderData(const struct iovec& iov);
@@ -111,7 +114,7 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession
QuicStreamId id,
spdy::SpdyHeaderBlock headers,
bool fin,
- spdy::SpdyPriority priority,
+ const spdy::SpdyStreamPrecedence& precedence,
QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener);
// Writes a PRIORITY frame the to peer. Returns the size in bytes of the
@@ -142,9 +145,8 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession
bool server_push_enabled() const { return server_push_enabled_; }
- // Called by |QuicHeadersStream::UpdateEnableServerPush()| with
- // value from SETTINGS_ENABLE_PUSH.
- void set_server_push_enabled(bool enable) { server_push_enabled_ = enable; }
+ // Called when a setting is parsed from an incoming SETTINGS frame.
+ void OnSetting(uint64_t id, uint64_t value);
// Return true if this session wants to release headers stream's buffer
// aggressively.
@@ -153,14 +155,25 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession
void CloseConnectionWithDetails(QuicErrorCode error,
const std::string& details);
- // Must be called before Initialize().
+ // Must not be called after Initialize().
// TODO(bnc): Move to constructor argument.
- void set_max_inbound_header_list_size(size_t max_inbound_header_list_size) {
- max_inbound_header_list_size_ = max_inbound_header_list_size;
+ void set_qpack_maximum_dynamic_table_capacity(
+ uint64_t qpack_maximum_dynamic_table_capacity) {
+ qpack_maximum_dynamic_table_capacity_ =
+ qpack_maximum_dynamic_table_capacity;
+ }
+
+ // Must not be called after Initialize().
+ // TODO(bnc): Move to constructor argument.
+ void set_qpack_maximum_blocked_streams(
+ uint64_t qpack_maximum_blocked_streams) {
+ qpack_maximum_blocked_streams_ = qpack_maximum_blocked_streams;
}
- void set_max_outbound_header_list_size(size_t max_outbound_header_list_size) {
- max_outbound_header_list_size_ = max_outbound_header_list_size;
+ // Must not be called after Initialize().
+ // TODO(bnc): Move to constructor argument.
+ void set_max_inbound_header_list_size(size_t max_inbound_header_list_size) {
+ max_inbound_header_list_size_ = max_inbound_header_list_size;
}
size_t max_outbound_header_list_size() const {
@@ -174,6 +187,28 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession
// Returns true if the session has active request streams.
bool HasActiveRequestStreams() const;
+ // Called when the size of the compressed frame payload is available.
+ void OnCompressedFrameSize(size_t frame_len);
+
+ // Called when a PUSH_PROMISE frame has been received.
+ void OnPushPromise(spdy::SpdyStreamId stream_id,
+ spdy::SpdyStreamId promised_stream_id);
+
+ // Called when the complete list of headers is available.
+ void OnHeaderList(const QuicHeaderList& header_list);
+
+ QuicStreamId promised_stream_id() const { return promised_stream_id_; }
+
+ // Initialze HTTP/3 unidirectional streams if |unidirectional| is true and
+ // those streams are not initialized yet.
+ void OnCanCreateNewOutgoingStream(bool unidirectional) override;
+
+ void set_max_allowed_push_id(QuicStreamId max_allowed_push_id);
+
+ QuicStreamId max_allowed_push_id() { return max_allowed_push_id_; }
+
+ int32_t destruction_indicator() const { return destruction_indicator_; }
+
protected:
// Override CreateIncomingStream(), CreateOutgoingBidirectionalStream() and
// CreateOutgoingUnidirectionalStream() with QuicSpdyStream return type to
@@ -233,6 +268,18 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession
bool IsConnected() { return connection()->connected(); }
+ const QuicReceiveControlStream* receive_control_stream() const {
+ return receive_control_stream_;
+ }
+
+ // Initializes HTTP/3 unidirectional streams if not yet initialzed.
+ virtual void MaybeInitializeHttp3UnidirectionalStreams();
+
+ void set_max_uncompressed_header_bytes(
+ size_t set_max_uncompressed_header_bytes);
+
+ void SendMaxPushId(QuicStreamId max_allowed_push_id);
+
private:
friend class test::QuicSpdySessionPeer;
@@ -243,21 +290,15 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession
// Called when a HEADERS frame has been received.
void OnHeaders(spdy::SpdyStreamId stream_id,
bool has_priority,
- spdy::SpdyPriority priority,
+ const spdy::SpdyStreamPrecedence& precedence,
bool fin);
- // Called when a PUSH_PROMISE frame has been received.
- void OnPushPromise(spdy::SpdyStreamId stream_id,
- spdy::SpdyStreamId promised_stream_id);
-
// Called when a PRIORITY frame has been received.
- void OnPriority(spdy::SpdyStreamId stream_id, spdy::SpdyPriority priority);
-
- // Called when the complete list of headers is available.
- void OnHeaderList(const QuicHeaderList& header_list);
+ void OnPriority(spdy::SpdyStreamId stream_id,
+ const spdy::SpdyStreamPrecedence& precedence);
- // Called when the size of the compressed frame payload is available.
- void OnCompressedFrameSize(size_t frame_len);
+ void CloseConnectionOnDuplicateHttp3UnidirectionalStreams(
+ QuicStringPiece type);
std::unique_ptr<QpackEncoder> qpack_encoder_;
std::unique_ptr<QpackDecoder> qpack_decoder_;
@@ -265,13 +306,32 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession
// Pointer to the header stream in stream_map_.
QuicHeadersStream* headers_stream_;
- // HTTP/3 control streams. They are owned by QuicSession inside dynamic
+ // HTTP/3 control streams. They are owned by QuicSession inside
// stream map, and can be accessed by those unowned pointers below.
QuicSendControlStream* send_control_stream_;
QuicReceiveControlStream* receive_control_stream_;
+ // Pointers to HTTP/3 QPACK streams in stream map.
+ QpackReceiveStream* qpack_encoder_receive_stream_;
+ QpackReceiveStream* qpack_decoder_receive_stream_;
+ QpackSendStream* qpack_encoder_send_stream_;
+ QpackSendStream* qpack_decoder_send_stream_;
+
+ // Maximum dynamic table capacity as defined at
+ // https://quicwg.org/base-drafts/draft-ietf-quic-qpack.html#maximum-dynamic-table-capacity
+ // for the decoding context. Value will be sent via
+ // SETTINGS_QPACK_MAX_TABLE_CAPACITY.
+ uint64_t qpack_maximum_dynamic_table_capacity_;
+
+ // Maximum number of blocked streams as defined at
+ // https://quicwg.org/base-drafts/draft-ietf-quic-qpack.html#blocked-streams
+ // for the decoding context. Value will be sent via
+ // SETTINGS_QPACK_BLOCKED_STREAMS.
+ uint64_t qpack_maximum_blocked_streams_;
+
// The maximum size of a header block that will be accepted from the peer,
// defined per spec as key + value + overhead per field (uncompressed).
+ // Value will be sent via SETTINGS_MAX_HEADER_LIST_SIZE.
size_t max_inbound_header_list_size_;
// The maximum size of a header block that can be sent to the peer. This field
@@ -288,17 +348,18 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession
QuicStreamId promised_stream_id_;
bool fin_;
size_t frame_len_;
- size_t uncompressed_frame_len_;
bool supports_push_promise_;
spdy::SpdyFramer spdy_framer_;
http2::Http2DecoderAdapter h2_deframer_;
std::unique_ptr<SpdyFramerVisitor> spdy_framer_visitor_;
+ QuicStreamId max_allowed_push_id_;
- // TODO(renjietang): Replace these two members with actual QPACK send streams.
- NoopQpackStreamSenderDelegate encoder_stream_sender_delegate_;
- NoopQpackStreamSenderDelegate decoder_stream_sender_delegate_;
+ // An integer used for live check. The indicator is assigned a value in
+ // constructor. As long as it is not the assigned value, that would indicate
+ // an use-after-free.
+ int32_t destruction_indicator_;
};
} // 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 2042f88019e..55de8b68475 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
@@ -11,12 +11,15 @@
#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h"
#include "net/third_party/quiche/src/quic/core/crypto/null_encrypter.h"
+#include "net/third_party/quiche/src/quic/core/frames/quic_stream_frame.h"
#include "net/third_party/quiche/src/quic/core/http/http_constants.h"
#include "net/third_party/quiche/src/quic/core/quic_crypto_stream.h"
#include "net/third_party/quiche/src/quic/core/quic_data_writer.h"
#include "net/third_party/quiche/src/quic/core/quic_packets.h"
#include "net/third_party/quiche/src/quic/core/quic_stream.h"
#include "net/third_party/quiche/src/quic/core/quic_utils.h"
+#include "net/third_party/quiche/src/quic/core/quic_versions.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_map_util.h"
@@ -24,6 +27,9 @@
#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
+#include "net/third_party/quiche/src/quic/test_tools/qpack_encoder_peer.h"
+#include "net/third_party/quiche/src/quic/test_tools/qpack_header_table_peer.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_config_peer.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_flow_controller_peer.h"
@@ -52,6 +58,11 @@ namespace quic {
namespace test {
namespace {
+bool VerifyAndClearStopSendingFrame(const QuicFrame& frame) {
+ EXPECT_EQ(STOP_SENDING_FRAME, frame.type);
+ return ClearControlFrame(frame);
+}
+
class TestCryptoStream : public QuicCryptoStream, public QuicCryptoHandshaker {
public:
explicit TestCryptoStream(QuicSession* session)
@@ -293,6 +304,11 @@ class QuicSpdySessionTestBase : public QuicTestWithParam<ParsedQuicVersion> {
kInitialStreamFlowControlWindowForTest);
session_.config()->SetInitialSessionFlowControlWindowToSend(
kInitialSessionFlowControlWindowForTest);
+ if (VersionUsesQpack(transport_version())) {
+ QuicConfigPeer::SetReceivedMaxIncomingUnidirectionalStreams(
+ session_.config(),
+ session_.num_expected_unidirectional_static_streams());
+ }
connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
TestCryptoStream* crypto_stream = session_.GetMutableCryptoStream();
EXPECT_CALL(*crypto_stream, HasPendingRetransmission())
@@ -406,7 +422,14 @@ TEST_P(QuicSpdySessionTestServer, SelfAddress) {
}
TEST_P(QuicSpdySessionTestServer, IsCryptoHandshakeConfirmed) {
- EXPECT_CALL(*connection_, CloseConnection(_, _, _));
+ if (!GetQuicReloadableFlag(quic_do_not_send_settings) ||
+ VersionUsesQpack(transport_version())) {
+ MockPacketWriter* writer = static_cast<MockPacketWriter*>(
+ QuicConnectionPeer::GetWriter(session_.connection()));
+ EXPECT_CALL(*writer, WritePacket(_, _, _, _, _))
+ .Times(1)
+ .WillRepeatedly(Return(WriteResult(WRITE_STATUS_OK, 0)));
+ }
EXPECT_FALSE(session_.IsCryptoHandshakeConfirmed());
CryptoHandshakeMessage message;
session_.GetMutableCryptoStream()->OnHandshakeMessage(message);
@@ -477,12 +500,9 @@ TEST_P(QuicSpdySessionTestServer, MaximumAvailableOpenedStreams) {
// stream ID, the next ID should fail. Since the actual limit
// is not the number of open streams, we allocate the max and the max+2.
// Get the max allowed stream ID, this should succeed.
- QuicStreamCount headers_stream_offset =
- VersionLacksHeadersStream(QUIC_VERSION_99) ? 1 : 0;
QuicStreamId stream_id = StreamCountToId(
QuicSessionPeer::v99_streamid_manager(&session_)
- ->actual_max_allowed_incoming_bidirectional_streams() -
- headers_stream_offset,
+ ->actual_max_allowed_incoming_bidirectional_streams(),
Perspective::IS_CLIENT, // Client initates stream, allocs stream id.
/*bidirectional=*/true);
EXPECT_NE(nullptr, session_.GetOrCreateStream(stream_id));
@@ -497,7 +517,7 @@ TEST_P(QuicSpdySessionTestServer, MaximumAvailableOpenedStreams) {
stream_id = StreamCountToId(
QuicSessionPeer::v99_streamid_manager(&session_)
->actual_max_allowed_incoming_bidirectional_streams() +
- 1 - headers_stream_offset,
+ 1,
Perspective::IS_CLIENT,
/*bidirectional=*/true);
EXPECT_EQ(nullptr, session_.GetOrCreateStream(stream_id));
@@ -654,7 +674,7 @@ TEST_P(QuicSpdySessionTestServer, TestBatchedWrites) {
// Now let stream 4 do the 2nd of its 3 writes, but add a block for a high
// priority stream 6. 4 should be preempted. 6 will write but *not* block so
// will cede back to 4.
- stream6->SetPriority(kV3HighestPriority);
+ stream6->SetPriority(spdy::SpdyStreamPrecedence(kV3HighestPriority));
EXPECT_CALL(*stream4, OnCanWrite())
.WillOnce(Invoke([this, stream4, stream6]() {
session_.SendLargeFakeData(stream4, 6000);
@@ -687,13 +707,16 @@ TEST_P(QuicSpdySessionTestServer, OnCanWriteBundlesStreams) {
.WillRepeatedly(Invoke(
this, &QuicSpdySessionTestServer::ClearMaxStreamsControlFrame));
}
+
// Encryption needs to be established before data can be sent.
CryptoHandshakeMessage msg;
MockPacketWriter* writer = static_cast<MockPacketWriter*>(
QuicConnectionPeer::GetWriter(session_.connection()));
EXPECT_CALL(*writer, WritePacket(_, _, _, _, _))
- .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 0)));
+ .Times(testing::AnyNumber())
+ .WillRepeatedly(Return(WriteResult(WRITE_STATUS_OK, 0)));
session_.GetMutableCryptoStream()->OnHandshakeMessage(msg);
+ testing::Mock::VerifyAndClearExpectations(writer);
// Drive congestion control manually.
MockSendAlgorithm* send_algorithm = new StrictMock<MockSendAlgorithm>;
@@ -927,14 +950,16 @@ TEST_P(QuicSpdySessionTestServer,
TestCryptoStream* crypto_stream = session_.GetMutableCryptoStream();
EXPECT_CALL(*crypto_stream, OnCanWrite());
}
- TestHeadersStream* headers_stream;
- QuicSpdySessionPeer::SetHeadersStream(&session_, nullptr);
- headers_stream = new TestHeadersStream(&session_);
- QuicSpdySessionPeer::SetHeadersStream(&session_, headers_stream);
- session_.MarkConnectionLevelWriteBlocked(
- QuicUtils::GetHeadersStreamId(connection_->transport_version()));
- EXPECT_CALL(*headers_stream, OnCanWrite());
+ if (!VersionUsesQpack(connection_->transport_version())) {
+ TestHeadersStream* headers_stream;
+ QuicSpdySessionPeer::SetHeadersStream(&session_, nullptr);
+ headers_stream = new TestHeadersStream(&session_);
+ QuicSpdySessionPeer::SetHeadersStream(&session_, headers_stream);
+ session_.MarkConnectionLevelWriteBlocked(
+ QuicUtils::GetHeadersStreamId(connection_->transport_version()));
+ EXPECT_CALL(*headers_stream, OnCanWrite());
+ }
// After the crypto and header streams perform a write, the connection will be
// blocked by the flow control, hence it should become application-limited.
@@ -949,6 +974,7 @@ TEST_P(QuicSpdySessionTestServer, SendGoAway) {
// GoAway frames are not in version 99
return;
}
+ connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
MockPacketWriter* writer = static_cast<MockPacketWriter*>(
QuicConnectionPeer::GetWriter(session_.connection()));
EXPECT_CALL(*writer, WritePacket(_, _, _, _, _))
@@ -1010,13 +1036,20 @@ TEST_P(QuicSpdySessionTestServer, ServerReplyToConnecitivityProbe) {
connection_->OnPathChallengeFrame(
QuicPathChallengeFrame(0, {{0, 1, 2, 3, 4, 5, 6, 7}}));
}
- session_.OnConnectivityProbeReceived(session_.self_address(),
- new_peer_address);
+ session_.OnPacketReceived(session_.self_address(), new_peer_address,
+ /*is_connectivity_probe=*/true);
EXPECT_EQ(old_peer_address, session_.peer_address());
}
TEST_P(QuicSpdySessionTestServer, IncreasedTimeoutAfterCryptoHandshake) {
- EXPECT_CALL(*connection_, CloseConnection(_, _, _));
+ if (!GetQuicReloadableFlag(quic_do_not_send_settings) ||
+ VersionUsesQpack(transport_version())) {
+ MockPacketWriter* writer = static_cast<MockPacketWriter*>(
+ QuicConnectionPeer::GetWriter(session_.connection()));
+ EXPECT_CALL(*writer, WritePacket(_, _, _, _, _))
+ .Times(1)
+ .WillRepeatedly(Return(WriteResult(WRITE_STATUS_OK, 0)));
+ }
EXPECT_EQ(kInitialIdleTimeoutSecs + 3,
QuicConnectionPeer::GetNetworkTimeout(connection_).ToSeconds());
CryptoHandshakeMessage msg;
@@ -1066,10 +1099,20 @@ TEST_P(QuicSpdySessionTestServer, RstStreamBeforeHeadersDecompressed) {
}
TEST_P(QuicSpdySessionTestServer, OnStreamFrameFinStaticStreamId) {
+ QuicStreamId id;
+ // Initialize HTTP/3 control stream.
+ if (VersionUsesQpack(transport_version())) {
+ id = GetNthClientInitiatedUnidirectionalStreamId(transport_version(), 3);
+ char type[] = {kControlStream};
+
+ QuicStreamFrame data1(id, false, 0, QuicStringPiece(type, 1));
+ session_.OnStreamFrame(data1);
+ } else {
+ id = QuicUtils::GetHeadersStreamId(connection_->transport_version());
+ }
+
// Send two bytes of payload.
- QuicStreamFrame data1(
- QuicUtils::GetHeadersStreamId(connection_->transport_version()), true, 0,
- QuicStringPiece("HT"));
+ QuicStreamFrame data1(id, true, 0, QuicStringPiece("HT"));
EXPECT_CALL(*connection_,
CloseConnection(
QUIC_INVALID_STREAM_ID, "Attempt to close a static stream",
@@ -1078,11 +1121,21 @@ TEST_P(QuicSpdySessionTestServer, OnStreamFrameFinStaticStreamId) {
}
TEST_P(QuicSpdySessionTestServer, OnRstStreamStaticStreamId) {
+ QuicStreamId id;
+ // Initialize HTTP/3 control stream.
+ if (VersionUsesQpack(transport_version())) {
+ id = GetNthClientInitiatedUnidirectionalStreamId(transport_version(), 3);
+ char type[] = {kControlStream};
+
+ QuicStreamFrame data1(id, false, 0, QuicStringPiece(type, 1));
+ session_.OnStreamFrame(data1);
+ } else {
+ id = QuicUtils::GetHeadersStreamId(connection_->transport_version());
+ }
+
// Send two bytes of payload.
- QuicRstStreamFrame rst1(
- kInvalidControlFrameId,
- QuicUtils::GetHeadersStreamId(connection_->transport_version()),
- QUIC_ERROR_PROCESSING_STREAM, 0);
+ QuicRstStreamFrame rst1(kInvalidControlFrameId, id,
+ QUIC_ERROR_PROCESSING_STREAM, 0);
EXPECT_CALL(*connection_,
CloseConnection(
QUIC_INVALID_STREAM_ID, "Attempt to reset a static stream",
@@ -1253,14 +1306,15 @@ TEST_P(QuicSpdySessionTestServer,
EXPECT_FALSE(session_.IsStreamFlowControlBlocked());
headers["header"] = QuicStrCat(random.RandUint64(), random.RandUint64(),
random.RandUint64());
- session_.WriteHeadersOnHeadersStream(stream_id, headers.Clone(), true, 0,
+ session_.WriteHeadersOnHeadersStream(stream_id, headers.Clone(), true,
+ spdy::SpdyStreamPrecedence(0),
nullptr);
stream_id += IdDelta();
}
// Write once more to ensure that the headers stream has buffered data. The
// random headers may have exactly filled the flow control window.
- session_.WriteHeadersOnHeadersStream(stream_id, std::move(headers), true, 0,
- nullptr);
+ session_.WriteHeadersOnHeadersStream(stream_id, std::move(headers), true,
+ spdy::SpdyStreamPrecedence(0), nullptr);
EXPECT_TRUE(headers_stream->HasBufferedData());
EXPECT_TRUE(headers_stream->flow_controller()->IsBlocked());
@@ -1494,11 +1548,10 @@ TEST_P(QuicSpdySessionTestServer, FlowControlWithInvalidFinalOffset) {
}
TEST_P(QuicSpdySessionTestServer, WindowUpdateUnblocksHeadersStream) {
- if (GetParam().handshake_protocol == PROTOCOL_TLS1_3) {
- // TODO(nharper, b/112643533): Figure out why this test fails when TLS is
- // enabled and fix it.
+ if (VersionUsesQpack(GetParam().transport_version)) {
return;
}
+
// Test that a flow control blocked headers stream gets unblocked on recipt of
// a WINDOW_UPDATE frame.
@@ -1583,7 +1636,7 @@ TEST_P(QuicSpdySessionTestServer,
*connection_,
CloseConnection(QUIC_INVALID_STREAM_ID,
testing::MatchesRegex(
- "Stream id \\d+ would exceed stream count limit 6"),
+ "Stream id \\d+ would exceed stream count limit 5"),
_));
}
// Create one more data streams to exceed limit of open stream.
@@ -1690,8 +1743,6 @@ TEST_P(QuicSpdySessionTestClient, TooLargeHeadersMustNotCauseWriteAfterReset) {
return;
}
- SetQuicReloadableFlag(quic_avoid_empty_frame_after_empty_headers, true);
-
TestStream* stream = session_.CreateOutgoingBidirectionalStream();
// Write headers with FIN set to close write side of stream.
@@ -1785,24 +1836,27 @@ TEST_P(QuicSpdySessionTestClient, Http3ServerPush) {
return;
}
- char type[] = {0x01};
- std::string data = std::string(type, 1) + "header";
EXPECT_EQ(0u, session_.GetNumOpenIncomingStreams());
+
+ // Push unidirectional stream is type 0x01.
+ std::string frame_type1 = QuicTextUtils::HexDecode("01");
QuicStreamId stream_id1 =
GetNthServerInitiatedUnidirectionalStreamId(transport_version(), 0);
- QuicStreamFrame data1(stream_id1, false, 0, QuicStringPiece(data));
- session_.OnStreamFrame(data1);
+ session_.OnStreamFrame(QuicStreamFrame(stream_id1, /* fin = */ false,
+ /* offset = */ 0, frame_type1));
+
EXPECT_EQ(1u, session_.GetNumOpenIncomingStreams());
QuicStream* stream = session_.GetOrCreateStream(stream_id1);
EXPECT_EQ(1u, stream->flow_controller()->bytes_consumed());
EXPECT_EQ(1u, session_.flow_controller()->bytes_consumed());
- char unoptimized_type[] = {0x80, 0x00, 0x00, 0x01};
- data = std::string(unoptimized_type, 4) + "header";
+ // The same stream type can be encoded differently.
+ std::string frame_type2 = QuicTextUtils::HexDecode("80000001");
QuicStreamId stream_id2 =
GetNthServerInitiatedUnidirectionalStreamId(transport_version(), 1);
- QuicStreamFrame data2(stream_id2, false, 0, QuicStringPiece(data));
- session_.OnStreamFrame(data2);
+ session_.OnStreamFrame(QuicStreamFrame(stream_id2, /* fin = */ false,
+ /* offset = */ 0, frame_type2));
+
EXPECT_EQ(2u, session_.GetNumOpenIncomingStreams());
stream = session_.GetOrCreateStream(stream_id2);
EXPECT_EQ(4u, stream->flow_controller()->bytes_consumed());
@@ -1814,19 +1868,30 @@ TEST_P(QuicSpdySessionTestClient, Http3ServerPushOutofOrderFrame) {
return;
}
- char type[] = {0x01};
- EXPECT_EQ(0u, session_.GetNumOpenIncomingStreams());
- QuicStreamFrame data1(
- GetNthServerInitiatedUnidirectionalStreamId(transport_version(), 0),
- false, 1, QuicStringPiece("header"));
- session_.OnStreamFrame(data1);
EXPECT_EQ(0u, session_.GetNumOpenIncomingStreams());
- QuicStreamFrame data2(
- GetNthServerInitiatedUnidirectionalStreamId(transport_version(), 0),
- false, 0, QuicStringPiece(type, 1));
+ // Push unidirectional stream is type 0x01.
+ std::string frame_type = QuicTextUtils::HexDecode("01");
+ // The first field of a push stream is the Push ID.
+ std::string push_id = QuicTextUtils::HexDecode("4000");
+
+ QuicStreamId stream_id =
+ GetNthServerInitiatedUnidirectionalStreamId(transport_version(), 0);
+
+ QuicStreamFrame data1(stream_id,
+ /* fin = */ false, /* offset = */ 0, frame_type);
+ QuicStreamFrame data2(stream_id,
+ /* fin = */ false, /* offset = */ frame_type.size(),
+ push_id);
+
+ // Receiving some stream data without stream type does not open the stream.
session_.OnStreamFrame(data2);
+ EXPECT_EQ(0u, session_.GetNumOpenIncomingStreams());
+
+ session_.OnStreamFrame(data1);
EXPECT_EQ(1u, session_.GetNumOpenIncomingStreams());
+ QuicStream* stream = session_.GetOrCreateStream(stream_id);
+ EXPECT_EQ(3u, stream->flow_controller()->highest_received_byte_offset());
}
TEST_P(QuicSpdySessionTestServer, ZombieStreams) {
@@ -2006,49 +2071,86 @@ TEST_P(QuicSpdySessionTestServer, RetransmitFrames) {
TEST_P(QuicSpdySessionTestServer, OnPriorityFrame) {
QuicStreamId stream_id = GetNthClientInitiatedBidirectionalId(0);
TestStream* stream = session_.CreateIncomingStream(stream_id);
- session_.OnPriorityFrame(stream_id, kV3HighestPriority);
- EXPECT_EQ(kV3HighestPriority, stream->priority());
+ session_.OnPriorityFrame(stream_id,
+ spdy::SpdyStreamPrecedence(kV3HighestPriority));
+ EXPECT_EQ(spdy::SpdyStreamPrecedence(kV3HighestPriority),
+ stream->precedence());
}
TEST_P(QuicSpdySessionTestServer, SimplePendingStreamType) {
if (!VersionHasStreamType(transport_version())) {
return;
}
- PendingStream pending(QuicUtils::GetFirstUnidirectionalStreamId(
- transport_version(), Perspective::IS_CLIENT),
- &session_);
- char input[] = {// type
- 0x04,
- // data
- 'a', 'b', 'c'};
- QuicStreamFrame data(pending.id(), true, 0, QuicStringPiece(input, 4));
- pending.OnStreamFrame(data);
-
- // A stop sending frame will be sent to indicate unknown type.
- EXPECT_CALL(*connection_, SendControlFrame(_));
- session_.ProcessPendingStream(&pending);
+
+ char input[] = {0x04, // type
+ 'a', 'b', 'c'}; // data
+ QuicStringPiece payload(input, QUIC_ARRAYSIZE(input));
+
+ // This is a server test with a client-initiated unidirectional stream.
+ QuicStreamId stream_id = QuicUtils::GetFirstUnidirectionalStreamId(
+ transport_version(), Perspective::IS_CLIENT);
+
+ for (bool fin : {true, false}) {
+ QuicStreamFrame frame(stream_id, fin, /* offset = */ 0, payload);
+
+ // A STOP_SENDING frame is sent in response to the unknown stream type.
+ EXPECT_CALL(*connection_, SendControlFrame(_))
+ .WillOnce(Invoke(&VerifyAndClearStopSendingFrame));
+ session_.OnStreamFrame(frame);
+
+ PendingStream* pending =
+ QuicSessionPeer::GetPendingStream(&session_, stream_id);
+ if (fin) {
+ // Stream is closed if FIN is received.
+ EXPECT_FALSE(pending);
+ } else {
+ ASSERT_TRUE(pending);
+ // The pending stream must ignore read data.
+ EXPECT_TRUE(pending->sequencer()->ignore_read_data());
+ }
+
+ stream_id += QuicUtils::StreamIdDelta(transport_version());
+ }
}
TEST_P(QuicSpdySessionTestServer, SimplePendingStreamTypeOutOfOrderDelivery) {
if (!VersionHasStreamType(transport_version())) {
return;
}
- PendingStream pending(QuicUtils::GetFirstUnidirectionalStreamId(
- transport_version(), Perspective::IS_CLIENT),
- &session_);
- char input[] = {// type
- 0x04,
- // data
- 'a', 'b', 'c'};
- QuicStreamFrame data1(pending.id(), true, 1, QuicStringPiece(&input[1], 3));
- pending.OnStreamFrame(data1);
- session_.ProcessPendingStream(&pending);
- QuicStreamFrame data2(pending.id(), false, 0, QuicStringPiece(input, 1));
- pending.OnStreamFrame(data2);
+ char input[] = {0x04, // type
+ 'a', 'b', 'c'}; // data
+ QuicStringPiece payload(input, QUIC_ARRAYSIZE(input));
- EXPECT_CALL(*connection_, SendControlFrame(_));
- session_.ProcessPendingStream(&pending);
+ // This is a server test with a client-initiated unidirectional stream.
+ QuicStreamId stream_id = QuicUtils::GetFirstUnidirectionalStreamId(
+ transport_version(), Perspective::IS_CLIENT);
+
+ for (bool fin : {true, false}) {
+ QuicStreamFrame frame1(stream_id, /* fin = */ false, /* offset = */ 0,
+ payload.substr(0, 1));
+ QuicStreamFrame frame2(stream_id, fin, /* offset = */ 1, payload.substr(1));
+
+ // Deliver frames out of order.
+ session_.OnStreamFrame(frame2);
+ // A STOP_SENDING frame is sent in response to the unknown stream type.
+ EXPECT_CALL(*connection_, SendControlFrame(_))
+ .WillOnce(Invoke(&VerifyAndClearStopSendingFrame));
+ session_.OnStreamFrame(frame1);
+
+ PendingStream* pending =
+ QuicSessionPeer::GetPendingStream(&session_, stream_id);
+ if (fin) {
+ // Stream is closed if FIN is received.
+ EXPECT_FALSE(pending);
+ } else {
+ ASSERT_TRUE(pending);
+ // The pending stream must ignore read data.
+ EXPECT_TRUE(pending->sequencer()->ignore_read_data());
+ }
+
+ stream_id += QuicUtils::StreamIdDelta(transport_version());
+ }
}
TEST_P(QuicSpdySessionTestServer,
@@ -2056,34 +2158,51 @@ TEST_P(QuicSpdySessionTestServer,
if (!VersionHasStreamType(transport_version())) {
return;
}
- PendingStream pending(QuicUtils::GetFirstUnidirectionalStreamId(
- transport_version(), Perspective::IS_CLIENT),
- &session_);
- char input[] = {// type (256)
- 0x40 + 0x01, 0x00,
- // data
- 'a', 'b', 'c'};
- QuicStreamFrame data1(pending.id(), true, 2, QuicStringPiece(&input[2], 3));
- pending.OnStreamFrame(data1);
- session_.ProcessPendingStream(&pending);
+ char input[] = {0x41, 0x00, // type (256)
+ 'a', 'b', 'c'}; // data
+ QuicStringPiece payload(input, QUIC_ARRAYSIZE(input));
- QuicStreamFrame data2(pending.id(), false, 0, QuicStringPiece(input, 1));
- pending.OnStreamFrame(data2);
- session_.ProcessPendingStream(&pending);
+ // This is a server test with a client-initiated unidirectional stream.
+ QuicStreamId stream_id = QuicUtils::GetFirstUnidirectionalStreamId(
+ transport_version(), Perspective::IS_CLIENT);
- QuicStreamFrame data3(pending.id(), false, 1, QuicStringPiece(&input[1], 1));
- pending.OnStreamFrame(data3);
+ for (bool fin : {true, false}) {
+ QuicStreamFrame frame1(stream_id, /* fin = */ false, /* offset = */ 0,
+ payload.substr(0, 1));
+ QuicStreamFrame frame2(stream_id, /* fin = */ false, /* offset = */ 1,
+ payload.substr(1, 1));
+ QuicStreamFrame frame3(stream_id, fin, /* offset = */ 2, payload.substr(2));
- EXPECT_CALL(*connection_, SendControlFrame(_));
- session_.ProcessPendingStream(&pending);
+ // Deliver frames out of order.
+ session_.OnStreamFrame(frame3);
+ // The first byte does not contain the entire type varint.
+ session_.OnStreamFrame(frame1);
+ // A STOP_SENDING frame is sent in response to the unknown stream type.
+ EXPECT_CALL(*connection_, SendControlFrame(_))
+ .WillOnce(Invoke(&VerifyAndClearStopSendingFrame));
+ session_.OnStreamFrame(frame2);
+
+ PendingStream* pending =
+ QuicSessionPeer::GetPendingStream(&session_, stream_id);
+ if (fin) {
+ // Stream is closed if FIN is received.
+ EXPECT_FALSE(pending);
+ } else {
+ ASSERT_TRUE(pending);
+ // The pending stream must ignore read data.
+ EXPECT_TRUE(pending->sequencer()->ignore_read_data());
+ }
+
+ stream_id += QuicUtils::StreamIdDelta(transport_version());
+ }
}
TEST_P(QuicSpdySessionTestServer, ReceiveControlStream) {
if (!VersionHasStreamType(transport_version())) {
return;
}
- // Use a arbitrary stream id.
+ // Use an arbitrary stream id.
QuicStreamId stream_id =
GetNthClientInitiatedUnidirectionalStreamId(transport_version(), 3);
char type[] = {kControlStream};
@@ -2094,14 +2213,27 @@ TEST_P(QuicSpdySessionTestServer, ReceiveControlStream) {
QuicSpdySessionPeer::GetReceiveControlStream(&session_)->id());
SettingsFrame settings;
- settings.values[3] = 2;
- settings.values[kSettingsMaxHeaderListSize] = 5;
+ settings.values[SETTINGS_QPACK_MAX_TABLE_CAPACITY] = 512;
+ settings.values[SETTINGS_MAX_HEADER_LIST_SIZE] = 5;
+ settings.values[SETTINGS_QPACK_BLOCKED_STREAMS] = 42;
std::string data = EncodeSettings(settings);
QuicStreamFrame frame(stream_id, false, 1, QuicStringPiece(data));
+ QpackEncoder* qpack_encoder = session_.qpack_encoder();
+ QpackHeaderTable* header_table =
+ QpackEncoderPeer::header_table(qpack_encoder);
+
+ EXPECT_NE(512u,
+ QpackHeaderTablePeer::maximum_dynamic_table_capacity(header_table));
EXPECT_NE(5u, session_.max_outbound_header_list_size());
+ EXPECT_NE(42u, QpackEncoderPeer::maximum_blocked_streams(qpack_encoder));
+
session_.OnStreamFrame(frame);
+
+ EXPECT_EQ(512u,
+ QpackHeaderTablePeer::maximum_dynamic_table_capacity(header_table));
EXPECT_EQ(5u, session_.max_outbound_header_list_size());
+ EXPECT_EQ(42u, QpackEncoderPeer::maximum_blocked_streams(qpack_encoder));
}
TEST_P(QuicSpdySessionTestServer, ReceiveControlStreamOutOfOrderDelivery) {
@@ -2114,7 +2246,7 @@ TEST_P(QuicSpdySessionTestServer, ReceiveControlStreamOutOfOrderDelivery) {
char type[] = {kControlStream};
SettingsFrame settings;
settings.values[3] = 2;
- settings.values[kSettingsMaxHeaderListSize] = 5;
+ settings.values[SETTINGS_MAX_HEADER_LIST_SIZE] = 5;
std::string data = EncodeSettings(settings);
QuicStreamFrame data1(stream_id, false, 1, QuicStringPiece(data));
@@ -2126,6 +2258,203 @@ TEST_P(QuicSpdySessionTestServer, ReceiveControlStreamOutOfOrderDelivery) {
EXPECT_EQ(5u, session_.max_outbound_header_list_size());
}
+TEST_P(QuicSpdySessionTestClient, ResetAfterInvalidIncomingStreamType) {
+ if (!VersionHasStreamType(transport_version())) {
+ return;
+ }
+ ASSERT_TRUE(session_.UsesPendingStreams());
+
+ const QuicStreamId stream_id =
+ GetNthServerInitiatedUnidirectionalStreamId(transport_version(), 0);
+
+ // 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
+ // must not be interpreted as stream type.
+ std::string payload = QuicTextUtils::HexDecode("3f01");
+ QuicStreamFrame frame(stream_id, /* fin = */ false, /* offset = */ 0,
+ payload);
+
+ // A STOP_SENDING frame is sent in response to the unknown stream type.
+ EXPECT_CALL(*connection_, SendControlFrame(_))
+ .WillOnce(Invoke(&VerifyAndClearStopSendingFrame));
+ session_.OnStreamFrame(frame);
+
+ // There are no active streams.
+ EXPECT_EQ(0u, session_.GetNumOpenIncomingStreams());
+
+ // The pending stream is still around, because it did not receive a FIN.
+ PendingStream* pending =
+ QuicSessionPeer::GetPendingStream(&session_, stream_id);
+ ASSERT_TRUE(pending);
+
+ // The pending stream must ignore read data.
+ EXPECT_TRUE(pending->sequencer()->ignore_read_data());
+
+ // If the stream frame is received again, it should be ignored.
+ session_.OnStreamFrame(frame);
+
+ // Receive RESET_STREAM.
+ QuicRstStreamFrame rst_frame(kInvalidControlFrameId, stream_id,
+ QUIC_STREAM_CANCELLED,
+ /* bytes_written = */ payload.size());
+
+ // This will trigger the sending of two control frames: one RESET_STREAM with
+ // QUIC_RST_ACKNOWLEDGEMENT, and one STOP_SENDING.
+ EXPECT_CALL(*connection_, SendControlFrame(_))
+ .Times(2)
+ .WillRepeatedly(Invoke(&ClearControlFrame));
+ EXPECT_CALL(*connection_, OnStreamReset(stream_id, QUIC_RST_ACKNOWLEDGEMENT));
+ session_.OnRstStream(rst_frame);
+
+ // The stream is closed.
+ EXPECT_FALSE(QuicSessionPeer::GetPendingStream(&session_, stream_id));
+}
+
+TEST_P(QuicSpdySessionTestClient, FinAfterInvalidIncomingStreamType) {
+ if (!VersionHasStreamType(transport_version())) {
+ return;
+ }
+ ASSERT_TRUE(session_.UsesPendingStreams());
+
+ const QuicStreamId stream_id =
+ GetNthServerInitiatedUnidirectionalStreamId(transport_version(), 0);
+
+ // 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
+ // must not be interpreted as stream type.
+ std::string payload = QuicTextUtils::HexDecode("3f01");
+ QuicStreamFrame frame(stream_id, /* fin = */ false, /* offset = */ 0,
+ payload);
+
+ // A STOP_SENDING frame is sent in response to the unknown stream type.
+ EXPECT_CALL(*connection_, SendControlFrame(_))
+ .WillOnce(Invoke(&VerifyAndClearStopSendingFrame));
+ session_.OnStreamFrame(frame);
+
+ // The pending stream is still around, because it did not receive a FIN.
+ PendingStream* pending =
+ QuicSessionPeer::GetPendingStream(&session_, stream_id);
+ EXPECT_TRUE(pending);
+
+ // The pending stream must ignore read data.
+ EXPECT_TRUE(pending->sequencer()->ignore_read_data());
+
+ // If the stream frame is received again, it should be ignored.
+ session_.OnStreamFrame(frame);
+
+ // Receive FIN.
+ session_.OnStreamFrame(QuicStreamFrame(stream_id, /* fin = */ true,
+ /* offset = */ payload.size(), ""));
+
+ EXPECT_FALSE(QuicSessionPeer::GetPendingStream(&session_, stream_id));
+}
+
+TEST_P(QuicSpdySessionTestClient, ResetInMiddleOfStreamType) {
+ if (!VersionHasStreamType(transport_version())) {
+ return;
+ }
+ ASSERT_TRUE(session_.UsesPendingStreams());
+
+ const QuicStreamId stream_id =
+ GetNthServerInitiatedUnidirectionalStreamId(transport_version(), 0);
+
+ // Payload is the first byte of a two byte varint encoding.
+ std::string payload = QuicTextUtils::HexDecode("40");
+ QuicStreamFrame frame(stream_id, /* fin = */ false, /* offset = */ 0,
+ payload);
+
+ session_.OnStreamFrame(frame);
+ EXPECT_TRUE(QuicSessionPeer::GetPendingStream(&session_, stream_id));
+
+ // Receive RESET_STREAM.
+ QuicRstStreamFrame rst_frame(kInvalidControlFrameId, stream_id,
+ QUIC_STREAM_CANCELLED,
+ /* bytes_written = */ payload.size());
+
+ // This will trigger the sending of two control frames: one RESET_STREAM with
+ // QUIC_RST_ACKNOWLEDGEMENT, and one STOP_SENDING.
+ EXPECT_CALL(*connection_, SendControlFrame(_))
+ .Times(2)
+ .WillRepeatedly(Invoke(&ClearControlFrame));
+ EXPECT_CALL(*connection_, OnStreamReset(stream_id, QUIC_RST_ACKNOWLEDGEMENT));
+ session_.OnRstStream(rst_frame);
+
+ // The stream is closed.
+ EXPECT_FALSE(QuicSessionPeer::GetPendingStream(&session_, stream_id));
+}
+
+TEST_P(QuicSpdySessionTestClient, FinInMiddleOfStreamType) {
+ if (!VersionHasStreamType(transport_version())) {
+ return;
+ }
+ ASSERT_TRUE(session_.UsesPendingStreams());
+
+ const QuicStreamId stream_id =
+ GetNthServerInitiatedUnidirectionalStreamId(transport_version(), 0);
+
+ // Payload is the first byte of a two byte varint encoding with a FIN.
+ std::string payload = QuicTextUtils::HexDecode("40");
+ QuicStreamFrame frame(stream_id, /* fin = */ true, /* offset = */ 0, payload);
+
+ session_.OnStreamFrame(frame);
+ EXPECT_FALSE(QuicSessionPeer::GetPendingStream(&session_, stream_id));
+}
+
+TEST_P(QuicSpdySessionTestClient, DuplicateHttp3UnidirectionalStreams) {
+ if (!VersionHasStreamType(transport_version())) {
+ return;
+ }
+ QuicStreamId id1 =
+ GetNthServerInitiatedUnidirectionalStreamId(transport_version(), 0);
+ char type1[] = {kControlStream};
+
+ QuicStreamFrame data1(id1, false, 0, QuicStringPiece(type1, 1));
+ session_.OnStreamFrame(data1);
+ QuicStreamId id2 =
+ GetNthServerInitiatedUnidirectionalStreamId(transport_version(), 1);
+ QuicStreamFrame data2(id2, false, 0, QuicStringPiece(type1, 1));
+ EXPECT_CALL(*connection_,
+ CloseConnection(QUIC_INVALID_STREAM_ID,
+ "Control stream is received twice.", _));
+ EXPECT_QUIC_PEER_BUG(
+ session_.OnStreamFrame(data2),
+ "Received a duplicate Control stream: Closing connection.");
+
+ QuicStreamId id3 =
+ GetNthServerInitiatedUnidirectionalStreamId(transport_version(), 2);
+ char type2[]{kQpackEncoderStream};
+
+ QuicStreamFrame data3(id3, false, 0, QuicStringPiece(type2, 1));
+ session_.OnStreamFrame(data3);
+
+ QuicStreamId id4 =
+ GetNthServerInitiatedUnidirectionalStreamId(transport_version(), 3);
+ QuicStreamFrame data4(id4, false, 0, QuicStringPiece(type2, 1));
+ EXPECT_CALL(*connection_,
+ CloseConnection(QUIC_INVALID_STREAM_ID,
+ "QPACK encoder stream is received twice.", _));
+ EXPECT_QUIC_PEER_BUG(
+ session_.OnStreamFrame(data4),
+ "Received a duplicate QPACK encoder stream: Closing connection.");
+
+ QuicStreamId id5 =
+ GetNthServerInitiatedUnidirectionalStreamId(transport_version(), 4);
+ char type3[]{kQpackDecoderStream};
+
+ QuicStreamFrame data5(id5, false, 0, QuicStringPiece(type3, 1));
+ session_.OnStreamFrame(data5);
+
+ QuicStreamId id6 =
+ GetNthServerInitiatedUnidirectionalStreamId(transport_version(), 5);
+ QuicStreamFrame data6(id6, false, 0, QuicStringPiece(type3, 1));
+ EXPECT_CALL(*connection_,
+ CloseConnection(QUIC_INVALID_STREAM_ID,
+ "QPACK decoder stream is received twice.", _));
+ EXPECT_QUIC_PEER_BUG(
+ session_.OnStreamFrame(data6),
+ "Received a duplicate QPACK decoder stream: Closing connection.");
+}
+
} // namespace
} // namespace test
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.cc
index 97991e8b42b..28bcdcfc4b9 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
@@ -47,7 +47,7 @@ class QuicSpdyStream::HttpDecoderVisitor : public HttpDecoder::Visitor {
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
}
- bool OnPriorityFrameStart(Http3FrameLengths /*frame_lengths*/) override {
+ bool OnPriorityFrameStart(QuicByteCount /*header_length*/) override {
CloseConnectionOnWrongFrame("Priority");
return false;
}
@@ -72,7 +72,7 @@ class QuicSpdyStream::HttpDecoderVisitor : public HttpDecoder::Visitor {
return false;
}
- bool OnSettingsFrameStart(Http3FrameLengths /*frame_lengths*/) override {
+ bool OnSettingsFrameStart(QuicByteCount /*header_length*/) override {
CloseConnectionOnWrongFrame("Settings");
return false;
}
@@ -88,8 +88,8 @@ class QuicSpdyStream::HttpDecoderVisitor : public HttpDecoder::Visitor {
return false;
}
- bool OnDataFrameStart(Http3FrameLengths frame_lengths) override {
- return stream_->OnDataFrameStart(frame_lengths);
+ bool OnDataFrameStart(QuicByteCount header_length) override {
+ return stream_->OnDataFrameStart(header_length);
}
bool OnDataFramePayload(QuicStringPiece payload) override {
@@ -99,12 +99,12 @@ class QuicSpdyStream::HttpDecoderVisitor : public HttpDecoder::Visitor {
bool OnDataFrameEnd() override { return stream_->OnDataFrameEnd(); }
- bool OnHeadersFrameStart(Http3FrameLengths frame_length) override {
+ bool OnHeadersFrameStart(QuicByteCount header_length) override {
if (!VersionUsesQpack(stream_->transport_version())) {
CloseConnectionOnWrongFrame("Headers");
return false;
}
- return stream_->OnHeadersFrameStart(frame_length);
+ return stream_->OnHeadersFrameStart(header_length);
}
bool OnHeadersFramePayload(QuicStringPiece payload) override {
@@ -124,42 +124,50 @@ class QuicSpdyStream::HttpDecoderVisitor : public HttpDecoder::Visitor {
return stream_->OnHeadersFrameEnd();
}
- bool OnPushPromiseFrameStart(PushId /*push_id*/,
- Http3FrameLengths /*frame_length*/) override {
- // TODO(b/137554973): Consume frame header.
- CloseConnectionOnWrongFrame("Push Promise");
- return false;
+ bool OnPushPromiseFrameStart(PushId push_id,
+ QuicByteCount header_length,
+ QuicByteCount push_id_length) override {
+ if (!VersionHasStreamType(stream_->transport_version())) {
+ CloseConnectionOnWrongFrame("Push Promise");
+ return false;
+ }
+ return stream_->OnPushPromiseFrameStart(push_id, header_length,
+ push_id_length);
}
bool OnPushPromiseFramePayload(QuicStringPiece payload) override {
- // TODO(b/137554973): Consume frame payload.
DCHECK(!payload.empty());
- CloseConnectionOnWrongFrame("Push Promise");
- return false;
+ if (!VersionUsesQpack(stream_->transport_version())) {
+ CloseConnectionOnWrongFrame("Push Promise");
+ return false;
+ }
+ return stream_->OnPushPromiseFramePayload(payload);
}
bool OnPushPromiseFrameEnd() override {
- CloseConnectionOnWrongFrame("Push Promise");
- return false;
+ if (!VersionUsesQpack(stream_->transport_version())) {
+ CloseConnectionOnWrongFrame("Push Promise");
+ return false;
+ }
+ return stream_->OnPushPromiseFrameEnd();
}
- bool OnUnknownFrameStart(uint64_t /* frame_type */,
- Http3FrameLengths /* frame_length */) override {
- // TODO(b/137554973): Consume frame header.
- return true;
+ bool OnUnknownFrameStart(uint64_t frame_type,
+ QuicByteCount header_length) override {
+ return stream_->OnUnknownFrameStart(frame_type, header_length);
}
- bool OnUnknownFramePayload(QuicStringPiece /* payload */) override {
- // TODO(b/137554973): Consume frame payload.
- return true;
+ bool OnUnknownFramePayload(QuicStringPiece payload) override {
+ return stream_->OnUnknownFramePayload(payload);
}
- bool OnUnknownFrameEnd() override { return true; }
+ bool OnUnknownFrameEnd() override { return stream_->OnUnknownFrameEnd(); }
private:
- void CloseConnectionOnWrongFrame(std::string frame_type) {
+ void CloseConnectionOnWrongFrame(QuicStringPiece frame_type) {
stream_->session()->connection()->CloseConnection(
- QUIC_HTTP_DECODER_ERROR, frame_type + " frame received on data stream",
+ QUIC_HTTP_DECODER_ERROR,
+ QuicStrCat(frame_type, " frame received on data stream"),
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
}
@@ -185,7 +193,6 @@ QuicSpdyStream::QuicSpdyStream(QuicStreamId id,
trailers_decompressed_(false),
trailers_consumed_(false),
priority_sent_(false),
- headers_bytes_to_be_marked_consumed_(0),
http_decoder_visitor_(QuicMakeUnique<HttpDecoderVisitor>(this)),
decoder_(http_decoder_visitor_.get()),
sequencer_offset_(0),
@@ -221,7 +228,6 @@ QuicSpdyStream::QuicSpdyStream(PendingStream* pending,
trailers_decompressed_(false),
trailers_consumed_(false),
priority_sent_(false),
- headers_bytes_to_be_marked_consumed_(0),
http_decoder_visitor_(QuicMakeUnique<HttpDecoderVisitor>(this)),
decoder_(http_decoder_visitor_.get()),
sequencer_offset_(sequencer()->NumBytesConsumed()),
@@ -344,6 +350,35 @@ size_t QuicSpdyStream::WriteTrailers(
return bytes_written;
}
+void QuicSpdyStream::WritePushPromise(const PushPromiseFrame& frame) {
+ DCHECK(VersionUsesQpack(transport_version()));
+ std::unique_ptr<char[]> push_promise_frame_with_id;
+ const size_t push_promise_frame_length =
+ encoder_.SerializePushPromiseFrameWithOnlyPushId(
+ frame, &push_promise_frame_with_id);
+
+ unacked_frame_headers_offsets_.Add(send_buffer().stream_offset(),
+ send_buffer().stream_offset() +
+ push_promise_frame_length +
+ frame.headers.length());
+
+ // Write Push Promise frame header and push id.
+ QUIC_DLOG(INFO) << "Stream " << id()
+ << " is writing Push Promise frame header of length "
+ << push_promise_frame_length << " , with promised id "
+ << frame.push_id;
+ WriteOrBufferData(QuicStringPiece(push_promise_frame_with_id.get(),
+ push_promise_frame_length),
+ /* fin = */ false, /* ack_listener = */ nullptr);
+
+ // Write response headers.
+ QUIC_DLOG(INFO) << "Stream " << id()
+ << " is writing Push Promise request header of length "
+ << frame.headers.length();
+ WriteOrBufferData(frame.headers, /* fin = */ false,
+ /* ack_listener = */ nullptr);
+}
+
QuicConsumedData QuicSpdyStream::WritevBody(const struct iovec* iov,
int count,
bool fin) {
@@ -396,13 +431,7 @@ size_t QuicSpdyStream::Readv(const struct iovec* iov, size_t iov_len) {
return sequencer()->Readv(iov, iov_len);
}
size_t bytes_read = 0;
- sequencer()->MarkConsumed(body_buffer_.ReadBody(iov, iov_len, &bytes_read));
-
- if (VersionUsesQpack(transport_version())) {
- // Maybe all DATA frame bytes have been read and some trailing HEADERS had
- // already been processed, in which case MarkConsumed() should be called.
- MaybeMarkHeadersBytesConsumed();
- }
+ sequencer()->MarkConsumed(body_manager_.ReadBody(iov, iov_len, &bytes_read));
return bytes_read;
}
@@ -412,7 +441,7 @@ int QuicSpdyStream::GetReadableRegions(iovec* iov, size_t iov_len) const {
if (!VersionHasDataFrameHeader(transport_version())) {
return sequencer()->GetReadableRegions(iov, iov_len);
}
- return body_buffer_.PeekBody(iov, iov_len);
+ return body_manager_.PeekBody(iov, iov_len);
}
void QuicSpdyStream::MarkConsumed(size_t num_bytes) {
@@ -421,13 +450,8 @@ void QuicSpdyStream::MarkConsumed(size_t num_bytes) {
sequencer()->MarkConsumed(num_bytes);
return;
}
- sequencer()->MarkConsumed(body_buffer_.OnBodyConsumed(num_bytes));
- if (VersionUsesQpack(transport_version())) {
- // Maybe all DATA frame bytes have been read and some trailing HEADERS had
- // already been processed, in which case MarkConsumed() should be called.
- MaybeMarkHeadersBytesConsumed();
- }
+ sequencer()->MarkConsumed(body_manager_.OnBodyConsumed(num_bytes));
}
bool QuicSpdyStream::IsDoneReading() const {
@@ -441,7 +465,7 @@ bool QuicSpdyStream::HasBytesToRead() const {
if (!VersionHasDataFrameHeader(transport_version())) {
return sequencer()->HasBytesToRead();
}
- return body_buffer_.HasBytesToRead();
+ return body_manager_.HasBytesToRead();
}
void QuicSpdyStream::MarkTrailersConsumed() {
@@ -450,7 +474,7 @@ void QuicSpdyStream::MarkTrailersConsumed() {
uint64_t QuicSpdyStream::total_body_bytes_read() const {
if (VersionHasDataFrameHeader(transport_version())) {
- return body_buffer_.total_body_bytes_received();
+ return body_manager_.total_body_bytes_received();
}
return sequencer()->NumBytesConsumed();
}
@@ -467,7 +491,7 @@ void QuicSpdyStream::ConsumeHeaderList() {
return;
}
- if (body_buffer_.HasBytesToRead()) {
+ if (body_manager_.HasBytesToRead()) {
OnBodyAvailable();
return;
}
@@ -479,9 +503,10 @@ void QuicSpdyStream::ConsumeHeaderList() {
}
}
-void QuicSpdyStream::OnStreamHeadersPriority(SpdyPriority priority) {
+void QuicSpdyStream::OnStreamHeadersPriority(
+ const spdy::SpdyStreamPrecedence& precedence) {
DCHECK_EQ(Perspective::IS_SERVER, session()->connection()->perspective());
- SetPriority(priority);
+ SetPriority(precedence);
}
void QuicSpdyStream::OnStreamHeaderList(bool fin,
@@ -555,14 +580,9 @@ void QuicSpdyStream::OnInitialHeadersComplete(
return;
}
- if (fin) {
- if (rst_sent() &&
- GetQuicReloadableFlag(quic_avoid_empty_frame_after_empty_headers)) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_avoid_empty_frame_after_empty_headers);
- } else {
- OnStreamFrame(
- QuicStreamFrame(id(), fin, /* offset = */ 0, QuicStringPiece()));
- }
+ if (fin && !rst_sent()) {
+ OnStreamFrame(
+ QuicStreamFrame(id(), fin, /* offset = */ 0, QuicStringPiece()));
}
if (FinishedReadingHeaders()) {
sequencer()->SetUnblocked();
@@ -623,9 +643,10 @@ void QuicSpdyStream::OnTrailingHeadersComplete(
}
}
-void QuicSpdyStream::OnPriorityFrame(SpdyPriority priority) {
+void QuicSpdyStream::OnPriorityFrame(
+ const spdy::SpdyStreamPrecedence& precedence) {
DCHECK_EQ(Perspective::IS_SERVER, session()->connection()->perspective());
- SetPriority(priority);
+ SetPriority(precedence);
}
void QuicSpdyStream::OnStreamReset(const QuicRstStreamFrame& frame) {
@@ -684,7 +705,7 @@ void QuicSpdyStream::OnDataAvailable() {
return;
}
- if (body_buffer_.HasBytesToRead()) {
+ if (body_manager_.HasBytesToRead()) {
OnBodyAvailable();
return;
}
@@ -759,7 +780,7 @@ void QuicSpdyStream::ClearSession() {
spdy_session_ = nullptr;
}
-bool QuicSpdyStream::OnDataFrameStart(Http3FrameLengths frame_lengths) {
+bool QuicSpdyStream::OnDataFrameStart(QuicByteCount header_length) {
DCHECK(VersionHasDataFrameHeader(transport_version()));
if (!headers_decompressed_ || trailers_decompressed_) {
// TODO(b/124216424): Change error code to HTTP_UNEXPECTED_FRAME.
@@ -769,21 +790,23 @@ bool QuicSpdyStream::OnDataFrameStart(Http3FrameLengths frame_lengths) {
return false;
}
- body_buffer_.OnDataHeader(frame_lengths);
+ sequencer()->MarkConsumed(body_manager_.OnNonBody(header_length));
+
return true;
}
bool QuicSpdyStream::OnDataFramePayload(QuicStringPiece payload) {
DCHECK(VersionHasDataFrameHeader(transport_version()));
- body_buffer_.OnDataPayload(payload);
+ body_manager_.OnBody(payload);
+
return true;
}
bool QuicSpdyStream::OnDataFrameEnd() {
DCHECK(VersionHasDataFrameHeader(transport_version()));
QUIC_DVLOG(1) << "Reaches the end of a data frame. Total bytes received are "
- << body_buffer_.total_body_bytes_received();
+ << body_manager_.total_body_bytes_received();
return true;
}
@@ -822,16 +845,6 @@ void QuicSpdyStream::OnStreamFrameRetransmitted(QuicStreamOffset offset,
}
}
-void QuicSpdyStream::MaybeMarkHeadersBytesConsumed() {
- DCHECK(VersionUsesQpack(transport_version()));
-
- if (!body_buffer_.HasBytesToRead() && !reading_stopped() &&
- headers_bytes_to_be_marked_consumed_ > 0) {
- sequencer()->MarkConsumed(headers_bytes_to_be_marked_consumed_);
- headers_bytes_to_be_marked_consumed_ = 0;
- }
-}
-
QuicByteCount QuicSpdyStream::GetNumFrameHeadersInInterval(
QuicStreamOffset offset,
QuicByteCount data_length) const {
@@ -844,7 +857,7 @@ QuicByteCount QuicSpdyStream::GetNumFrameHeadersInInterval(
return header_acked_length;
}
-bool QuicSpdyStream::OnHeadersFrameStart(Http3FrameLengths frame_length) {
+bool QuicSpdyStream::OnHeadersFrameStart(QuicByteCount header_length) {
DCHECK(VersionUsesQpack(transport_version()));
DCHECK(!qpack_decoded_headers_accumulator_);
@@ -857,31 +870,28 @@ bool QuicSpdyStream::OnHeadersFrameStart(Http3FrameLengths frame_length) {
return false;
}
- if (headers_decompressed_) {
- trailers_payload_length_ = frame_length.payload_length;
- } else {
- headers_payload_length_ = frame_length.payload_length;
- }
+ sequencer()->MarkConsumed(body_manager_.OnNonBody(header_length));
qpack_decoded_headers_accumulator_ =
QuicMakeUnique<QpackDecodedHeadersAccumulator>(
id(), spdy_session_->qpack_decoder(), this,
spdy_session_->max_inbound_header_list_size());
- // Do not call MaybeMarkHeadersBytesConsumed() yet, because
- // HEADERS frame header bytes might not have been parsed completely.
- headers_bytes_to_be_marked_consumed_ += frame_length.header_length;
-
return true;
}
bool QuicSpdyStream::OnHeadersFramePayload(QuicStringPiece payload) {
DCHECK(VersionUsesQpack(transport_version()));
+ if (headers_decompressed_) {
+ trailers_payload_length_ += payload.length();
+ } else {
+ headers_payload_length_ += payload.length();
+ }
+
const bool success = qpack_decoded_headers_accumulator_->Decode(payload);
- headers_bytes_to_be_marked_consumed_ += payload.size();
- MaybeMarkHeadersBytesConsumed();
+ sequencer()->MarkConsumed(body_manager_.OnNonBody(payload.size()));
if (!success) {
// TODO(124216424): Use HTTP_QPACK_DECOMPRESSION_FAILED error code.
@@ -919,11 +929,69 @@ bool QuicSpdyStream::OnHeadersFrameEnd() {
return !sequencer()->IsClosed() && !reading_stopped();
}
+bool QuicSpdyStream::OnPushPromiseFrameStart(PushId push_id,
+ QuicByteCount header_length,
+ QuicByteCount push_id_length) {
+ DCHECK(VersionHasStreamType(transport_version()));
+ DCHECK(!qpack_decoded_headers_accumulator_);
+
+ // TODO(renjietang): Check max push id and handle errors.
+ spdy_session_->OnPushPromise(id(), push_id);
+ sequencer()->MarkConsumed(
+ body_manager_.OnNonBody(header_length + push_id_length));
+
+ qpack_decoded_headers_accumulator_ =
+ QuicMakeUnique<QpackDecodedHeadersAccumulator>(
+ id(), spdy_session_->qpack_decoder(), this,
+ spdy_session_->max_inbound_header_list_size());
+
+ return true;
+}
+
+bool QuicSpdyStream::OnPushPromiseFramePayload(QuicStringPiece payload) {
+ spdy_session_->OnCompressedFrameSize(payload.length());
+ return OnHeadersFramePayload(payload);
+}
+
+bool QuicSpdyStream::OnPushPromiseFrameEnd() {
+ DCHECK(VersionUsesQpack(transport_version()));
+
+ return OnHeadersFrameEnd();
+}
+
+bool QuicSpdyStream::OnUnknownFrameStart(uint64_t frame_type,
+ QuicByteCount header_length) {
+ // Ignore unknown frames, but consume frame header.
+ QUIC_DVLOG(1) << "Discarding " << header_length
+ << " byte long frame header of frame of unknown type "
+ << frame_type << ".";
+ sequencer()->MarkConsumed(body_manager_.OnNonBody(header_length));
+ return true;
+}
+
+bool QuicSpdyStream::OnUnknownFramePayload(QuicStringPiece payload) {
+ // Ignore unknown frames, but consume frame payload.
+ QUIC_DVLOG(1) << "Discarding " << payload.size()
+ << " bytes of payload of frame of unknown type.";
+ sequencer()->MarkConsumed(body_manager_.OnNonBody(payload.size()));
+ return true;
+}
+
+bool QuicSpdyStream::OnUnknownFrameEnd() {
+ return true;
+}
+
void QuicSpdyStream::ProcessDecodedHeaders(const QuicHeaderList& headers) {
- const QuicByteCount frame_length = headers_decompressed_
- ? trailers_payload_length_
- : headers_payload_length_;
- OnStreamHeaderList(/* fin = */ false, frame_length, headers);
+ if (spdy_session_->promised_stream_id() ==
+ QuicUtils::GetInvalidStreamId(
+ session()->connection()->transport_version())) {
+ const QuicByteCount frame_length = headers_decompressed_
+ ? trailers_payload_length_
+ : headers_payload_length_;
+ OnStreamHeaderList(/* fin = */ false, frame_length, headers);
+ } else {
+ spdy_session_->OnHeaderList(headers);
+ }
qpack_decoded_headers_accumulator_.reset();
}
@@ -933,7 +1001,7 @@ size_t QuicSpdyStream::WriteHeadersImpl(
QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) {
if (!VersionUsesQpack(transport_version())) {
return spdy_session_->WriteHeadersOnHeadersStream(
- id(), std::move(header_block), fin, priority(),
+ id(), std::move(header_block), fin, precedence(),
std::move(ack_listener));
}
@@ -946,7 +1014,7 @@ size_t QuicSpdyStream::WriteHeadersImpl(
// Encode header list.
std::string encoded_headers =
- spdy_session_->qpack_encoder()->EncodeHeaderList(id(), &header_block);
+ spdy_session_->qpack_encoder()->EncodeHeaderList(id(), header_block);
// Write HEADERS frame.
std::unique_ptr<char[]> headers_frame_header;
@@ -973,7 +1041,7 @@ size_t QuicSpdyStream::WriteHeadersImpl(
}
void QuicSpdyStream::PopulatePriorityFrame(PriorityFrame* frame) {
- frame->weight = priority();
+ frame->weight = precedence().spdy3_priority();
frame->dependency_type = ROOT_OF_TREE;
frame->prioritized_type = REQUEST_STREAM;
frame->prioritized_element_id = id();
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 bdb87529d1c..42f76bb4e49 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
@@ -18,7 +18,7 @@
#include "net/third_party/quiche/src/quic/core/http/http_decoder.h"
#include "net/third_party/quiche/src/quic/core/http/http_encoder.h"
#include "net/third_party/quiche/src/quic/core/http/quic_header_list.h"
-#include "net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_buffer.h"
+#include "net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_manager.h"
#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator.h"
#include "net/third_party/quiche/src/quic/core/quic_packets.h"
#include "net/third_party/quiche/src/quic/core/quic_stream.h"
@@ -78,7 +78,8 @@ class QUIC_EXPORT_PRIVATE QuicSpdyStream
// Called by the session when headers with a priority have been received
// for this stream. This method will only be called for server streams.
- virtual void OnStreamHeadersPriority(spdy::SpdyPriority priority);
+ virtual void OnStreamHeadersPriority(
+ const spdy::SpdyStreamPrecedence& precedence);
// Called by the session when decompressed headers have been completely
// delivered to this stream. If |fin| is true, then this stream
@@ -95,7 +96,7 @@ class QUIC_EXPORT_PRIVATE QuicSpdyStream
// Called by the session when a PRIORITY frame has been been received for this
// stream. This method will only be called for server streams.
- void OnPriorityFrame(spdy::SpdyPriority priority);
+ void OnPriorityFrame(const spdy::SpdyStreamPrecedence& precedence);
// Override the base class to not discard response when receiving
// QUIC_STREAM_NO_ERROR.
@@ -125,6 +126,9 @@ class QUIC_EXPORT_PRIVATE QuicSpdyStream
spdy::SpdyHeaderBlock trailer_block,
QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener);
+ // Serializes |frame| and writes the encoded push promise data.
+ void WritePushPromise(const PushPromiseFrame& frame);
+
// Override to report newly acked bytes via ack_listener_.
bool OnStreamFrameAcked(QuicStreamOffset offset,
QuicByteCount data_length,
@@ -139,12 +143,10 @@ class QUIC_EXPORT_PRIVATE QuicSpdyStream
// Does the same thing as WriteOrBufferBody except this method takes iovec
// as the data input. Right now it only calls WritevData.
- // TODO(renjietang): Write data frame header before writing body.
QuicConsumedData WritevBody(const struct iovec* iov, int count, bool fin);
// Does the same thing as WriteOrBufferBody except this method takes
// memslicespan as the data input. Right now it only calls WriteMemSlices.
- // TODO(renjietang): Write data frame header before writing body.
QuicConsumedData WriteBodySlices(QuicMemSliceSpan slices, bool fin);
// Marks the trailers as consumed. This applies to the case where this object
@@ -248,20 +250,24 @@ class QUIC_EXPORT_PRIVATE QuicSpdyStream
class HttpDecoderVisitor;
// Called by HttpDecoderVisitor.
- bool OnDataFrameStart(Http3FrameLengths frame_lengths);
+ bool OnDataFrameStart(QuicByteCount header_length);
bool OnDataFramePayload(QuicStringPiece payload);
bool OnDataFrameEnd();
- bool OnHeadersFrameStart(Http3FrameLengths frame_length);
+ bool OnHeadersFrameStart(QuicByteCount header_length);
bool OnHeadersFramePayload(QuicStringPiece payload);
bool OnHeadersFrameEnd();
+ bool OnPushPromiseFrameStart(PushId push_id,
+ QuicByteCount header_length,
+ QuicByteCount push_id_length);
+ bool OnPushPromiseFramePayload(QuicStringPiece payload);
+ bool OnPushPromiseFrameEnd();
+ bool OnUnknownFrameStart(uint64_t frame_type, QuicByteCount header_length);
+ bool OnUnknownFramePayload(QuicStringPiece payload);
+ bool OnUnknownFrameEnd();
// Called internally when headers are decoded.
void ProcessDecodedHeaders(const QuicHeaderList& headers);
- // Call QuicStreamSequencer::MarkConsumed() with
- // |headers_bytes_to_be_marked_consumed_| if appropriate.
- void MaybeMarkHeadersBytesConsumed();
-
// Given the interval marked by [|offset|, |offset| + |data_length|), return
// the number of frame header bytes contained in it.
QuicByteCount GetNumFrameHeadersInInterval(QuicStreamOffset offset,
@@ -294,9 +300,6 @@ class QUIC_EXPORT_PRIVATE QuicSpdyStream
// True if the stream has already sent an priority frame.
bool priority_sent_;
- // Number of bytes consumed while decoding HEADERS frames that cannot be
- // marked consumed in QuicStreamSequencer until later.
- QuicByteCount headers_bytes_to_be_marked_consumed_;
// The parsed trailers received from the peer.
spdy::SpdyHeaderBlock received_trailers_;
@@ -309,8 +312,10 @@ class QUIC_EXPORT_PRIVATE QuicSpdyStream
std::unique_ptr<HttpDecoderVisitor> http_decoder_visitor_;
// HttpDecoder for processing raw incoming stream frames.
HttpDecoder decoder_;
- // Buffer that contains decoded data of the stream.
- QuicSpdyStreamBodyBuffer body_buffer_;
+ // Object that manages references to DATA frame payload fragments buffered by
+ // the sequencer and calculates how much data should be marked consumed with
+ // the sequencer each time new stream data is processed.
+ QuicSpdyStreamBodyManager body_manager_;
// Sequencer offset keeping track of how much data HttpDecoder has processed.
// Initial value is zero for fresh streams, or sequencer()->NumBytesConsumed()
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_buffer.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_buffer.cc
deleted file mode 100644
index c29c766ad59..00000000000
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_buffer.cc
+++ /dev/null
@@ -1,132 +0,0 @@
-// Copyright (c) 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_buffer.h"
-
-#include <algorithm>
-
-#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
-
-namespace quic {
-
-QuicSpdyStreamBodyBuffer::QuicSpdyStreamBodyBuffer()
- : bytes_remaining_(0),
- total_body_bytes_readable_(0),
- total_body_bytes_received_(0),
- total_payload_lengths_(0) {}
-
-void QuicSpdyStreamBodyBuffer::OnDataHeader(Http3FrameLengths frame_lengths) {
- frame_meta_.push_back(frame_lengths);
- total_payload_lengths_ += frame_lengths.payload_length;
-}
-
-void QuicSpdyStreamBodyBuffer::OnDataPayload(QuicStringPiece payload) {
- DCHECK(!payload.empty());
- bodies_.push_back(payload);
- total_body_bytes_received_ += payload.length();
- total_body_bytes_readable_ += payload.length();
- DCHECK_LE(total_body_bytes_received_, total_payload_lengths_);
-}
-
-size_t QuicSpdyStreamBodyBuffer::OnBodyConsumed(size_t num_bytes) {
- // Check if the stream has enough decoded data.
- if (num_bytes > total_body_bytes_readable_) {
- QUIC_BUG << "Invalid argument to OnBodyConsumed."
- << " expect to consume: " << num_bytes
- << ", but not enough bytes available. "
- << "Total bytes readable are: " << total_body_bytes_readable_;
- return 0;
- }
- // Discard references in the stream before the sequencer marks them consumed.
- size_t remaining = num_bytes;
- while (remaining > 0) {
- if (bodies_.empty()) {
- QUIC_BUG << "Failed to consume because body buffer is empty.";
- return 0;
- }
- auto body = bodies_.front();
- bodies_.pop_front();
- if (body.length() <= remaining) {
- remaining -= body.length();
- } else {
- body = body.substr(remaining, body.length() - remaining);
- bodies_.push_front(body);
- remaining = 0;
- }
- }
-
- // Consume headers.
- size_t bytes_to_consume = 0;
- while (bytes_remaining_ < num_bytes) {
- if (frame_meta_.empty()) {
- QUIC_BUG << "Faild to consume because frame header buffer is empty.";
- return 0;
- }
- auto meta = frame_meta_.front();
- frame_meta_.pop_front();
- bytes_remaining_ += meta.payload_length;
- bytes_to_consume += meta.header_length;
- }
- bytes_to_consume += num_bytes;
-
- // Update accountings.
- bytes_remaining_ -= num_bytes;
- total_body_bytes_readable_ -= num_bytes;
-
- return bytes_to_consume;
-}
-
-int QuicSpdyStreamBodyBuffer::PeekBody(iovec* iov, size_t iov_len) const {
- DCHECK(iov != nullptr);
- DCHECK_GT(iov_len, 0u);
-
- if (bodies_.empty()) {
- iov[0].iov_base = nullptr;
- iov[0].iov_len = 0;
- return 0;
- }
- // Fill iovs with references from the stream.
- size_t iov_filled = 0;
- while (iov_filled < bodies_.size() && iov_filled < iov_len) {
- QuicStringPiece body = bodies_[iov_filled];
- iov[iov_filled].iov_base = const_cast<char*>(body.data());
- iov[iov_filled].iov_len = body.size();
- iov_filled++;
- }
- return iov_filled;
-}
-
-size_t QuicSpdyStreamBodyBuffer::ReadBody(const struct iovec* iov,
- size_t iov_len,
- size_t* total_bytes_read) {
- *total_bytes_read = 0;
- QuicByteCount total_remaining = total_body_bytes_readable_;
- size_t index = 0;
- size_t src_offset = 0;
- for (size_t i = 0; i < iov_len && total_remaining > 0; ++i) {
- char* dest = reinterpret_cast<char*>(iov[i].iov_base);
- size_t dest_remaining = iov[i].iov_len;
- while (dest_remaining > 0 && total_remaining > 0) {
- auto body = bodies_[index];
- size_t bytes_to_copy =
- std::min<size_t>(body.length() - src_offset, dest_remaining);
- memcpy(dest, body.substr(src_offset, bytes_to_copy).data(),
- bytes_to_copy);
- dest += bytes_to_copy;
- dest_remaining -= bytes_to_copy;
- *total_bytes_read += bytes_to_copy;
- total_remaining -= bytes_to_copy;
- if (bytes_to_copy < body.length() - src_offset) {
- src_offset += bytes_to_copy;
- } else {
- index++;
- src_offset = 0;
- }
- }
- }
-
- return OnBodyConsumed(*total_bytes_read);
-}
-
-} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_buffer.h b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_buffer.h
deleted file mode 100644
index a37f3bf0b80..00000000000
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_buffer.h
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright (c) 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef QUICHE_QUIC_CORE_HTTP_QUIC_SPDY_STREAM_BODY_BUFFER_H_
-#define QUICHE_QUIC_CORE_HTTP_QUIC_SPDY_STREAM_BODY_BUFFER_H_
-
-#include "net/third_party/quiche/src/quic/core/http/http_decoder.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_iovec.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_macros.h"
-
-namespace quic {
-
-class QuicStreamSequencer;
-
-// Buffer decoded body for QuicSpdyStream. It also talks to the sequencer to
-// consume data.
-class QUIC_EXPORT_PRIVATE QuicSpdyStreamBodyBuffer {
- public:
- QuicSpdyStreamBodyBuffer();
- ~QuicSpdyStreamBodyBuffer() = default;
-
- // Add metadata of the frame to accountings.
- // Called when QuicSpdyStream receives data frame header.
- void OnDataHeader(Http3FrameLengths frame_lengths);
-
- // Add new data payload to buffer.
- // Called when QuicSpdyStream received data payload.
- // Data pointed by payload must be alive until consumed by
- // QuicStreamSequencer::MarkConsumed().
- void OnDataPayload(QuicStringPiece payload);
-
- // Internally marks |num_bytes| of DATA frame payload consumed, and returns
- // the number of bytes that the caller should mark consumed with the
- // sequencer, including DATA frame header bytes, if any.
- QUIC_MUST_USE_RESULT size_t OnBodyConsumed(size_t num_bytes);
-
- // Fill up to |iov_len| with bodies available in buffer. No data is consumed.
- // |iov|.iov_base will point to data in the buffer, and |iov|.iov_len will
- // be set to the underlying data length accordingly.
- // Returns the number of iov used.
- int PeekBody(iovec* iov, size_t iov_len) const;
-
- // Copies from buffer into |iov| up to |iov_len|, and consume data in
- // sequencer. |iov.iov_base| and |iov.iov_len| are preassigned and will not be
- // changed. |*total_bytes_read| is set to the number of bytes read. Returns
- // the number of bytes that should be marked consumed with the sequencer.
- QUIC_MUST_USE_RESULT size_t ReadBody(const struct iovec* iov,
- size_t iov_len,
- size_t* total_bytes_read);
-
- bool HasBytesToRead() const { return !bodies_.empty(); }
-
- uint64_t total_body_bytes_received() const {
- return total_body_bytes_received_;
- }
-
- private:
- // Storage for decoded data.
- QuicDeque<QuicStringPiece> bodies_;
- // Storage for header lengths.
- QuicDeque<Http3FrameLengths> frame_meta_;
- // Bytes in the first available data frame that are not consumed yet.
- QuicByteCount bytes_remaining_;
- // Total available body data in the stream.
- QuicByteCount total_body_bytes_readable_;
- // Total bytes read from the stream excluding headers.
- QuicByteCount total_body_bytes_received_;
- // Total length of payloads tracked by frame_meta_.
- QuicByteCount total_payload_lengths_;
-};
-
-} // namespace quic
-
-#endif // QUICHE_QUIC_CORE_HTTP_QUIC_SPDY_STREAM_BODY_BUFFER_H_
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_buffer_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_buffer_test.cc
deleted file mode 100644
index d5e816119d9..00000000000
--- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_buffer_test.cc
+++ /dev/null
@@ -1,163 +0,0 @@
-// Copyright (c) 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_buffer.h"
-
-#include <string>
-
-#include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
-
-namespace quic {
-
-namespace test {
-
-namespace {
-
-class QuicSpdyStreamBodyBufferTest : public QuicTest {
- protected:
- QuicSpdyStreamBodyBuffer body_buffer_;
-};
-
-TEST_F(QuicSpdyStreamBodyBufferTest, ReceiveBodies) {
- std::string body(1024, 'a');
- EXPECT_FALSE(body_buffer_.HasBytesToRead());
- body_buffer_.OnDataHeader(Http3FrameLengths(3, 1024));
- body_buffer_.OnDataPayload(body);
- EXPECT_EQ(1024u, body_buffer_.total_body_bytes_received());
- EXPECT_TRUE(body_buffer_.HasBytesToRead());
-}
-
-TEST_F(QuicSpdyStreamBodyBufferTest, PeekBody) {
- std::string body(1024, 'a');
- body_buffer_.OnDataHeader(Http3FrameLengths(3, 1024));
- body_buffer_.OnDataPayload(body);
- EXPECT_EQ(1024u, body_buffer_.total_body_bytes_received());
- iovec vec;
- EXPECT_EQ(1, body_buffer_.PeekBody(&vec, 1));
- EXPECT_EQ(1024u, vec.iov_len);
- EXPECT_EQ(body,
- QuicStringPiece(static_cast<const char*>(vec.iov_base), 1024));
-}
-
-// Buffer only receives 1 frame. Stream consumes less or equal than a frame.
-TEST_F(QuicSpdyStreamBodyBufferTest, MarkConsumedPartialSingleFrame) {
- testing::InSequence seq;
- std::string body(1024, 'a');
- const QuicByteCount header_length = 3;
- Http3FrameLengths lengths(header_length, 1024);
- body_buffer_.OnDataHeader(lengths);
- body_buffer_.OnDataPayload(body);
- EXPECT_EQ(header_length + 1024, body_buffer_.OnBodyConsumed(1024));
-}
-
-// Buffer received 2 frames. Stream consumes multiple times.
-TEST_F(QuicSpdyStreamBodyBufferTest, MarkConsumedMultipleFrames) {
- testing::InSequence seq;
- // 1st frame.
- std::string body1(1024, 'a');
- const QuicByteCount header_length1 = 2;
- Http3FrameLengths lengths1(header_length1, 1024);
- body_buffer_.OnDataHeader(lengths1);
- body_buffer_.OnDataPayload(body1);
-
- // 2nd frame.
- std::string body2(2048, 'b');
- const QuicByteCount header_length2 = 4;
- Http3FrameLengths lengths2(header_length2, 2048);
- body_buffer_.OnDataHeader(lengths2);
- body_buffer_.OnDataPayload(body2);
-
- EXPECT_EQ(header_length1 + 512, body_buffer_.OnBodyConsumed(512));
- EXPECT_EQ(header_length2 + 2048, body_buffer_.OnBodyConsumed(2048));
- EXPECT_EQ(512u, body_buffer_.OnBodyConsumed(512));
-}
-
-TEST_F(QuicSpdyStreamBodyBufferTest, MarkConsumedMoreThanBuffered) {
- std::string body(1024, 'a');
- Http3FrameLengths lengths(3, 1024);
- body_buffer_.OnDataHeader(lengths);
- body_buffer_.OnDataPayload(body);
- size_t bytes_to_consume = 0;
- EXPECT_QUIC_BUG(
- bytes_to_consume = body_buffer_.OnBodyConsumed(2048),
- "Invalid argument to OnBodyConsumed. expect to consume: 2048, but not "
- "enough bytes available. Total bytes readable are: 1024");
- EXPECT_EQ(0u, bytes_to_consume);
-}
-
-// Buffer receives 1 frame. Stream read from the buffer.
-TEST_F(QuicSpdyStreamBodyBufferTest, ReadSingleBody) {
- testing::InSequence seq;
- std::string body(1024, 'a');
- const QuicByteCount header_length = 2;
- Http3FrameLengths lengths(header_length, 1024);
- body_buffer_.OnDataHeader(lengths);
- body_buffer_.OnDataPayload(body);
-
- char base[1024];
- iovec iov = {&base[0], 1024};
- size_t total_bytes_read = 0;
- EXPECT_EQ(header_length + 1024,
- body_buffer_.ReadBody(&iov, 1, &total_bytes_read));
- EXPECT_EQ(1024u, total_bytes_read);
- EXPECT_EQ(1024u, iov.iov_len);
- EXPECT_EQ(body,
- QuicStringPiece(static_cast<const char*>(iov.iov_base), 1024));
-}
-
-// Buffer receives 2 frames, stream read from the buffer multiple times.
-TEST_F(QuicSpdyStreamBodyBufferTest, ReadMultipleBody) {
- testing::InSequence seq;
- // 1st frame.
- std::string body1(1024, 'a');
- const QuicByteCount header_length1 = 2;
- Http3FrameLengths lengths1(header_length1, 1024);
- body_buffer_.OnDataHeader(lengths1);
- body_buffer_.OnDataPayload(body1);
-
- // 2nd frame.
- std::string body2(2048, 'b');
- const QuicByteCount header_length2 = 4;
- Http3FrameLengths lengths2(header_length2, 2048);
- body_buffer_.OnDataHeader(lengths2);
- body_buffer_.OnDataPayload(body2);
-
- // First read of 512 bytes.
- char base[512];
- iovec iov = {&base[0], 512};
- size_t total_bytes_read = 0;
- EXPECT_EQ(header_length1 + 512,
- body_buffer_.ReadBody(&iov, 1, &total_bytes_read));
- EXPECT_EQ(512u, total_bytes_read);
- EXPECT_EQ(512u, iov.iov_len);
- EXPECT_EQ(body1.substr(0, 512),
- QuicStringPiece(static_cast<const char*>(iov.iov_base), 512));
-
- // Second read of 2048 bytes.
- char base2[2048];
- iovec iov2 = {&base2[0], 2048};
- EXPECT_EQ(header_length2 + 2048,
- body_buffer_.ReadBody(&iov2, 1, &total_bytes_read));
- EXPECT_EQ(2048u, total_bytes_read);
- EXPECT_EQ(2048u, iov2.iov_len);
- EXPECT_EQ(body1.substr(512, 512) + body2.substr(0, 1536),
- QuicStringPiece(static_cast<const char*>(iov2.iov_base), 2048));
-
- // Third read of the rest 512 bytes.
- char base3[512];
- iovec iov3 = {&base3[0], 512};
- EXPECT_EQ(512u, body_buffer_.ReadBody(&iov3, 1, &total_bytes_read));
- EXPECT_EQ(512u, total_bytes_read);
- EXPECT_EQ(512u, iov3.iov_len);
- EXPECT_EQ(body2.substr(1536, 512),
- QuicStringPiece(static_cast<const char*>(iov3.iov_base), 512));
-}
-
-} // anonymous namespace
-
-} // namespace test
-
-} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_manager.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_manager.cc
new file mode 100644
index 00000000000..798f55142ca
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_manager.cc
@@ -0,0 +1,139 @@
+// Copyright (c) 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_manager.h"
+
+#include <algorithm>
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
+
+namespace quic {
+
+QuicSpdyStreamBodyManager::QuicSpdyStreamBodyManager()
+ : total_body_bytes_received_(0) {}
+
+size_t QuicSpdyStreamBodyManager::OnNonBody(QuicByteCount length) {
+ DCHECK_NE(0u, length);
+
+ if (fragments_.empty()) {
+ // Non-body bytes can be consumed immediately, because all previously
+ // received body bytes have been read.
+ return length;
+ }
+
+ // Non-body bytes will be consumed after last body fragment is read.
+ fragments_.back().trailing_non_body_byte_count += length;
+ return 0;
+}
+
+void QuicSpdyStreamBodyManager::OnBody(QuicStringPiece body) {
+ DCHECK(!body.empty());
+
+ fragments_.push_back({body, 0});
+ total_body_bytes_received_ += body.length();
+}
+
+size_t QuicSpdyStreamBodyManager::OnBodyConsumed(size_t num_bytes) {
+ QuicByteCount bytes_to_consume = 0;
+ size_t remaining_bytes = num_bytes;
+
+ while (remaining_bytes > 0) {
+ if (fragments_.empty()) {
+ QUIC_BUG << "Not enough available body to consume.";
+ return 0;
+ }
+
+ Fragment& fragment = fragments_.front();
+ const QuicStringPiece body = fragment.body;
+
+ if (body.length() > remaining_bytes) {
+ // Consume leading |remaining_bytes| bytes of body.
+ bytes_to_consume += remaining_bytes;
+ fragment.body = body.substr(remaining_bytes);
+ return bytes_to_consume;
+ }
+
+ // Consume entire fragment and the following
+ // |trailing_non_body_byte_count| bytes.
+ remaining_bytes -= body.length();
+ bytes_to_consume += body.length() + fragment.trailing_non_body_byte_count;
+ fragments_.pop_front();
+ }
+
+ return bytes_to_consume;
+}
+
+int QuicSpdyStreamBodyManager::PeekBody(iovec* iov, size_t iov_len) const {
+ DCHECK(iov);
+ DCHECK_GT(iov_len, 0u);
+
+ // TODO(bnc): Is this really necessary?
+ if (fragments_.empty()) {
+ iov[0].iov_base = nullptr;
+ iov[0].iov_len = 0;
+ return 0;
+ }
+
+ size_t iov_filled = 0;
+ while (iov_filled < fragments_.size() && iov_filled < iov_len) {
+ QuicStringPiece body = fragments_[iov_filled].body;
+ iov[iov_filled].iov_base = const_cast<char*>(body.data());
+ iov[iov_filled].iov_len = body.size();
+ iov_filled++;
+ }
+
+ return iov_filled;
+}
+
+size_t QuicSpdyStreamBodyManager::ReadBody(const struct iovec* iov,
+ size_t iov_len,
+ size_t* total_bytes_read) {
+ *total_bytes_read = 0;
+ QuicByteCount bytes_to_consume = 0;
+
+ // The index of iovec to write to.
+ size_t index = 0;
+ // Address to write to within current iovec.
+ char* dest = reinterpret_cast<char*>(iov[index].iov_base);
+ // Remaining space in current iovec.
+ size_t dest_remaining = iov[index].iov_len;
+
+ while (!fragments_.empty()) {
+ Fragment& fragment = fragments_.front();
+ const QuicStringPiece body = fragment.body;
+
+ const size_t bytes_to_copy =
+ std::min<size_t>(body.length(), dest_remaining);
+ memcpy(dest, body.data(), bytes_to_copy);
+ bytes_to_consume += bytes_to_copy;
+ *total_bytes_read += bytes_to_copy;
+
+ if (bytes_to_copy == body.length()) {
+ // Entire fragment read.
+ bytes_to_consume += fragment.trailing_non_body_byte_count;
+ fragments_.pop_front();
+ } else {
+ // Consume leading |bytes_to_copy| bytes of body.
+ fragment.body = body.substr(bytes_to_copy);
+ }
+
+ if (bytes_to_copy == dest_remaining) {
+ // Current iovec full.
+ ++index;
+ if (index == iov_len) {
+ break;
+ }
+ dest = reinterpret_cast<char*>(iov[index].iov_base);
+ dest_remaining = iov[index].iov_len;
+ } else {
+ // Advance destination parameters within this iovec.
+ dest += bytes_to_copy;
+ dest_remaining -= bytes_to_copy;
+ }
+ }
+
+ return bytes_to_consume;
+}
+
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_manager.h b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_manager.h
new file mode 100644
index 00000000000..6b2dd62b02d
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_manager.h
@@ -0,0 +1,94 @@
+// Copyright (c) 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_CORE_HTTP_QUIC_SPDY_STREAM_BODY_MANAGER_H_
+#define QUICHE_QUIC_CORE_HTTP_QUIC_SPDY_STREAM_BODY_MANAGER_H_
+
+#include "net/third_party/quiche/src/quic/core/quic_constants.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_iovec.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_macros.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
+
+namespace quic {
+
+// All data that a request stream receives falls into one of two categories:
+// * "body", that is, DATA frame payload, which the QuicStreamSequencer must
+// buffer until it is read;
+// * everything else, which QuicSpdyStream immediately processes and thus could
+// be marked as consumed with QuicStreamSequencer, unless there is some piece
+// of body received prior that still needs to be buffered.
+// QuicSpdyStreamBodyManager does two things: it keeps references to body
+// fragments (owned by QuicStreamSequencer) and offers methods to read them; and
+// it calculates the total number of bytes (including non-body bytes) the caller
+// needs to mark consumed (with QuicStreamSequencer) when non-body bytes are
+// received or when body is consumed.
+class QUIC_EXPORT_PRIVATE QuicSpdyStreamBodyManager {
+ public:
+ QuicSpdyStreamBodyManager();
+ ~QuicSpdyStreamBodyManager() = default;
+
+ // One of the following two methods must be called every time data is received
+ // on the request stream.
+
+ // Called when data that could immediately be marked consumed with the
+ // sequencer (provided that all previous body fragments are consumed) is
+ // received. |length| must be positive. Returns number of bytes the caller
+ // must mark consumed, which might be zero.
+ QUIC_MUST_USE_RESULT size_t OnNonBody(QuicByteCount length);
+
+ // Called when body is received. |body| is added to |fragments_|. The data
+ // pointed to by |body| must be kept alive until an OnBodyConsumed() or
+ // ReadBody() call consumes it. |body| must not be empty.
+ void OnBody(QuicStringPiece body);
+
+ // Internally marks |num_bytes| of body consumed. |num_bytes| might be zero.
+ // Returns the number of bytes that the caller should mark consumed with the
+ // sequencer, which is the sum of |num_bytes| for body, and the number of any
+ // interleaving or immediately trailing non-body bytes.
+ QUIC_MUST_USE_RESULT size_t OnBodyConsumed(size_t num_bytes);
+
+ // Set up to |iov_len| elements of iov[] to point to available bodies: each
+ // iov[i].iov_base will point to a body fragment, and iov[i].iov_len will be
+ // set to its length. No data is copied, no data is consumed. Returns the
+ // number of iov set.
+ int PeekBody(iovec* iov, size_t iov_len) const;
+
+ // Copies data from available bodies into at most |iov_len| elements of iov[].
+ // Internally consumes copied body bytes as well as all interleaving and
+ // immediately trailing non-body bytes. |iov.iov_base| and |iov.iov_len| are
+ // preassigned and will not be changed. Returns the total number of bytes the
+ // caller shall mark consumed. Sets |*total_bytes_read| to the total number
+ // of body bytes read.
+ QUIC_MUST_USE_RESULT size_t ReadBody(const struct iovec* iov,
+ size_t iov_len,
+ size_t* total_bytes_read);
+
+ bool HasBytesToRead() const { return !fragments_.empty(); }
+
+ uint64_t total_body_bytes_received() const {
+ return total_body_bytes_received_;
+ }
+
+ private:
+ // A Fragment instance represents a body fragment with a count of bytes
+ // received afterwards but before the next body fragment that can be marked
+ // consumed as soon as all of the body fragment is read.
+ struct Fragment {
+ // |body| must not be empty.
+ QuicStringPiece body;
+ // Might be zero.
+ QuicByteCount trailing_non_body_byte_count;
+ };
+ // Queue of body fragments and trailing non-body byte counts.
+ QuicDeque<Fragment> fragments_;
+ // Total body bytes received.
+ QuicByteCount total_body_bytes_received_;
+};
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_CORE_HTTP_QUIC_SPDY_STREAM_BODY_MANAGER_H_
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_manager_test.cc
new file mode 100644
index 00000000000..3a5b720d277
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_manager_test.cc
@@ -0,0 +1,282 @@
+// Copyright (c) 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_manager.h"
+
+#include <algorithm>
+#include <numeric>
+#include <string>
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+
+namespace quic {
+
+namespace test {
+
+namespace {
+
+class QuicSpdyStreamBodyManagerTest : public QuicTest {
+ protected:
+ QuicSpdyStreamBodyManager body_manager_;
+};
+
+TEST_F(QuicSpdyStreamBodyManagerTest, HasBytesToRead) {
+ EXPECT_FALSE(body_manager_.HasBytesToRead());
+ EXPECT_EQ(0u, body_manager_.total_body_bytes_received());
+
+ const QuicByteCount header_length = 3;
+ EXPECT_EQ(header_length, body_manager_.OnNonBody(header_length));
+
+ EXPECT_FALSE(body_manager_.HasBytesToRead());
+ EXPECT_EQ(0u, body_manager_.total_body_bytes_received());
+
+ std::string body(1024, 'a');
+ body_manager_.OnBody(body);
+
+ EXPECT_TRUE(body_manager_.HasBytesToRead());
+ EXPECT_EQ(1024u, body_manager_.total_body_bytes_received());
+}
+
+TEST_F(QuicSpdyStreamBodyManagerTest, ConsumeMoreThanAvailable) {
+ std::string body(1024, 'a');
+ body_manager_.OnBody(body);
+ size_t bytes_to_consume = 0;
+ EXPECT_QUIC_BUG(bytes_to_consume = body_manager_.OnBodyConsumed(2048),
+ "Not enough available body to consume.");
+ EXPECT_EQ(0u, bytes_to_consume);
+}
+
+struct {
+ std::vector<QuicByteCount> frame_header_lengths;
+ std::vector<const char*> frame_payloads;
+ std::vector<QuicByteCount> body_bytes_to_read;
+ std::vector<QuicByteCount> expected_return_values;
+} const kOnBodyConsumedTestData[] = {
+ // One frame consumed in one call.
+ {{2}, {"foobar"}, {6}, {6}},
+ // Two frames consumed in one call.
+ {{3, 5}, {"foobar", "baz"}, {9}, {14}},
+ // One frame consumed in two calls.
+ {{2}, {"foobar"}, {4, 2}, {4, 2}},
+ // Two frames consumed in two calls matching frame boundaries.
+ {{3, 5}, {"foobar", "baz"}, {6, 3}, {11, 3}},
+ // Two frames consumed in two calls,
+ // the first call only consuming part of the first frame.
+ {{3, 5}, {"foobar", "baz"}, {5, 4}, {5, 9}},
+ // Two frames consumed in two calls,
+ // the first call consuming the entire first frame and part of the second.
+ {{3, 5}, {"foobar", "baz"}, {7, 2}, {12, 2}},
+};
+
+TEST_F(QuicSpdyStreamBodyManagerTest, OnBodyConsumed) {
+ for (size_t test_case_index = 0;
+ test_case_index < QUIC_ARRAYSIZE(kOnBodyConsumedTestData);
+ ++test_case_index) {
+ const std::vector<QuicByteCount>& frame_header_lengths =
+ kOnBodyConsumedTestData[test_case_index].frame_header_lengths;
+ const std::vector<const char*>& frame_payloads =
+ kOnBodyConsumedTestData[test_case_index].frame_payloads;
+ const std::vector<QuicByteCount>& body_bytes_to_read =
+ kOnBodyConsumedTestData[test_case_index].body_bytes_to_read;
+ const std::vector<QuicByteCount>& expected_return_values =
+ kOnBodyConsumedTestData[test_case_index].expected_return_values;
+
+ for (size_t frame_index = 0; frame_index < frame_header_lengths.size();
+ ++frame_index) {
+ // Frame header of first frame can immediately be consumed, but not the
+ // other frames. Each test case start with an empty
+ // QuicSpdyStreamBodyManager.
+ EXPECT_EQ(frame_index == 0 ? frame_header_lengths[frame_index] : 0u,
+ body_manager_.OnNonBody(frame_header_lengths[frame_index]));
+ body_manager_.OnBody(frame_payloads[frame_index]);
+ }
+
+ for (size_t call_index = 0; call_index < body_bytes_to_read.size();
+ ++call_index) {
+ EXPECT_EQ(expected_return_values[call_index],
+ body_manager_.OnBodyConsumed(body_bytes_to_read[call_index]));
+ }
+
+ EXPECT_FALSE(body_manager_.HasBytesToRead());
+ }
+}
+
+struct {
+ std::vector<QuicByteCount> frame_header_lengths;
+ std::vector<const char*> frame_payloads;
+ size_t iov_len;
+} const kPeekBodyTestData[] = {
+ // No frames, more iovecs than frames.
+ {{}, {}, 1},
+ // One frame, same number of iovecs.
+ {{3}, {"foobar"}, 1},
+ // One frame, more iovecs than frames.
+ {{3}, {"foobar"}, 2},
+ // Two frames, fewer iovecs than frames.
+ {{3, 5}, {"foobar", "baz"}, 1},
+ // Two frames, same number of iovecs.
+ {{3, 5}, {"foobar", "baz"}, 2},
+ // Two frames, more iovecs than frames.
+ {{3, 5}, {"foobar", "baz"}, 3},
+};
+
+TEST_F(QuicSpdyStreamBodyManagerTest, PeekBody) {
+ for (size_t test_case_index = 0;
+ test_case_index < QUIC_ARRAYSIZE(kPeekBodyTestData); ++test_case_index) {
+ const std::vector<QuicByteCount>& frame_header_lengths =
+ kPeekBodyTestData[test_case_index].frame_header_lengths;
+ const std::vector<const char*>& frame_payloads =
+ kPeekBodyTestData[test_case_index].frame_payloads;
+ size_t iov_len = kPeekBodyTestData[test_case_index].iov_len;
+
+ QuicSpdyStreamBodyManager body_manager;
+
+ for (size_t frame_index = 0; frame_index < frame_header_lengths.size();
+ ++frame_index) {
+ // Frame header of first frame can immediately be consumed, but not the
+ // other frames. Each test case uses a new QuicSpdyStreamBodyManager
+ // instance.
+ EXPECT_EQ(frame_index == 0 ? frame_header_lengths[frame_index] : 0u,
+ body_manager.OnNonBody(frame_header_lengths[frame_index]));
+ body_manager.OnBody(frame_payloads[frame_index]);
+ }
+
+ std::vector<iovec> iovecs;
+ iovecs.resize(iov_len);
+ size_t iovs_filled = std::min(frame_payloads.size(), iov_len);
+ ASSERT_EQ(iovs_filled,
+ static_cast<size_t>(body_manager.PeekBody(&iovecs[0], iov_len)));
+ for (size_t iovec_index = 0; iovec_index < iovs_filled; ++iovec_index) {
+ EXPECT_EQ(frame_payloads[iovec_index],
+ QuicStringPiece(
+ static_cast<const char*>(iovecs[iovec_index].iov_base),
+ iovecs[iovec_index].iov_len));
+ }
+ }
+}
+
+struct {
+ std::vector<QuicByteCount> frame_header_lengths;
+ std::vector<const char*> frame_payloads;
+ std::vector<std::vector<QuicByteCount>> iov_lengths;
+ std::vector<QuicByteCount> expected_total_bytes_read;
+ std::vector<QuicByteCount> expected_return_values;
+} const kReadBodyTestData[] = {
+ // One frame, one read with smaller iovec.
+ {{4}, {"foo"}, {{2}}, {2}, {2}},
+ // One frame, one read with same size iovec.
+ {{4}, {"foo"}, {{3}}, {3}, {3}},
+ // One frame, one read with larger iovec.
+ {{4}, {"foo"}, {{5}}, {3}, {3}},
+ // One frame, one read with two iovecs, smaller total size.
+ {{4}, {"foobar"}, {{2, 3}}, {5}, {5}},
+ // One frame, one read with two iovecs, same total size.
+ {{4}, {"foobar"}, {{2, 4}}, {6}, {6}},
+ // One frame, one read with two iovecs, larger total size in last iovec.
+ {{4}, {"foobar"}, {{2, 6}}, {6}, {6}},
+ // One frame, one read with extra iovecs, body ends at iovec boundary.
+ {{4}, {"foobar"}, {{2, 4, 4, 3}}, {6}, {6}},
+ // One frame, one read with extra iovecs, body ends not at iovec boundary.
+ {{4}, {"foobar"}, {{2, 7, 4, 3}}, {6}, {6}},
+ // One frame, two reads with two iovecs each, smaller total size.
+ {{4}, {"foobarbaz"}, {{2, 1}, {3, 2}}, {3, 5}, {3, 5}},
+ // One frame, two reads with two iovecs each, same total size.
+ {{4}, {"foobarbaz"}, {{2, 1}, {4, 2}}, {3, 6}, {3, 6}},
+ // One frame, two reads with two iovecs each, larger total size.
+ {{4}, {"foobarbaz"}, {{2, 1}, {4, 10}}, {3, 6}, {3, 6}},
+ // Two frames, one read with smaller iovec.
+ {{4, 3}, {"foobar", "baz"}, {{8}}, {8}, {11}},
+ // Two frames, one read with same size iovec.
+ {{4, 3}, {"foobar", "baz"}, {{9}}, {9}, {12}},
+ // Two frames, one read with larger iovec.
+ {{4, 3}, {"foobar", "baz"}, {{10}}, {9}, {12}},
+ // Two frames, one read with two iovecs, smaller total size.
+ {{4, 3}, {"foobar", "baz"}, {{4, 3}}, {7}, {10}},
+ // Two frames, one read with two iovecs, same total size.
+ {{4, 3}, {"foobar", "baz"}, {{4, 5}}, {9}, {12}},
+ // Two frames, one read with two iovecs, larger total size in last iovec.
+ {{4, 3}, {"foobar", "baz"}, {{4, 6}}, {9}, {12}},
+ // Two frames, one read with extra iovecs, body ends at iovec boundary.
+ {{4, 3}, {"foobar", "baz"}, {{4, 6, 4, 3}}, {9}, {12}},
+ // Two frames, one read with extra iovecs, body ends not at iovec boundary.
+ {{4, 3}, {"foobar", "baz"}, {{4, 7, 4, 3}}, {9}, {12}},
+ // Two frames, two reads with two iovecs each, reads end on frame boundary.
+ {{4, 3}, {"foobar", "baz"}, {{2, 4}, {2, 1}}, {6, 3}, {9, 3}},
+ // Three frames, three reads, extra iovecs, no iovec ends on frame boundary.
+ {{4, 3, 6},
+ {"foobar", "bazquux", "qux"},
+ {{4, 3}, {2, 3}, {5, 3}},
+ {7, 5, 4},
+ {10, 5, 10}},
+};
+
+TEST_F(QuicSpdyStreamBodyManagerTest, ReadBody) {
+ for (size_t test_case_index = 0;
+ test_case_index < QUIC_ARRAYSIZE(kReadBodyTestData); ++test_case_index) {
+ const std::vector<QuicByteCount>& frame_header_lengths =
+ kReadBodyTestData[test_case_index].frame_header_lengths;
+ const std::vector<const char*>& frame_payloads =
+ kReadBodyTestData[test_case_index].frame_payloads;
+ const std::vector<std::vector<QuicByteCount>>& iov_lengths =
+ kReadBodyTestData[test_case_index].iov_lengths;
+ const std::vector<QuicByteCount>& expected_total_bytes_read =
+ kReadBodyTestData[test_case_index].expected_total_bytes_read;
+ const std::vector<QuicByteCount>& expected_return_values =
+ kReadBodyTestData[test_case_index].expected_return_values;
+
+ QuicSpdyStreamBodyManager body_manager;
+
+ std::string received_body;
+
+ for (size_t frame_index = 0; frame_index < frame_header_lengths.size();
+ ++frame_index) {
+ // Frame header of first frame can immediately be consumed, but not the
+ // other frames. Each test case uses a new QuicSpdyStreamBodyManager
+ // instance.
+ EXPECT_EQ(frame_index == 0 ? frame_header_lengths[frame_index] : 0u,
+ body_manager.OnNonBody(frame_header_lengths[frame_index]));
+ body_manager.OnBody(frame_payloads[frame_index]);
+ received_body.append(frame_payloads[frame_index]);
+ }
+
+ std::string read_body;
+
+ for (size_t call_index = 0; call_index < iov_lengths.size(); ++call_index) {
+ // Allocate single buffer for iovecs.
+ size_t total_iov_length = std::accumulate(iov_lengths[call_index].begin(),
+ iov_lengths[call_index].end(),
+ static_cast<size_t>(0));
+ std::string buffer(total_iov_length, 'z');
+
+ // Construct iovecs pointing to contiguous areas in the buffer.
+ std::vector<iovec> iovecs;
+ size_t offset = 0;
+ for (size_t iov_length : iov_lengths[call_index]) {
+ CHECK(offset + iov_length <= buffer.size());
+ iovecs.push_back({&buffer[offset], iov_length});
+ offset += iov_length;
+ }
+
+ // Make sure |total_bytes_read| differs from |expected_total_bytes_read|.
+ size_t total_bytes_read = expected_total_bytes_read[call_index] + 12;
+ EXPECT_EQ(
+ expected_return_values[call_index],
+ body_manager.ReadBody(&iovecs[0], iovecs.size(), &total_bytes_read));
+ read_body.append(buffer.substr(0, total_bytes_read));
+ }
+
+ EXPECT_EQ(received_body.substr(0, read_body.size()), read_body);
+ EXPECT_EQ(read_body.size() < received_body.size(),
+ body_manager.HasBytesToRead());
+ }
+}
+
+} // anonymous namespace
+
+} // namespace test
+
+} // namespace quic
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 f9777ec420f..e09cbf46e16 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
@@ -108,22 +108,26 @@ class TestStream : public QuicSpdyStream {
class TestMockUpdateStreamSession : public MockQuicSpdySession {
public:
explicit TestMockUpdateStreamSession(QuicConnection* connection)
- : MockQuicSpdySession(connection) {}
+ : MockQuicSpdySession(connection),
+ expected_precedence_(
+ spdy::SpdyStreamPrecedence(QuicStream::kDefaultPriority)) {}
- void UpdateStreamPriority(QuicStreamId id, SpdyPriority priority) override {
+ void UpdateStreamPriority(
+ QuicStreamId id,
+ const spdy::SpdyStreamPrecedence& precedence) override {
EXPECT_EQ(id, expected_stream_->id());
- EXPECT_EQ(expected_priority_, priority);
- EXPECT_EQ(expected_priority_, expected_stream_->priority());
+ EXPECT_EQ(expected_precedence_, precedence);
+ EXPECT_EQ(expected_precedence_, expected_stream_->precedence());
}
void SetExpectedStream(QuicSpdyStream* stream) { expected_stream_ = stream; }
- void SetExpectedPriority(SpdyPriority priority) {
- expected_priority_ = priority;
+ void SetExpectedPriority(const spdy::SpdyStreamPrecedence& precedence) {
+ expected_precedence_ = precedence;
}
private:
QuicSpdyStream* expected_stream_;
- SpdyPriority expected_priority_;
+ spdy::SpdyStreamPrecedence expected_precedence_;
};
class QuicSpdyStreamTest : public QuicTestWithParam<ParsedQuicVersion> {
@@ -160,11 +164,27 @@ class QuicSpdyStreamTest : public QuicTestWithParam<ParsedQuicVersion> {
~QuicSpdyStreamTest() override = default;
- std::string EncodeQpackHeaders(QuicStreamId id, SpdyHeaderBlock* header) {
+ // Return QPACK-encoded header block without using the dynamic table.
+ std::string EncodeQpackHeaders(
+ std::vector<std::pair<QuicStringPiece, QuicStringPiece>> headers) {
+ SpdyHeaderBlock header_block;
+ for (const auto& header_field : headers) {
+ header_block.AppendValueOrAddHeader(header_field.first,
+ header_field.second);
+ }
+
+ return EncodeQpackHeaders(header_block);
+ }
+
+ // Return QPACK-encoded header block without using the dynamic table.
+ std::string EncodeQpackHeaders(const SpdyHeaderBlock& header) {
NoopQpackStreamSenderDelegate encoder_stream_sender_delegate;
- auto qpack_encoder = QuicMakeUnique<QpackEncoder>(
- session_.get(), &encoder_stream_sender_delegate);
- return qpack_encoder->EncodeHeaderList(id, header);
+ auto qpack_encoder = QuicMakeUnique<QpackEncoder>(session_.get());
+ qpack_encoder->set_qpack_stream_sender_delegate(
+ &encoder_stream_sender_delegate);
+ // QpackEncoder does not use the dynamic table by default,
+ // therefore the value of |stream_id| does not matter.
+ return qpack_encoder->EncodeHeaderList(/* stream_id = */ 0, header);
}
void Initialize(bool stream_should_process_data) {
@@ -206,6 +226,20 @@ class QuicSpdyStreamTest : public QuicTestWithParam<ParsedQuicVersion> {
return VersionHasDataFrameHeader(GetParam().transport_version);
}
+ // Construct HEADERS frame with QPACK-encoded |headers| without using the
+ // dynamic table.
+ std::string HeadersFrame(
+ std::vector<std::pair<QuicStringPiece, QuicStringPiece>> headers) {
+ return HeadersFrame(EncodeQpackHeaders(headers));
+ }
+
+ // Construct HEADERS frame with QPACK-encoded |headers| without using the
+ // dynamic table.
+ std::string HeadersFrame(const SpdyHeaderBlock& headers) {
+ return HeadersFrame(EncodeQpackHeaders(headers));
+ }
+
+ // Construct HEADERS frame with given payload.
std::string HeadersFrame(QuicStringPiece payload) {
std::unique_ptr<char[]> headers_buffer;
QuicByteCount headers_frame_header_length =
@@ -224,6 +258,24 @@ class QuicSpdyStreamTest : public QuicTestWithParam<ParsedQuicVersion> {
return QuicStrCat(data_frame_header, payload);
}
+ std::string UnknownFrame(uint64_t frame_type, QuicStringPiece payload) {
+ std::string frame;
+ const size_t length = QuicDataWriter::GetVarInt62Len(frame_type) +
+ QuicDataWriter::GetVarInt62Len(payload.size()) +
+ payload.size();
+ frame.resize(length);
+
+ QuicDataWriter writer(length, const_cast<char*>(frame.data()));
+ writer.WriteVarInt62(frame_type);
+ writer.WriteStringPieceVarInt62(payload);
+ // Even though integers can be encoded with different lengths,
+ // QuicDataWriter is expected to produce an encoding in Write*() of length
+ // promised in GetVarInt62Len().
+ DCHECK_EQ(length, writer.length());
+
+ return frame;
+ }
+
MockQuicConnectionHelper helper_;
MockAlarmFactory alarm_factory_;
MockQuicConnection* connection_;
@@ -245,7 +297,8 @@ INSTANTIATE_TEST_SUITE_P(Tests,
TEST_P(QuicSpdyStreamTest, ProcessHeaderList) {
Initialize(kShouldProcessData);
- stream_->OnStreamHeadersPriority(kV3HighestPriority);
+ stream_->OnStreamHeadersPriority(
+ spdy::SpdyStreamPrecedence(kV3HighestPriority));
ProcessHeaders(false, headers_);
EXPECT_EQ("", stream_->data());
EXPECT_FALSE(stream_->header_list().empty());
@@ -256,7 +309,8 @@ TEST_P(QuicSpdyStreamTest, ProcessTooLargeHeaderList) {
Initialize(kShouldProcessData);
QuicHeaderList headers;
- stream_->OnStreamHeadersPriority(kV3HighestPriority);
+ stream_->OnStreamHeadersPriority(
+ spdy::SpdyStreamPrecedence(kV3HighestPriority));
const bool version_uses_qpack =
VersionUsesQpack(GetParam().transport_version);
@@ -288,7 +342,8 @@ TEST_P(QuicSpdyStreamTest, ProcessHeaderListWithFin) {
headers.OnHeader(p.first, p.second);
total_bytes += p.first.size() + p.second.size();
}
- stream_->OnStreamHeadersPriority(kV3HighestPriority);
+ stream_->OnStreamHeadersPriority(
+ spdy::SpdyStreamPrecedence(kV3HighestPriority));
stream_->OnStreamHeaderList(true, total_bytes, headers);
EXPECT_EQ("", stream_->data());
EXPECT_FALSE(stream_->header_list().empty());
@@ -925,7 +980,8 @@ TEST_P(QuicSpdyStreamTest, ReceivingTrailersViaHeaderList) {
total_bytes += p.first.size() + p.second.size();
}
- stream_->OnStreamHeadersPriority(kV3HighestPriority);
+ stream_->OnStreamHeadersPriority(
+ spdy::SpdyStreamPrecedence(kV3HighestPriority));
stream_->OnStreamHeaderList(/*fin=*/false, total_bytes, headers);
stream_->ConsumeHeaderList();
@@ -1191,6 +1247,14 @@ TEST_P(QuicSpdyStreamTest, ClientWritesPriority) {
EXPECT_CALL(*session_, WritevData(send_control_stream,
send_control_stream->id(), _, _, _))
.Times(3);
+ auto qpack_encoder_stream =
+ QuicSpdySessionPeer::GetQpackEncoderSendStream(session_.get());
+ EXPECT_CALL(*session_, WritevData(qpack_encoder_stream,
+ qpack_encoder_stream->id(), 1, 0, _));
+ auto qpack_decoder_stream =
+ QuicSpdySessionPeer::GetQpackDecoderSendStream(session_.get());
+ EXPECT_CALL(*session_, WritevData(qpack_decoder_stream,
+ qpack_decoder_stream->id(), 1, 0, _));
}
// Write the initial headers, without a FIN.
@@ -1352,7 +1416,7 @@ TEST_P(QuicSpdyStreamTest, WritingTrailersAfterFIN) {
TEST_P(QuicSpdyStreamTest, HeaderStreamNotiferCorrespondingSpdyStream) {
// There is no headers stream if QPACK is used.
- if (!VersionUsesQpack(GetParam().transport_version)) {
+ if (VersionUsesQpack(GetParam().transport_version)) {
return;
}
@@ -1432,8 +1496,9 @@ TEST_P(QuicSpdyStreamTest, StreamBecomesZombieWithWriteThatCloses) {
TEST_P(QuicSpdyStreamTest, OnPriorityFrame) {
Initialize(kShouldProcessData);
- stream_->OnPriorityFrame(kV3HighestPriority);
- EXPECT_EQ(kV3HighestPriority, stream_->priority());
+ stream_->OnPriorityFrame(spdy::SpdyStreamPrecedence(kV3HighestPriority));
+ EXPECT_EQ(spdy::SpdyStreamPrecedence(kV3HighestPriority),
+ stream_->precedence());
}
TEST_P(QuicSpdyStreamTest, OnPriorityFrameAfterSendingData) {
@@ -1451,8 +1516,9 @@ TEST_P(QuicSpdyStreamTest, OnPriorityFrameAfterSendingData) {
}
EXPECT_CALL(*session_, WritevData(_, _, 4, _, FIN));
stream_->WriteOrBufferBody("data", true);
- stream_->OnPriorityFrame(kV3HighestPriority);
- EXPECT_EQ(kV3HighestPriority, stream_->priority());
+ stream_->OnPriorityFrame(spdy::SpdyStreamPrecedence(kV3HighestPriority));
+ EXPECT_EQ(spdy::SpdyStreamPrecedence(kV3HighestPriority),
+ stream_->precedence());
}
TEST_P(QuicSpdyStreamTest, SetPriorityBeforeUpdateStreamPriority) {
@@ -1473,11 +1539,11 @@ TEST_P(QuicSpdyStreamTest, SetPriorityBeforeUpdateStreamPriority) {
// if called within UpdateStreamPriority(). This expectation is enforced in
// TestMockUpdateStreamSession::UpdateStreamPriority().
session->SetExpectedStream(stream);
- session->SetExpectedPriority(kV3HighestPriority);
- stream->SetPriority(kV3HighestPriority);
+ session->SetExpectedPriority(spdy::SpdyStreamPrecedence(kV3HighestPriority));
+ stream->SetPriority(spdy::SpdyStreamPrecedence(kV3HighestPriority));
- session->SetExpectedPriority(kV3LowestPriority);
- stream->SetPriority(kV3LowestPriority);
+ session->SetExpectedPriority(spdy::SpdyStreamPrecedence(kV3LowestPriority));
+ stream->SetPriority(spdy::SpdyStreamPrecedence(kV3LowestPriority));
}
TEST_P(QuicSpdyStreamTest, StreamWaitsForAcks) {
@@ -1735,14 +1801,10 @@ TEST_P(QuicSpdyStreamTest, HeadersFrameOnRequestStream) {
Initialize(kShouldProcessData);
- // HEADERS frame with QPACK encoded single header field "foo: bar".
- std::string headers =
- HeadersFrame(QuicTextUtils::HexDecode("00002a94e703626172"));
+ std::string headers = HeadersFrame({std::make_pair("foo", "bar")});
std::string data = DataFrame(kDataFramePayload);
- // HEADERS frame with QPACK encoded single header
- // field "custom-key: custom-value".
- std::string trailers = HeadersFrame(
- QuicTextUtils::HexDecode("00002f0125a849e95ba97d7f8925a849e95bb8e8b4bf"));
+ std::string trailers =
+ HeadersFrame({std::make_pair("custom-key", "custom-value")});
std::string stream_frame_payload = QuicStrCat(headers, data, trailers);
QuicStreamFrame frame(stream_->id(), false, 0, stream_frame_payload);
@@ -1767,11 +1829,7 @@ TEST_P(QuicSpdyStreamTest, ProcessBodyAfterTrailers) {
Initialize(!kShouldProcessData);
- // HEADERS frame with QPACK encoded single header field "foo: bar".
- std::string headers =
- HeadersFrame(QuicTextUtils::HexDecode("00002a94e703626172"));
-
- // DATA frame.
+ std::string headers = HeadersFrame({std::make_pair("foo", "bar")});
std::string data = DataFrame(kDataFramePayload);
// A header block that will take more than one block of sequencer buffer.
@@ -1779,9 +1837,7 @@ TEST_P(QuicSpdyStreamTest, ProcessBodyAfterTrailers) {
// be freed.
SpdyHeaderBlock trailers_block;
trailers_block["key1"] = std::string(10000, 'x');
- std::string trailers_frame_payload =
- EncodeQpackHeaders(stream_->id(), &trailers_block);
- std::string trailers = HeadersFrame(trailers_frame_payload);
+ std::string trailers = HeadersFrame(trailers_block);
// Feed all three HTTP/3 frames in a single stream frame.
std::string stream_frame_payload = QuicStrCat(headers, data, trailers);
@@ -1857,8 +1913,24 @@ TEST_P(QuicSpdyStreamTest, ImmediateHeaderDecodingWithDynamicTableEntries) {
return;
}
+ if (GetParam().handshake_protocol == PROTOCOL_TLS1_3) {
+ // TODO(nharper, b/112643533): Figure out why this test fails when TLS is
+ // enabled and fix it.
+ return;
+ }
+
+ testing::InSequence s;
Initialize(kShouldProcessData);
+ session_->qpack_decoder()->OnSetDynamicTableCapacity(1024);
+
+ auto decoder_send_stream =
+ QuicSpdySessionPeer::GetQpackDecoderSendStream(session_.get());
+ // The stream byte will be written in the first byte.
+ EXPECT_CALL(*session_, WritevData(decoder_send_stream,
+ decoder_send_stream->id(), 1, 0, _));
+ EXPECT_CALL(*session_, WritevData(decoder_send_stream,
+ decoder_send_stream->id(), _, _, _));
// Deliver dynamic table entry to decoder.
session_->qpack_decoder()->OnInsertWithoutNameReference("foo", "bar");
@@ -1879,6 +1951,8 @@ TEST_P(QuicSpdyStreamTest, ImmediateHeaderDecodingWithDynamicTableEntries) {
headers.length(), data));
EXPECT_EQ(kDataFramePayload, stream_->data());
+ EXPECT_CALL(*session_, WritevData(decoder_send_stream,
+ decoder_send_stream->id(), _, _, _));
// Deliver second dynamic table entry to decoder.
session_->qpack_decoder()->OnInsertWithoutNameReference("trailing", "foobar");
@@ -1902,7 +1976,15 @@ TEST_P(QuicSpdyStreamTest, BlockedHeaderDecoding) {
return;
}
+ if (GetParam().handshake_protocol == PROTOCOL_TLS1_3) {
+ // TODO(nharper, b/112643533): Figure out why this test fails when TLS is
+ // enabled and fix it.
+ return;
+ }
+
+ testing::InSequence s;
Initialize(kShouldProcessData);
+ session_->qpack_decoder()->OnSetDynamicTableCapacity(1024);
// HEADERS frame referencing first dynamic table entry.
std::string headers = HeadersFrame(QuicTextUtils::HexDecode("020080"));
@@ -1911,6 +1993,14 @@ TEST_P(QuicSpdyStreamTest, BlockedHeaderDecoding) {
// Decoding is blocked because dynamic table entry has not been received yet.
EXPECT_FALSE(stream_->headers_decompressed());
+ auto decoder_send_stream =
+ QuicSpdySessionPeer::GetQpackDecoderSendStream(session_.get());
+
+ // The stream byte will be written in the first byte.
+ EXPECT_CALL(*session_, WritevData(decoder_send_stream,
+ decoder_send_stream->id(), 1, 0, _));
+ EXPECT_CALL(*session_, WritevData(decoder_send_stream,
+ decoder_send_stream->id(), _, _, _));
// Deliver dynamic table entry to decoder.
session_->qpack_decoder()->OnInsertWithoutNameReference("foo", "bar");
EXPECT_TRUE(stream_->headers_decompressed());
@@ -1934,6 +2024,8 @@ TEST_P(QuicSpdyStreamTest, BlockedHeaderDecoding) {
// Decoding is blocked because dynamic table entry has not been received yet.
EXPECT_FALSE(stream_->trailers_decompressed());
+ EXPECT_CALL(*session_, WritevData(decoder_send_stream,
+ decoder_send_stream->id(), _, _, _));
// Deliver second dynamic table entry to decoder.
session_->qpack_decoder()->OnInsertWithoutNameReference("trailing", "foobar");
EXPECT_TRUE(stream_->trailers_decompressed());
@@ -1950,6 +2042,7 @@ TEST_P(QuicSpdyStreamTest, AsyncErrorDecodingHeaders) {
}
Initialize(kShouldProcessData);
+ session_->qpack_decoder()->OnSetDynamicTableCapacity(1024);
// HEADERS frame only referencing entry with absolute index 0 but with
// Required Insert Count = 2, which is incorrect.
@@ -1980,7 +2073,15 @@ TEST_P(QuicSpdyStreamTest, AsyncErrorDecodingTrailers) {
return;
}
+ if (GetParam().handshake_protocol == PROTOCOL_TLS1_3) {
+ // TODO(nharper, b/112643533): Figure out why this test fails when TLS is
+ // enabled and fix it.
+ return;
+ }
+
+ testing::InSequence s;
Initialize(kShouldProcessData);
+ session_->qpack_decoder()->OnSetDynamicTableCapacity(1024);
// HEADERS frame referencing first dynamic table entry.
std::string headers = HeadersFrame(QuicTextUtils::HexDecode("020080"));
@@ -1989,6 +2090,14 @@ TEST_P(QuicSpdyStreamTest, AsyncErrorDecodingTrailers) {
// Decoding is blocked because dynamic table entry has not been received yet.
EXPECT_FALSE(stream_->headers_decompressed());
+ auto decoder_send_stream =
+ QuicSpdySessionPeer::GetQpackDecoderSendStream(session_.get());
+
+ // The stream byte will be written in the first byte.
+ EXPECT_CALL(*session_, WritevData(decoder_send_stream,
+ decoder_send_stream->id(), 1, 0, _));
+ EXPECT_CALL(*session_, WritevData(decoder_send_stream,
+ decoder_send_stream->id(), _, _, _));
// Deliver dynamic table entry to decoder.
session_->qpack_decoder()->OnInsertWithoutNameReference("foo", "bar");
EXPECT_TRUE(stream_->headers_decompressed());
@@ -2076,20 +2185,17 @@ INSTANTIATE_TEST_SUITE_P(Tests,
// Test that stream bytes are consumed (by calling
// sequencer()->MarkConsumed()) incrementally, as soon as possible.
-TEST_P(QuicSpdyStreamIncrementalConsumptionTest, IncrementalConsumptionTest) {
+TEST_P(QuicSpdyStreamIncrementalConsumptionTest, OnlyKnownFrames) {
if (!VersionUsesQpack(GetParam().transport_version)) {
return;
}
Initialize(!kShouldProcessData);
- // HEADERS frame with QPACK encoded single header field "foo: bar".
- std::string headers =
- HeadersFrame(QuicTextUtils::HexDecode("00002a94e703626172"));
+ std::string headers = HeadersFrame({std::make_pair("foo", "bar")});
// All HEADERS frame bytes are consumed even if the frame is not received
- // completely (as long as at least some of the payload is received, which is
- // an implementation detail that should not be tested).
+ // completely.
OnStreamFrame(QuicStringPiece(headers).substr(0, headers.size() - 1));
EXPECT_EQ(headers.size() - 1, NewlyConsumedBytes());
@@ -2104,21 +2210,21 @@ TEST_P(QuicSpdyStreamIncrementalConsumptionTest, IncrementalConsumptionTest) {
// DATA frame.
QuicStringPiece data_payload(kDataFramePayload);
std::string data_frame = DataFrame(data_payload);
+ QuicByteCount data_frame_header_length =
+ data_frame.size() - data_payload.size();
- // DATA frame is not consumed because payload has to be buffered.
- // TODO(bnc): Consume frame header as soon as possible.
+ // DATA frame header is consumed.
+ // DATA frame payload is not consumed because payload has to be buffered.
OnStreamFrame(data_frame);
- EXPECT_EQ(0u, NewlyConsumedBytes());
+ EXPECT_EQ(data_frame_header_length, NewlyConsumedBytes());
// Consume all but last byte of data.
EXPECT_EQ(data_payload.substr(0, data_payload.size() - 1),
ReadFromStream(data_payload.size() - 1));
- EXPECT_EQ(data_frame.size() - 1, NewlyConsumedBytes());
+ EXPECT_EQ(data_payload.size() - 1, NewlyConsumedBytes());
- // Trailing HEADERS frame with QPACK encoded
- // single header field "custom-key: custom-value".
- std::string trailers = HeadersFrame(
- QuicTextUtils::HexDecode("00002f0125a849e95ba97d7f8925a849e95bb8e8b4bf"));
+ std::string trailers =
+ HeadersFrame({std::make_pair("custom-key", "custom-value")});
// No bytes are consumed, because last byte of DATA payload is still buffered.
OnStreamFrame(QuicStringPiece(trailers).substr(0, trailers.size() - 1));
@@ -2138,24 +2244,109 @@ TEST_P(QuicSpdyStreamIncrementalConsumptionTest, IncrementalConsumptionTest) {
ElementsAre(Pair("custom-key", "custom-value")));
}
-TEST_P(QuicSpdyStreamTest, PushPromiseOnDataStreamShouldClose) {
+TEST_P(QuicSpdyStreamIncrementalConsumptionTest, UnknownFramesInterleaved) {
+ if (!VersionUsesQpack(GetParam().transport_version)) {
+ return;
+ }
+
+ Initialize(!kShouldProcessData);
+
+ // Unknown frame of reserved type before HEADERS is consumed immediately.
+ std::string unknown_frame1 = UnknownFrame(0x21, "foo");
+ OnStreamFrame(unknown_frame1);
+ EXPECT_EQ(unknown_frame1.size(), NewlyConsumedBytes());
+
+ std::string headers = HeadersFrame({std::make_pair("foo", "bar")});
+
+ // All HEADERS frame bytes are consumed even if the frame is not received
+ // completely.
+ OnStreamFrame(QuicStringPiece(headers).substr(0, headers.size() - 1));
+ EXPECT_EQ(headers.size() - 1, NewlyConsumedBytes());
+
+ // The rest of the HEADERS frame is also consumed immediately.
+ OnStreamFrame(QuicStringPiece(headers).substr(headers.size() - 1));
+ EXPECT_EQ(1u, NewlyConsumedBytes());
+
+ // Verify headers.
+ EXPECT_THAT(stream_->header_list(), ElementsAre(Pair("foo", "bar")));
+ stream_->ConsumeHeaderList();
+
+ // Frame of unknown, not reserved type between HEADERS and DATA is consumed
+ // immediately.
+ std::string unknown_frame2 = UnknownFrame(0x3a, "");
+ OnStreamFrame(unknown_frame2);
+ EXPECT_EQ(unknown_frame2.size(), NewlyConsumedBytes());
+
+ // DATA frame.
+ QuicStringPiece data_payload(kDataFramePayload);
+ std::string data_frame = DataFrame(data_payload);
+ QuicByteCount data_frame_header_length =
+ data_frame.size() - data_payload.size();
+
+ // DATA frame header is consumed.
+ // DATA frame payload is not consumed because payload has to be buffered.
+ OnStreamFrame(data_frame);
+ EXPECT_EQ(data_frame_header_length, NewlyConsumedBytes());
+
+ // Frame of unknown, not reserved type is not consumed because DATA payload is
+ // still buffered.
+ std::string unknown_frame3 = UnknownFrame(0x39, "bar");
+ OnStreamFrame(unknown_frame3);
+ EXPECT_EQ(0u, NewlyConsumedBytes());
+
+ // Consume all but last byte of data.
+ EXPECT_EQ(data_payload.substr(0, data_payload.size() - 1),
+ ReadFromStream(data_payload.size() - 1));
+ EXPECT_EQ(data_payload.size() - 1, NewlyConsumedBytes());
+
+ std::string trailers =
+ HeadersFrame({std::make_pair("custom-key", "custom-value")});
+
+ // No bytes are consumed, because last byte of DATA payload is still buffered.
+ OnStreamFrame(QuicStringPiece(trailers).substr(0, trailers.size() - 1));
+ EXPECT_EQ(0u, NewlyConsumedBytes());
+
+ // Reading last byte of DATA payload triggers consumption of all data received
+ // so far, even though last HEADERS frame has not been received completely.
+ EXPECT_EQ(data_payload.substr(data_payload.size() - 1), ReadFromStream(1));
+ EXPECT_EQ(1 + unknown_frame3.size() + trailers.size() - 1,
+ NewlyConsumedBytes());
+
+ // Last byte of trailers is immediately consumed.
+ OnStreamFrame(QuicStringPiece(trailers).substr(trailers.size() - 1));
+ EXPECT_EQ(1u, NewlyConsumedBytes());
+
+ // Verify trailers.
+ EXPECT_THAT(stream_->received_trailers(),
+ ElementsAre(Pair("custom-key", "custom-value")));
+
+ // Unknown frame of reserved type after trailers is consumed immediately.
+ std::string unknown_frame4 = UnknownFrame(0x40, "");
+ OnStreamFrame(unknown_frame4);
+ EXPECT_EQ(unknown_frame4.size(), NewlyConsumedBytes());
+}
+
+TEST_P(QuicSpdyStreamTest, PushPromiseOnDataStream) {
Initialize(kShouldProcessData);
if (!HasFrameHeader()) {
return;
}
+
+ std::string headers = EncodeQpackHeaders({{"foo", "bar"}});
+
PushPromiseFrame push_promise;
push_promise.push_id = 0x01;
- push_promise.headers = "Headers";
+ push_promise.headers = headers;
std::unique_ptr<char[]> buffer;
HttpEncoder encoder;
uint64_t length =
encoder.SerializePushPromiseFrameWithOnlyPushId(push_promise, &buffer);
- QuicStreamFrame frame(stream_->id(), false, 0, buffer.get(), length);
- // TODO(lassey): Check for HTTP_WRONG_STREAM error code.
- EXPECT_CALL(*connection_, CloseConnection(QUIC_HTTP_DECODER_ERROR, _, _));
- stream_->OnStreamHeadersPriority(kV3HighestPriority);
- ProcessHeaders(false, headers_);
- stream_->ConsumeHeaderList();
+ std::string data = std::string(buffer.get(), length) + headers;
+ QuicStreamFrame frame(stream_->id(), false, 0, data);
+
+ EXPECT_CALL(*session_,
+ OnPromiseHeaderList(stream_->id(), push_promise.push_id,
+ headers.length(), _));
stream_->OnStreamFrame(frame);
}
@@ -2189,9 +2380,8 @@ TEST_P(QuicSpdyStreamTest, TrailersAfterTrailers) {
Initialize(kShouldProcessData);
- // Receive and consume headers, with single header field "foo: bar".
- std::string headers =
- HeadersFrame(QuicTextUtils::HexDecode("00002a94e703626172"));
+ // Receive and consume headers.
+ std::string headers = HeadersFrame({std::make_pair("foo", "bar")});
QuicStreamOffset offset = 0;
stream_->OnStreamFrame(
QuicStreamFrame(stream_->id(), false, offset, headers));
@@ -2207,10 +2397,9 @@ TEST_P(QuicSpdyStreamTest, TrailersAfterTrailers) {
EXPECT_EQ(kDataFramePayload, stream_->data());
- // Receive and consume trailers, with single header field
- // "custom-key: custom-value".
- std::string trailers1 = HeadersFrame(
- QuicTextUtils::HexDecode("00002f0125a849e95ba97d7f8925a849e95bb8e8b4bf"));
+ // Receive and consume trailers.
+ std::string trailers1 =
+ HeadersFrame({std::make_pair("custom-key", "custom-value")});
stream_->OnStreamFrame(
QuicStreamFrame(stream_->id(), false, offset, trailers1));
offset += trailers1.size();
@@ -2230,7 +2419,7 @@ TEST_P(QuicSpdyStreamTest, TrailersAfterTrailers) {
.WillOnce(InvokeWithoutArgs([this]() { stream_->StopReading(); }));
// Receive another HEADERS frame, with no header fields.
- std::string trailers2 = HeadersFrame(QuicTextUtils::HexDecode("0000"));
+ std::string trailers2 = HeadersFrame(SpdyHeaderBlock());
stream_->OnStreamFrame(
QuicStreamFrame(stream_->id(), false, offset, trailers2));
}
@@ -2244,9 +2433,8 @@ TEST_P(QuicSpdyStreamTest, DataAfterTrailers) {
Initialize(kShouldProcessData);
- // Receive and consume headers, with single header field "foo: bar".
- std::string headers =
- HeadersFrame(QuicTextUtils::HexDecode("00002a94e703626172"));
+ // Receive and consume headers.
+ std::string headers = HeadersFrame({std::make_pair("foo", "bar")});
QuicStreamOffset offset = 0;
stream_->OnStreamFrame(
QuicStreamFrame(stream_->id(), false, offset, headers));
@@ -2262,8 +2450,8 @@ TEST_P(QuicSpdyStreamTest, DataAfterTrailers) {
EXPECT_EQ(kDataFramePayload, stream_->data());
// Receive trailers, with single header field "custom-key: custom-value".
- std::string trailers = HeadersFrame(
- QuicTextUtils::HexDecode("00002f0125a849e95ba97d7f8925a849e95bb8e8b4bf"));
+ std::string trailers =
+ HeadersFrame({std::make_pair("custom-key", "custom-value")});
stream_->OnStreamFrame(
QuicStreamFrame(stream_->id(), false, offset, trailers));
offset += trailers.size();
@@ -2297,10 +2485,10 @@ TEST_P(QuicSpdyStreamTest, StopProcessingIfConnectionClosed) {
// SETTINGS frame with empty payload.
std::string settings = QuicTextUtils::HexDecode("0400");
- // HEADERS frame with QPACK encoded single header field "foo: bar".
+
+ // HEADERS frame.
// Since it arrives after a SETTINGS frame, it should never be read.
- std::string headers =
- HeadersFrame(QuicTextUtils::HexDecode("00002a94e703626172"));
+ std::string headers = HeadersFrame({std::make_pair("foo", "bar")});
// Combine the two frames to make sure they are processed in a single
// QuicSpdyStream::OnDataAvailable() call.
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/offline/qpack_offline_decoder.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/offline/qpack_offline_decoder.cc
index 20af0748723..dc2d864f058 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/offline/qpack_offline_decoder.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/offline/qpack_offline_decoder.cc
@@ -20,7 +20,6 @@ namespace quic {
QpackOfflineDecoder::QpackOfflineDecoder()
: encoder_stream_error_detected_(false),
- qpack_decoder_(this, &decoder_stream_sender_delegate_),
max_blocked_streams_(0) {}
bool QpackOfflineDecoder::DecodeAndVerifyOfflineData(
@@ -93,8 +92,10 @@ bool QpackOfflineDecoder::ParseInputFilename(QuicStringPiece input_filename) {
<< "\" as an integer.";
return false;
}
-
- qpack_decoder_.SetMaximumDynamicTableCapacity(maximum_dynamic_table_capacity);
+ qpack_decoder_ = QuicMakeUnique<QpackDecoder>(maximum_dynamic_table_capacity,
+ max_blocked_streams_, this);
+ qpack_decoder_->set_qpack_stream_sender_delegate(
+ &decoder_stream_sender_delegate_);
return true;
}
@@ -133,7 +134,7 @@ bool QpackOfflineDecoder::DecodeHeaderBlocksFromFile(
// Process data.
if (stream_id == 0) {
- qpack_decoder_.DecodeEncoderStreamData(data);
+ qpack_decoder_->encoder_stream_receiver()->Decode(data);
if (encoder_stream_error_detected_) {
QUIC_LOG(ERROR) << "Error detected on encoder stream.";
@@ -141,7 +142,7 @@ bool QpackOfflineDecoder::DecodeHeaderBlocksFromFile(
}
} else {
auto headers_handler = QuicMakeUnique<test::TestHeadersHandler>();
- auto progressive_decoder = qpack_decoder_.CreateProgressiveDecoder(
+ auto progressive_decoder = qpack_decoder_->CreateProgressiveDecoder(
stream_id, headers_handler.get());
progressive_decoder->Decode(data);
@@ -183,6 +184,7 @@ bool QpackOfflineDecoder::DecodeHeaderBlocksFromFile(
}
// Enforce limit on blocked streams.
+ // TODO(b/112770235): Move this logic to QpackDecoder.
uint64_t blocked_streams_count = 0;
for (const auto& decoder : decoders_) {
if (!decoder.headers_handler->decoding_completed()) {
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/offline/qpack_offline_decoder.h b/chromium/net/third_party/quiche/src/quic/core/qpack/offline/qpack_offline_decoder.h
index 9984d4b4b16..dcb8894572c 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/offline/qpack_offline_decoder.h
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/offline/qpack_offline_decoder.h
@@ -72,7 +72,7 @@ class QpackOfflineDecoder : public QpackDecoder::EncoderStreamErrorDelegate {
bool encoder_stream_error_detected_;
NoopQpackStreamSenderDelegate decoder_stream_sender_delegate_;
- QpackDecoder qpack_decoder_;
+ std::unique_ptr<QpackDecoder> qpack_decoder_;
uint64_t max_blocked_streams_;
// Objects necessary for decoding, one list element for each header block.
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.cc
new file mode 100644
index 00000000000..04d824fa969
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.cc
@@ -0,0 +1,144 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.h"
+
+#include <utility>
+
+namespace quic {
+
+QpackBlockingManager::QpackBlockingManager() : known_received_count_(0) {}
+
+bool QpackBlockingManager::OnHeaderAcknowledgement(QuicStreamId stream_id) {
+ auto it = header_blocks_.find(stream_id);
+ if (it == header_blocks_.end()) {
+ return false;
+ }
+
+ DCHECK(!it->second.empty());
+
+ const IndexSet& indices = it->second.front();
+ DCHECK(!indices.empty());
+
+ const uint64_t required_index_count = RequiredInsertCount(indices);
+ if (known_received_count_ < required_index_count) {
+ IncreaseKnownReceivedCountTo(required_index_count);
+ }
+
+ DecreaseReferenceCounts(indices);
+
+ it->second.pop_front();
+ if (it->second.empty()) {
+ header_blocks_.erase(it);
+ }
+
+ return true;
+}
+
+void QpackBlockingManager::OnStreamCancellation(QuicStreamId stream_id) {
+ auto it = header_blocks_.find(stream_id);
+ if (it == header_blocks_.end()) {
+ return;
+ }
+
+ for (const IndexSet& indices : it->second) {
+ DecreaseReferenceCounts(indices);
+ }
+
+ header_blocks_.erase(it);
+}
+
+void QpackBlockingManager::OnInsertCountIncrement(uint64_t increment) {
+ IncreaseKnownReceivedCountTo(known_received_count_ + increment);
+}
+
+void QpackBlockingManager::OnHeaderBlockSent(QuicStreamId stream_id,
+ IndexSet indices) {
+ DCHECK(!indices.empty());
+
+ IncreaseReferenceCounts(indices);
+ header_blocks_[stream_id].push_back(std::move(indices));
+}
+
+void QpackBlockingManager::OnReferenceSentOnEncoderStream(
+ uint64_t inserted_index,
+ uint64_t referred_index) {
+ auto result = unacked_encoder_stream_references_.insert(
+ {inserted_index, referred_index});
+ // Each dynamic table entry can refer to at most one |referred_index|.
+ DCHECK(result.second);
+ IncreaseReferenceCounts({referred_index});
+}
+
+uint64_t QpackBlockingManager::blocked_stream_count() const {
+ uint64_t blocked_stream_count = 0;
+ for (const auto& header_blocks_for_stream : header_blocks_) {
+ for (const IndexSet& indices : header_blocks_for_stream.second) {
+ if (RequiredInsertCount(indices) > known_received_count_) {
+ ++blocked_stream_count;
+ break;
+ }
+ }
+ }
+
+ return blocked_stream_count;
+}
+
+uint64_t QpackBlockingManager::smallest_blocking_index() const {
+ return entry_reference_counts_.empty()
+ ? std::numeric_limits<uint64_t>::max()
+ : entry_reference_counts_.begin()->first;
+}
+
+// static
+uint64_t QpackBlockingManager::RequiredInsertCount(const IndexSet& indices) {
+ return *indices.rbegin() + 1;
+}
+
+void QpackBlockingManager::IncreaseKnownReceivedCountTo(
+ uint64_t new_known_received_count) {
+ DCHECK_GT(new_known_received_count, known_received_count_);
+
+ known_received_count_ = new_known_received_count;
+
+ // Remove referred indices with key less than new Known Received Count from
+ // |unacked_encoder_stream_references_| and |entry_reference_counts_|.
+ IndexSet acknowledged_references;
+ auto it = unacked_encoder_stream_references_.begin();
+ while (it != unacked_encoder_stream_references_.end() &&
+ it->first < known_received_count_) {
+ acknowledged_references.insert(it->second);
+ ++it;
+ }
+ unacked_encoder_stream_references_.erase(
+ unacked_encoder_stream_references_.begin(), it);
+ DecreaseReferenceCounts(acknowledged_references);
+}
+
+void QpackBlockingManager::IncreaseReferenceCounts(const IndexSet& indices) {
+ for (const uint64_t index : indices) {
+ auto it = entry_reference_counts_.lower_bound(index);
+ if (it != entry_reference_counts_.end() && it->first == index) {
+ ++it->second;
+ } else {
+ entry_reference_counts_.insert(it, {index, 1});
+ }
+ }
+}
+
+void QpackBlockingManager::DecreaseReferenceCounts(const IndexSet& indices) {
+ for (const uint64_t index : indices) {
+ auto it = entry_reference_counts_.find(index);
+ DCHECK(it != entry_reference_counts_.end());
+ DCHECK_NE(0u, it->second);
+
+ if (it->second == 1) {
+ entry_reference_counts_.erase(it);
+ } else {
+ --it->second;
+ }
+ }
+}
+
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.h
new file mode 100644
index 00000000000..7acfd5abac1
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.h
@@ -0,0 +1,100 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_CORE_QPACK_QPACK_BLOCKING_MANAGER_H_
+#define QUICHE_QUIC_CORE_QPACK_QPACK_BLOCKING_MANAGER_H_
+
+#include <cstdint>
+#include <map>
+#include <set>
+
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
+
+namespace quic {
+
+// Class to keep track of blocked streams and blocking dynamic table entries:
+// https://quicwg.org/base-drafts/draft-ietf-quic-qpack.html#blocked-decoding
+// https://quicwg.org/base-drafts/draft-ietf-quic-qpack.html#blocked-insertion
+class QUIC_EXPORT_PRIVATE QpackBlockingManager {
+ public:
+ using IndexSet = std::multiset<uint64_t>;
+
+ QpackBlockingManager();
+
+ // Called when a Header Acknowledgement instruction is received on the decoder
+ // stream. Returns false if there are no outstanding header blocks to be
+ // acknowledged on |stream_id|.
+ bool OnHeaderAcknowledgement(QuicStreamId stream_id);
+
+ // Called when a Stream Cancellation instruction is received on the decoder
+ // stream.
+ void OnStreamCancellation(QuicStreamId stream_id);
+
+ // Called when an Insert Count Increment instruction is received on the
+ // decoder stream.
+ void OnInsertCountIncrement(uint64_t increment);
+
+ // Called when sending a header block containing references to dynamic table
+ // entries with |indices|. |indices| must not be empty.
+ void OnHeaderBlockSent(QuicStreamId stream_id, IndexSet indices);
+
+ // Called when sending Insert With Name Reference or Duplicate instruction on
+ // encoder stream, inserting entry |inserted_index| referring to
+ // |referred_index|.
+ void OnReferenceSentOnEncoderStream(uint64_t inserted_index,
+ uint64_t referred_index);
+
+ // Returns the number of blocked streams.
+ uint64_t blocked_stream_count() const;
+
+ // Returns the index of the blocking entry with the smallest index,
+ // or std::numeric_limits<uint64_t>::max() if there are no blocking entries.
+ uint64_t smallest_blocking_index() const;
+
+ // Returns the Known Received Count as defined at
+ // https://quicwg.org/base-drafts/draft-ietf-quic-qpack.html#known-received-count.
+ uint64_t known_received_count() const { return known_received_count_; }
+
+ // Required Insert Count for set of indices.
+ static uint64_t RequiredInsertCount(const IndexSet& indices);
+
+ private:
+ // A stream typically has only one header block, except for the rare cases of
+ // 1xx responses, trailers, or push promises. Even if there are multiple
+ // header blocks sent on a single stream, they might not be blocked at the
+ // same time. Use std::list instead of QuicDeque because it has lower memory
+ // footprint when holding few elements.
+ using HeaderBlocksForStream = std::list<IndexSet>;
+ using HeaderBlocks = QuicUnorderedMap<QuicStreamId, HeaderBlocksForStream>;
+
+ // Increases |known_received_count_| to |new_known_received_count|, which must
+ // me larger than |known_received_count_|. Removes acknowledged references
+ // from |unacked_encoder_stream_references_|.
+ void IncreaseKnownReceivedCountTo(uint64_t new_known_received_count);
+
+ // Increase or decrease the reference count for each index in |indices|.
+ void IncreaseReferenceCounts(const IndexSet& indices);
+ void DecreaseReferenceCounts(const IndexSet& indices);
+
+ // Multiset of indices in each header block for each stream.
+ // Must not contain a stream id with an empty queue.
+ HeaderBlocks header_blocks_;
+
+ // Unacknowledged references on the encoder stream.
+ // The key is the absolute index of the inserted entry,
+ // the mapped value is the absolute index of the entry referred.
+ std::map<uint64_t, uint64_t> unacked_encoder_stream_references_;
+
+ // Number of references in |header_blocks_| and
+ // |unacked_encoder_stream_references_| for each entry index.
+ std::map<uint64_t, uint64_t> entry_reference_counts_;
+
+ uint64_t known_received_count_;
+};
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_CORE_QPACK_QPACK_BLOCKING_MANAGER_H_
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager_test.cc
new file mode 100644
index 00000000000..6f78d87bd54
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager_test.cc
@@ -0,0 +1,293 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.h"
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+
+namespace quic {
+namespace test {
+namespace {
+
+class QpackBlockingManagerTest : public QuicTest {
+ protected:
+ QpackBlockingManagerTest() = default;
+ ~QpackBlockingManagerTest() override = default;
+
+ QpackBlockingManager manager_;
+};
+
+TEST_F(QpackBlockingManagerTest, Empty) {
+ EXPECT_EQ(0u, manager_.blocked_stream_count());
+ EXPECT_EQ(0u, manager_.known_received_count());
+ EXPECT_EQ(std::numeric_limits<uint64_t>::max(),
+ manager_.smallest_blocking_index());
+
+ EXPECT_FALSE(manager_.OnHeaderAcknowledgement(0));
+ EXPECT_FALSE(manager_.OnHeaderAcknowledgement(1));
+}
+
+TEST_F(QpackBlockingManagerTest, NotBlockedByInsertCountIncrement) {
+ manager_.OnInsertCountIncrement(2);
+
+ // Stream 0 is not blocked, because it only references entries that are
+ // already acknowledged by an Insert Count Increment instruction.
+ manager_.OnHeaderBlockSent(0, {1, 0});
+ EXPECT_EQ(0u, manager_.blocked_stream_count());
+}
+
+TEST_F(QpackBlockingManagerTest, UnblockedByInsertCountIncrement) {
+ manager_.OnHeaderBlockSent(0, {1, 0});
+ EXPECT_EQ(1u, manager_.blocked_stream_count());
+
+ manager_.OnInsertCountIncrement(2);
+ EXPECT_EQ(0u, manager_.blocked_stream_count());
+}
+
+TEST_F(QpackBlockingManagerTest, NotBlockedByHeaderAcknowledgement) {
+ manager_.OnHeaderBlockSent(0, {2, 1, 1});
+ EXPECT_EQ(1u, manager_.blocked_stream_count());
+
+ EXPECT_TRUE(manager_.OnHeaderAcknowledgement(0));
+ EXPECT_EQ(0u, manager_.blocked_stream_count());
+
+ // Stream 1 is not blocked, because it only references entries that are
+ // already acknowledged by a Header Acknowledgement instruction.
+ manager_.OnHeaderBlockSent(1, {2, 2});
+ EXPECT_EQ(0u, manager_.blocked_stream_count());
+}
+
+TEST_F(QpackBlockingManagerTest, UnblockedByHeaderAcknowledgement) {
+ manager_.OnHeaderBlockSent(0, {2, 1, 1});
+ manager_.OnHeaderBlockSent(1, {2, 2});
+ EXPECT_EQ(2u, manager_.blocked_stream_count());
+
+ EXPECT_TRUE(manager_.OnHeaderAcknowledgement(0));
+ EXPECT_EQ(0u, manager_.blocked_stream_count());
+}
+
+TEST_F(QpackBlockingManagerTest, KnownReceivedCount) {
+ EXPECT_EQ(0u, manager_.known_received_count());
+
+ // Sending a header block does not change Known Received Count.
+ manager_.OnHeaderBlockSent(0, {0});
+ EXPECT_EQ(0u, manager_.known_received_count());
+
+ manager_.OnHeaderBlockSent(1, {1});
+ EXPECT_EQ(0u, manager_.known_received_count());
+
+ // Header Acknowledgement might increase Known Received Count.
+ EXPECT_TRUE(manager_.OnHeaderAcknowledgement(0));
+ EXPECT_EQ(1u, manager_.known_received_count());
+
+ manager_.OnHeaderBlockSent(2, {5});
+ EXPECT_EQ(1u, manager_.known_received_count());
+
+ EXPECT_TRUE(manager_.OnHeaderAcknowledgement(1));
+ EXPECT_EQ(2u, manager_.known_received_count());
+
+ // Insert Count Increment increases Known Received Count.
+ manager_.OnInsertCountIncrement(2);
+ EXPECT_EQ(4u, manager_.known_received_count());
+
+ EXPECT_TRUE(manager_.OnHeaderAcknowledgement(2));
+ EXPECT_EQ(6u, manager_.known_received_count());
+
+ // Stream Cancellation does not change Known Received Count.
+ manager_.OnStreamCancellation(0);
+ EXPECT_EQ(6u, manager_.known_received_count());
+
+ // Header Acknowledgement of a block with smaller Required Insert Count does
+ // not increase Known Received Count.
+ manager_.OnHeaderBlockSent(0, {3});
+ EXPECT_EQ(6u, manager_.known_received_count());
+
+ EXPECT_TRUE(manager_.OnHeaderAcknowledgement(0));
+ EXPECT_EQ(6u, manager_.known_received_count());
+
+ // Header Acknowledgement of a block with equal Required Insert Count does not
+ // increase Known Received Count.
+ manager_.OnHeaderBlockSent(1, {5});
+ EXPECT_EQ(6u, manager_.known_received_count());
+
+ EXPECT_TRUE(manager_.OnHeaderAcknowledgement(1));
+ EXPECT_EQ(6u, manager_.known_received_count());
+}
+
+TEST_F(QpackBlockingManagerTest, SmallestBlockingIndex) {
+ EXPECT_EQ(std::numeric_limits<uint64_t>::max(),
+ manager_.smallest_blocking_index());
+
+ manager_.OnHeaderBlockSent(0, {0});
+ EXPECT_EQ(0u, manager_.smallest_blocking_index());
+
+ manager_.OnHeaderBlockSent(1, {2});
+ EXPECT_EQ(0u, manager_.smallest_blocking_index());
+
+ EXPECT_TRUE(manager_.OnHeaderAcknowledgement(0));
+ EXPECT_EQ(2u, manager_.smallest_blocking_index());
+
+ manager_.OnHeaderBlockSent(1, {1});
+ EXPECT_EQ(1u, manager_.smallest_blocking_index());
+
+ EXPECT_TRUE(manager_.OnHeaderAcknowledgement(1));
+ EXPECT_EQ(1u, manager_.smallest_blocking_index());
+
+ // Insert Count Increment does not change smallest blocking index.
+ manager_.OnInsertCountIncrement(2);
+ EXPECT_EQ(1u, manager_.smallest_blocking_index());
+
+ manager_.OnStreamCancellation(1);
+ EXPECT_EQ(std::numeric_limits<uint64_t>::max(),
+ manager_.smallest_blocking_index());
+}
+
+TEST_F(QpackBlockingManagerTest, HeaderAcknowledgementsOnSingleStream) {
+ EXPECT_EQ(0u, manager_.known_received_count());
+ EXPECT_EQ(0u, manager_.blocked_stream_count());
+ EXPECT_EQ(std::numeric_limits<uint64_t>::max(),
+ manager_.smallest_blocking_index());
+
+ manager_.OnHeaderBlockSent(0, {2, 1, 1});
+ EXPECT_EQ(0u, manager_.known_received_count());
+ EXPECT_EQ(1u, manager_.blocked_stream_count());
+ EXPECT_EQ(1u, manager_.smallest_blocking_index());
+
+ manager_.OnHeaderBlockSent(0, {1, 0});
+ EXPECT_EQ(0u, manager_.known_received_count());
+ EXPECT_EQ(1u, manager_.blocked_stream_count());
+ EXPECT_EQ(0u, manager_.smallest_blocking_index());
+
+ EXPECT_TRUE(manager_.OnHeaderAcknowledgement(0));
+ EXPECT_EQ(3u, manager_.known_received_count());
+ EXPECT_EQ(0u, manager_.blocked_stream_count());
+ EXPECT_EQ(0u, manager_.smallest_blocking_index());
+
+ manager_.OnHeaderBlockSent(0, {3});
+ EXPECT_EQ(3u, manager_.known_received_count());
+ EXPECT_EQ(1u, manager_.blocked_stream_count());
+ EXPECT_EQ(0u, manager_.smallest_blocking_index());
+
+ EXPECT_TRUE(manager_.OnHeaderAcknowledgement(0));
+ EXPECT_EQ(3u, manager_.known_received_count());
+ EXPECT_EQ(1u, manager_.blocked_stream_count());
+ EXPECT_EQ(3u, manager_.smallest_blocking_index());
+
+ EXPECT_TRUE(manager_.OnHeaderAcknowledgement(0));
+ EXPECT_EQ(4u, manager_.known_received_count());
+ EXPECT_EQ(0u, manager_.blocked_stream_count());
+ EXPECT_EQ(std::numeric_limits<uint64_t>::max(),
+ manager_.smallest_blocking_index());
+
+ EXPECT_FALSE(manager_.OnHeaderAcknowledgement(0));
+}
+
+TEST_F(QpackBlockingManagerTest, CancelStream) {
+ manager_.OnHeaderBlockSent(0, {3});
+ EXPECT_EQ(1u, manager_.blocked_stream_count());
+ EXPECT_EQ(3u, manager_.smallest_blocking_index());
+
+ manager_.OnHeaderBlockSent(0, {2});
+ EXPECT_EQ(1u, manager_.blocked_stream_count());
+ EXPECT_EQ(2u, manager_.smallest_blocking_index());
+
+ manager_.OnHeaderBlockSent(1, {4});
+ EXPECT_EQ(2u, manager_.blocked_stream_count());
+ EXPECT_EQ(2u, manager_.smallest_blocking_index());
+
+ manager_.OnStreamCancellation(0);
+ EXPECT_EQ(1u, manager_.blocked_stream_count());
+ EXPECT_EQ(4u, manager_.smallest_blocking_index());
+
+ manager_.OnStreamCancellation(1);
+ EXPECT_EQ(0u, manager_.blocked_stream_count());
+ EXPECT_EQ(std::numeric_limits<uint64_t>::max(),
+ manager_.smallest_blocking_index());
+}
+
+TEST_F(QpackBlockingManagerTest,
+ ReferenceOnEncoderStreamUnblockedByInsertCountIncrement) {
+ EXPECT_EQ(0u, manager_.known_received_count());
+ EXPECT_EQ(std::numeric_limits<uint64_t>::max(),
+ manager_.smallest_blocking_index());
+
+ // Entry 1 refers to entry 0.
+ manager_.OnReferenceSentOnEncoderStream(1, 0);
+ // Entry 2 also refers to entry 0.
+ manager_.OnReferenceSentOnEncoderStream(2, 0);
+
+ EXPECT_EQ(0u, manager_.known_received_count());
+ EXPECT_EQ(0u, manager_.smallest_blocking_index());
+
+ // Acknowledging entry 1 still leaves one unacknowledged reference to entry 0.
+ manager_.OnInsertCountIncrement(2);
+
+ EXPECT_EQ(2u, manager_.known_received_count());
+ EXPECT_EQ(0u, manager_.smallest_blocking_index());
+
+ // Entry 3 also refers to entry 2.
+ manager_.OnReferenceSentOnEncoderStream(3, 2);
+
+ EXPECT_EQ(2u, manager_.known_received_count());
+ EXPECT_EQ(0u, manager_.smallest_blocking_index());
+
+ // Acknowledging entry 2 removes last reference to entry 0.
+ manager_.OnInsertCountIncrement(1);
+
+ EXPECT_EQ(3u, manager_.known_received_count());
+ EXPECT_EQ(2u, manager_.smallest_blocking_index());
+
+ // Acknowledging entry 4 (and implicitly 3) removes reference to entry 2.
+ manager_.OnInsertCountIncrement(2);
+
+ EXPECT_EQ(5u, manager_.known_received_count());
+ EXPECT_EQ(std::numeric_limits<uint64_t>::max(),
+ manager_.smallest_blocking_index());
+}
+
+TEST_F(QpackBlockingManagerTest,
+ ReferenceOnEncoderStreamUnblockedByHeaderAcknowledgement) {
+ EXPECT_EQ(0u, manager_.known_received_count());
+ EXPECT_EQ(std::numeric_limits<uint64_t>::max(),
+ manager_.smallest_blocking_index());
+
+ // Entry 1 refers to entry 0.
+ manager_.OnReferenceSentOnEncoderStream(1, 0);
+ // Entry 2 also refers to entry 0.
+ manager_.OnReferenceSentOnEncoderStream(2, 0);
+
+ EXPECT_EQ(0u, manager_.known_received_count());
+ EXPECT_EQ(0u, manager_.smallest_blocking_index());
+
+ // Acknowledging a header block with entries up to 1 still leave one
+ // unacknowledged reference to entry 0.
+ manager_.OnHeaderBlockSent(/* stream_id = */ 0, {0, 1});
+ manager_.OnHeaderAcknowledgement(/* stream_id = */ 0);
+
+ EXPECT_EQ(2u, manager_.known_received_count());
+ EXPECT_EQ(0u, manager_.smallest_blocking_index());
+
+ // Entry 3 also refers to entry 2.
+ manager_.OnReferenceSentOnEncoderStream(3, 2);
+
+ // Acknowledging a header block with entries up to 2 removes last reference to
+ // entry 0.
+ manager_.OnHeaderBlockSent(/* stream_id = */ 0, {2, 0, 2});
+ manager_.OnHeaderAcknowledgement(/* stream_id = */ 0);
+
+ EXPECT_EQ(3u, manager_.known_received_count());
+ EXPECT_EQ(2u, manager_.smallest_blocking_index());
+
+ // Acknowledging entry 4 (and implicitly 3) removes reference to entry 2.
+ manager_.OnHeaderBlockSent(/* stream_id = */ 0, {1, 4, 2, 0});
+ manager_.OnHeaderAcknowledgement(/* stream_id = */ 0);
+
+ EXPECT_EQ(5u, manager_.known_received_count());
+ EXPECT_EQ(std::numeric_limits<uint64_t>::max(),
+ manager_.smallest_blocking_index());
+}
+
+} // namespace
+} // namespace test
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator_test.cc
index 0898327c6be..1d60660e9c4 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
@@ -31,6 +31,9 @@ const size_t kMaxHeaderListSize = 100;
// Maximum dynamic table capacity.
const size_t kMaxDynamicTableCapacity = 100;
+// Maximum number of blocked streams.
+const uint64_t kMaximumBlockedStreams = 1;
+
// Header Acknowledgement decoder stream instruction with stream_id = 1.
const char* const kHeaderAcknowledgement = "\x81";
@@ -46,12 +49,16 @@ class NoopVisitor : public QpackDecodedHeadersAccumulator::Visitor {
class QpackDecodedHeadersAccumulatorTest : public QuicTest {
protected:
QpackDecodedHeadersAccumulatorTest()
- : qpack_decoder_(&encoder_stream_error_delegate_,
- &decoder_stream_sender_delegate_),
+ : qpack_decoder_(kMaxDynamicTableCapacity,
+ kMaximumBlockedStreams,
+ &encoder_stream_error_delegate_),
accumulator_(kTestStreamId,
&qpack_decoder_,
&visitor_,
- kMaxHeaderListSize) {}
+ kMaxHeaderListSize) {
+ qpack_decoder_.set_qpack_stream_sender_delegate(
+ &decoder_stream_sender_delegate_);
+ }
NoopEncoderStreamErrorDelegate encoder_stream_error_delegate_;
StrictMock<MockQpackStreamSenderDelegate> decoder_stream_sender_delegate_;
@@ -74,9 +81,6 @@ TEST_F(QpackDecodedHeadersAccumulatorTest, TruncatedHeaderBlockPrefix) {
}
TEST_F(QpackDecodedHeadersAccumulatorTest, EmptyHeaderList) {
- EXPECT_CALL(decoder_stream_sender_delegate_,
- WriteStreamData(Eq(kHeaderAcknowledgement)));
-
EXPECT_TRUE(accumulator_.Decode(QuicTextUtils::HexDecode("0000")));
EXPECT_EQ(Status::kSuccess, accumulator_.EndHeaderBlock());
@@ -98,9 +102,6 @@ TEST_F(QpackDecodedHeadersAccumulatorTest, InvalidPayload) {
}
TEST_F(QpackDecodedHeadersAccumulatorTest, Success) {
- EXPECT_CALL(decoder_stream_sender_delegate_,
- WriteStreamData(Eq(kHeaderAcknowledgement)));
-
std::string encoded_data(QuicTextUtils::HexDecode("000023666f6f03626172"));
EXPECT_TRUE(accumulator_.Decode(encoded_data));
EXPECT_EQ(Status::kSuccess, accumulator_.EndHeaderBlock());
@@ -114,9 +115,6 @@ TEST_F(QpackDecodedHeadersAccumulatorTest, Success) {
}
TEST_F(QpackDecodedHeadersAccumulatorTest, ExceedingLimit) {
- EXPECT_CALL(decoder_stream_sender_delegate_,
- WriteStreamData(Eq(kHeaderAcknowledgement)));
-
// Total length of header list exceeds kMaxHeaderListSize.
EXPECT_TRUE(accumulator_.Decode(QuicTextUtils::HexDecode(
"0000" // header block prefix
@@ -132,12 +130,12 @@ TEST_F(QpackDecodedHeadersAccumulatorTest, ExceedingLimit) {
}
TEST_F(QpackDecodedHeadersAccumulatorTest, BlockedDecoding) {
- qpack_decoder_.SetMaximumDynamicTableCapacity(kMaxDynamicTableCapacity);
-
// Reference to dynamic table entry not yet received.
EXPECT_TRUE(accumulator_.Decode(QuicTextUtils::HexDecode("020080")));
EXPECT_EQ(Status::kBlocked, accumulator_.EndHeaderBlock());
+ // Set dynamic table capacity.
+ qpack_decoder_.OnSetDynamicTableCapacity(kMaxDynamicTableCapacity);
// Adding dynamic table entry unblocks decoding.
EXPECT_CALL(decoder_stream_sender_delegate_,
WriteStreamData(Eq(kHeaderAcknowledgement)));
@@ -148,11 +146,11 @@ TEST_F(QpackDecodedHeadersAccumulatorTest, BlockedDecoding) {
TEST_F(QpackDecodedHeadersAccumulatorTest,
BlockedDecodingUnblockedBeforeEndOfHeaderBlock) {
- qpack_decoder_.SetMaximumDynamicTableCapacity(kMaxDynamicTableCapacity);
-
// Reference to dynamic table entry not yet received.
EXPECT_TRUE(accumulator_.Decode(QuicTextUtils::HexDecode("020080")));
+ // Set dynamic table capacity.
+ qpack_decoder_.OnSetDynamicTableCapacity(kMaxDynamicTableCapacity);
// Adding dynamic table entry unblocks decoding.
qpack_decoder_.OnInsertWithoutNameReference("foo", "bar");
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder.cc
index d0e5ad948a5..b20cbdf9d45 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder.cc
@@ -4,36 +4,41 @@
#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h"
-#include <limits>
-
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_index_conversions.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
namespace quic {
QpackDecoder::QpackDecoder(
- EncoderStreamErrorDelegate* encoder_stream_error_delegate,
- QpackStreamSenderDelegate* decoder_stream_sender_delegate)
+ uint64_t maximum_dynamic_table_capacity,
+ uint64_t maximum_blocked_streams,
+ EncoderStreamErrorDelegate* encoder_stream_error_delegate)
: encoder_stream_error_delegate_(encoder_stream_error_delegate),
encoder_stream_receiver_(this),
- decoder_stream_sender_(decoder_stream_sender_delegate) {
+ maximum_blocked_streams_(maximum_blocked_streams) {
DCHECK(encoder_stream_error_delegate_);
- DCHECK(decoder_stream_sender_delegate);
-}
-
-QpackDecoder::~QpackDecoder() {}
-void QpackDecoder::SetMaximumDynamicTableCapacity(
- uint64_t maximum_dynamic_table_capacity) {
header_table_.SetMaximumDynamicTableCapacity(maximum_dynamic_table_capacity);
}
+QpackDecoder::~QpackDecoder() {}
+
void QpackDecoder::OnStreamReset(QuicStreamId stream_id) {
+ // TODO(bnc): SendStreamCancellation should not be called if maximum dynamic
+ // table capacity is zero.
decoder_stream_sender_.SendStreamCancellation(stream_id);
}
-void QpackDecoder::DecodeEncoderStreamData(QuicStringPiece data) {
- encoder_stream_receiver_.Decode(data);
+bool QpackDecoder::OnStreamBlocked(QuicStreamId stream_id) {
+ auto result = blocked_streams_.insert(stream_id);
+ DCHECK(result.second);
+ return blocked_streams_.size() <= maximum_blocked_streams_;
+}
+
+void QpackDecoder::OnStreamUnblocked(QuicStreamId stream_id) {
+ size_t result = blocked_streams_.erase(stream_id);
+ DCHECK_EQ(1u, result);
}
void QpackDecoder::OnInsertWithNameReference(bool is_static,
@@ -56,7 +61,8 @@ void QpackDecoder::OnInsertWithNameReference(bool is_static,
}
uint64_t absolute_index;
- if (!EncoderStreamRelativeIndexToAbsoluteIndex(name_index, &absolute_index)) {
+ if (!QpackEncoderStreamRelativeIndexToAbsoluteIndex(
+ name_index, header_table_.inserted_entry_count(), &absolute_index)) {
encoder_stream_error_delegate_->OnEncoderStreamError(
"Invalid relative index.");
return;
@@ -87,7 +93,8 @@ void QpackDecoder::OnInsertWithoutNameReference(QuicStringPiece name,
void QpackDecoder::OnDuplicate(uint64_t index) {
uint64_t absolute_index;
- if (!EncoderStreamRelativeIndexToAbsoluteIndex(index, &absolute_index)) {
+ if (!QpackEncoderStreamRelativeIndexToAbsoluteIndex(
+ index, header_table_.inserted_entry_count(), &absolute_index)) {
encoder_stream_error_delegate_->OnEncoderStreamError(
"Invalid relative index.");
return;
@@ -118,24 +125,11 @@ void QpackDecoder::OnErrorDetected(QuicStringPiece error_message) {
encoder_stream_error_delegate_->OnEncoderStreamError(error_message);
}
-bool QpackDecoder::EncoderStreamRelativeIndexToAbsoluteIndex(
- uint64_t relative_index,
- uint64_t* absolute_index) const {
- if (relative_index == std::numeric_limits<uint64_t>::max() ||
- relative_index + 1 > std::numeric_limits<uint64_t>::max() -
- header_table_.inserted_entry_count()) {
- return false;
- }
-
- *absolute_index = header_table_.inserted_entry_count() - relative_index - 1;
- return true;
-}
-
std::unique_ptr<QpackProgressiveDecoder> QpackDecoder::CreateProgressiveDecoder(
QuicStreamId stream_id,
QpackProgressiveDecoder::HeadersHandlerInterface* handler) {
return QuicMakeUnique<QpackProgressiveDecoder>(
- stream_id, &header_table_, &decoder_stream_sender_, handler);
+ stream_id, this, &header_table_, &decoder_stream_sender_, handler);
}
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h
index 9f8a3e38de1..102fbc4c41e 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h
@@ -7,6 +7,7 @@
#include <cstdint>
#include <memory>
+#include <set>
#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender.h"
#include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_receiver.h"
@@ -22,7 +23,8 @@ namespace quic {
// This class vends a new QpackProgressiveDecoder instance for each new header
// list to be encoded.
class QUIC_EXPORT_PRIVATE QpackDecoder
- : public QpackEncoderStreamReceiver::Delegate {
+ : public QpackEncoderStreamReceiver::Delegate,
+ public QpackProgressiveDecoder::BlockedStreamLimitEnforcer {
public:
// Interface for receiving notification that an error has occurred on the
// encoder stream. This MUST be treated as a connection error of type
@@ -34,14 +36,11 @@ class QUIC_EXPORT_PRIVATE QpackDecoder
virtual void OnEncoderStreamError(QuicStringPiece error_message) = 0;
};
- QpackDecoder(EncoderStreamErrorDelegate* encoder_stream_error_delegate,
- QpackStreamSenderDelegate* decoder_stream_sender_delegate);
+ QpackDecoder(uint64_t maximum_dynamic_table_capacity,
+ uint64_t maximum_blocked_streams,
+ EncoderStreamErrorDelegate* encoder_stream_error_delegate);
~QpackDecoder() override;
- // Set maximum capacity of dynamic table.
- // This method must only be called at most once.
- void SetMaximumDynamicTableCapacity(uint64_t maximum_dynamic_table_capacity);
-
// Signal to the peer's encoder that a stream is reset. This lets the peer's
// encoder know that no more header blocks will be processed on this stream,
// therefore references to dynamic table entries shall not prevent their
@@ -60,6 +59,10 @@ class QUIC_EXPORT_PRIVATE QpackDecoder
// using the FIN bit.
void OnStreamReset(QuicStreamId stream_id);
+ // QpackProgressiveDecoder::BlockedStreamLimitEnforcer implementation.
+ bool OnStreamBlocked(QuicStreamId stream_id) override;
+ void OnStreamUnblocked(QuicStreamId stream_id) override;
+
// Factory method to create a QpackProgressiveDecoder for decoding a header
// block. |handler| must remain valid until the returned
// QpackProgressiveDecoder instance is destroyed or the decoder calls
@@ -68,9 +71,6 @@ class QUIC_EXPORT_PRIVATE QpackDecoder
QuicStreamId stream_id,
QpackProgressiveDecoder::HeadersHandlerInterface* handler);
- // Decode data received on the encoder stream.
- void DecodeEncoderStreamData(QuicStringPiece data);
-
// QpackEncoderStreamReceiver::Delegate implementation
void OnInsertWithNameReference(bool is_static,
uint64_t name_index,
@@ -81,19 +81,22 @@ class QUIC_EXPORT_PRIVATE QpackDecoder
void OnSetDynamicTableCapacity(uint64_t capacity) override;
void OnErrorDetected(QuicStringPiece error_message) override;
- private:
- // The encoder stream uses relative index (but different from the kind of
- // relative index used on a request stream). This method converts relative
- // index to absolute index (zero based). It returns true on success, or false
- // if conversion fails due to overflow/underflow.
- bool EncoderStreamRelativeIndexToAbsoluteIndex(
- uint64_t relative_index,
- uint64_t* absolute_index) const;
+ // delegate must be set if dynamic table capacity is not zero.
+ void set_qpack_stream_sender_delegate(QpackStreamSenderDelegate* delegate) {
+ decoder_stream_sender_.set_qpack_stream_sender_delegate(delegate);
+ }
+
+ QpackStreamReceiver* encoder_stream_receiver() {
+ return &encoder_stream_receiver_;
+ }
+ private:
EncoderStreamErrorDelegate* const encoder_stream_error_delegate_;
QpackEncoderStreamReceiver encoder_stream_receiver_;
QpackDecoderStreamSender decoder_stream_sender_;
QpackHeaderTable header_table_;
+ std::set<QuicStreamId> blocked_streams_;
+ const uint64_t maximum_blocked_streams_;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender.cc
index 63f17219928..7f3f346ca5d 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender.cc
@@ -13,11 +13,7 @@
namespace quic {
-QpackDecoderStreamSender::QpackDecoderStreamSender(
- QpackStreamSenderDelegate* delegate)
- : delegate_(delegate) {
- DCHECK(delegate_);
-}
+QpackDecoderStreamSender::QpackDecoderStreamSender() : delegate_(nullptr) {}
void QpackDecoderStreamSender::SendInsertCountIncrement(uint64_t increment) {
values_.varint = increment;
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender.h
index 5f17744f207..6bf466f9276 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender.h
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender.h
@@ -19,8 +19,7 @@ namespace quic {
// stream.
class QUIC_EXPORT_PRIVATE QpackDecoderStreamSender {
public:
- explicit QpackDecoderStreamSender(QpackStreamSenderDelegate* delegate);
- QpackDecoderStreamSender() = delete;
+ QpackDecoderStreamSender();
QpackDecoderStreamSender(const QpackDecoderStreamSender&) = delete;
QpackDecoderStreamSender& operator=(const QpackDecoderStreamSender&) = delete;
@@ -34,8 +33,13 @@ class QUIC_EXPORT_PRIVATE QpackDecoderStreamSender {
// 5.3.3 Stream Cancellation
void SendStreamCancellation(QuicStreamId stream_id);
+ // delegate must be set if dynamic table capacity is not zero.
+ void set_qpack_stream_sender_delegate(QpackStreamSenderDelegate* delegate) {
+ delegate_ = delegate;
+ }
+
private:
- QpackStreamSenderDelegate* const delegate_;
+ QpackStreamSenderDelegate* delegate_;
QpackInstructionEncoder instruction_encoder_;
QpackInstructionEncoder::Values values_;
};
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender_test.cc
index 49483f7f37d..ccb42a3c25d 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender_test.cc
@@ -17,7 +17,9 @@ namespace {
class QpackDecoderStreamSenderTest : public QuicTest {
protected:
- QpackDecoderStreamSenderTest() : stream_(&delegate_) {}
+ QpackDecoderStreamSenderTest() {
+ stream_.set_qpack_stream_sender_delegate(&delegate_);
+ }
~QpackDecoderStreamSenderTest() override = default;
StrictMock<MockQpackStreamSenderDelegate> delegate_;
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 af3a6a250c1..ef711b969fb 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
@@ -26,25 +26,34 @@ namespace {
// Header Acknowledgement decoder stream instruction with stream_id = 1.
const char* const kHeaderAcknowledgement = "\x81";
+const uint64_t kMaximumDynamicTableCapacity = 1024;
+const uint64_t kMaximumBlockedStreams = 1;
+
class QpackDecoderTest : public QuicTestWithParam<FragmentMode> {
protected:
QpackDecoderTest()
- : qpack_decoder_(&encoder_stream_error_delegate_,
- &decoder_stream_sender_delegate_),
+ : qpack_decoder_(kMaximumDynamicTableCapacity,
+ kMaximumBlockedStreams,
+ &encoder_stream_error_delegate_),
fragment_mode_(GetParam()) {
- qpack_decoder_.SetMaximumDynamicTableCapacity(1024);
+ qpack_decoder_.set_qpack_stream_sender_delegate(
+ &decoder_stream_sender_delegate_);
}
~QpackDecoderTest() override = default;
void DecodeEncoderStreamData(QuicStringPiece data) {
- qpack_decoder_.DecodeEncoderStreamData(data);
+ qpack_decoder_.encoder_stream_receiver()->Decode(data);
+ }
+
+ std::unique_ptr<QpackProgressiveDecoder> CreateProgressiveDecoder(
+ QuicStreamId stream_id) {
+ return qpack_decoder_.CreateProgressiveDecoder(stream_id, &handler_);
}
// Set up |progressive_decoder_|.
void StartDecoding() {
- progressive_decoder_ =
- qpack_decoder_.CreateProgressiveDecoder(/* stream_id = */ 1, &handler_);
+ progressive_decoder_ = CreateProgressiveDecoder(/* stream_id = */ 1);
}
// Pass header block data to QpackProgressiveDecoder::Decode()
@@ -98,8 +107,6 @@ TEST_P(QpackDecoderTest, NoPrefix) {
TEST_P(QpackDecoderTest, EmptyHeaderBlock) {
EXPECT_CALL(handler_, OnDecodingCompleted());
- EXPECT_CALL(decoder_stream_sender_delegate_,
- WriteStreamData(Eq(kHeaderAcknowledgement)));
DecodeHeaderBlock(QuicTextUtils::HexDecode("0000"));
}
@@ -107,8 +114,6 @@ TEST_P(QpackDecoderTest, EmptyHeaderBlock) {
TEST_P(QpackDecoderTest, LiteralEntryEmptyName) {
EXPECT_CALL(handler_, OnHeaderDecoded(Eq(""), Eq("foo")));
EXPECT_CALL(handler_, OnDecodingCompleted());
- EXPECT_CALL(decoder_stream_sender_delegate_,
- WriteStreamData(Eq(kHeaderAcknowledgement)));
DecodeHeaderBlock(QuicTextUtils::HexDecode("00002003666f6f"));
}
@@ -116,8 +121,6 @@ TEST_P(QpackDecoderTest, LiteralEntryEmptyName) {
TEST_P(QpackDecoderTest, LiteralEntryEmptyValue) {
EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("")));
EXPECT_CALL(handler_, OnDecodingCompleted());
- EXPECT_CALL(decoder_stream_sender_delegate_,
- WriteStreamData(Eq(kHeaderAcknowledgement)));
DecodeHeaderBlock(QuicTextUtils::HexDecode("000023666f6f00"));
}
@@ -125,8 +128,6 @@ TEST_P(QpackDecoderTest, LiteralEntryEmptyValue) {
TEST_P(QpackDecoderTest, LiteralEntryEmptyNameAndValue) {
EXPECT_CALL(handler_, OnHeaderDecoded(Eq(""), Eq("")));
EXPECT_CALL(handler_, OnDecodingCompleted());
- EXPECT_CALL(decoder_stream_sender_delegate_,
- WriteStreamData(Eq(kHeaderAcknowledgement)));
DecodeHeaderBlock(QuicTextUtils::HexDecode("00002000"));
}
@@ -134,8 +135,6 @@ TEST_P(QpackDecoderTest, LiteralEntryEmptyNameAndValue) {
TEST_P(QpackDecoderTest, SimpleLiteralEntry) {
EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("bar")));
EXPECT_CALL(handler_, OnDecodingCompleted());
- EXPECT_CALL(decoder_stream_sender_delegate_,
- WriteStreamData(Eq(kHeaderAcknowledgement)));
DecodeHeaderBlock(QuicTextUtils::HexDecode("000023666f6f03626172"));
}
@@ -145,8 +144,6 @@ TEST_P(QpackDecoderTest, MultipleLiteralEntries) {
std::string str(127, 'a');
EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foobaar"), QuicStringPiece(str)));
EXPECT_CALL(handler_, OnDecodingCompleted());
- EXPECT_CALL(decoder_stream_sender_delegate_,
- WriteStreamData(Eq(kHeaderAcknowledgement)));
DecodeHeaderBlock(QuicTextUtils::HexDecode(
"0000" // prefix
@@ -204,8 +201,6 @@ TEST_P(QpackDecoderTest, IncompleteHeaderBlock) {
TEST_P(QpackDecoderTest, HuffmanSimple) {
EXPECT_CALL(handler_, OnHeaderDecoded(Eq("custom-key"), Eq("custom-value")));
EXPECT_CALL(handler_, OnDecodingCompleted());
- EXPECT_CALL(decoder_stream_sender_delegate_,
- WriteStreamData(Eq(kHeaderAcknowledgement)));
DecodeHeaderBlock(
QuicTextUtils::HexDecode("00002f0125a849e95ba97d7f8925a849e95bb8e8b4bf"));
@@ -215,8 +210,6 @@ TEST_P(QpackDecoderTest, AlternatingHuffmanNonHuffman) {
EXPECT_CALL(handler_, OnHeaderDecoded(Eq("custom-key"), Eq("custom-value")))
.Times(4);
EXPECT_CALL(handler_, OnDecodingCompleted());
- EXPECT_CALL(decoder_stream_sender_delegate_,
- WriteStreamData(Eq(kHeaderAcknowledgement)));
DecodeHeaderBlock(QuicTextUtils::HexDecode(
"0000" // Prefix.
@@ -289,8 +282,6 @@ TEST_P(QpackDecoderTest, StaticTable) {
EXPECT_CALL(handler_, OnHeaderDecoded(Eq("location"), Eq("foo")));
EXPECT_CALL(handler_, OnDecodingCompleted());
- EXPECT_CALL(decoder_stream_sender_delegate_,
- WriteStreamData(Eq(kHeaderAcknowledgement)));
DecodeHeaderBlock(QuicTextUtils::HexDecode(
"0000d1dfccd45f108621e9aec2a11f5c8294e75f000554524143455f1000"));
@@ -310,6 +301,7 @@ TEST_P(QpackDecoderTest, TooHighStaticTableIndex) {
TEST_P(QpackDecoderTest, DynamicTable) {
DecodeEncoderStreamData(QuicTextUtils::HexDecode(
+ "3fe107" // Set dynamic table capacity to 1024.
"6294e703626172" // Add literal entry with name "foo" and value "bar".
"80035a5a5a" // Add entry with name of dynamic table entry index 0
// (relative index) and value "ZZZ".
@@ -391,6 +383,8 @@ TEST_P(QpackDecoderTest, DynamicTable) {
}
TEST_P(QpackDecoderTest, DecreasingDynamicTableCapacityEvictsEntries) {
+ // Set dynamic table capacity to 1024.
+ DecodeEncoderStreamData(QuicTextUtils::HexDecode("3fe107"));
// Add literal entry with name "foo" and value "bar".
DecodeEncoderStreamData(QuicTextUtils::HexDecode("6294e703626172"));
@@ -437,9 +431,10 @@ TEST_P(QpackDecoderTest, EncoderStreamErrorInvalidStaticTableEntry) {
TEST_P(QpackDecoderTest, EncoderStreamErrorInvalidDynamicTableEntry) {
EXPECT_CALL(encoder_stream_error_delegate_,
- OnEncoderStreamError(Eq("Dynamic table entry not found.")));
+ OnEncoderStreamError(Eq("Invalid relative index.")));
DecodeEncoderStreamData(QuicTextUtils::HexDecode(
+ "3fe107" // Set dynamic table capacity to 1024.
"6294e703626172" // Add literal entry with name "foo" and value "bar".
"8100")); // Address dynamic table entry with relative index 1. Such
// entry does not exist. The most recently added and only
@@ -448,9 +443,10 @@ TEST_P(QpackDecoderTest, EncoderStreamErrorInvalidDynamicTableEntry) {
TEST_P(QpackDecoderTest, EncoderStreamErrorDuplicateInvalidEntry) {
EXPECT_CALL(encoder_stream_error_delegate_,
- OnEncoderStreamError(Eq("Dynamic table entry not found.")));
+ OnEncoderStreamError(Eq("Invalid relative index.")));
DecodeEncoderStreamData(QuicTextUtils::HexDecode(
+ "3fe107" // Set dynamic table capacity to 1024.
"6294e703626172" // Add literal entry with name "foo" and value "bar".
"01")); // Duplicate dynamic table entry with relative index 1. Such
// entry does not exist. The most recently added and only
@@ -467,6 +463,8 @@ TEST_P(QpackDecoderTest, EncoderStreamErrorTooLargeInteger) {
TEST_P(QpackDecoderTest, InvalidDynamicEntryWhenBaseIsZero) {
EXPECT_CALL(handler_, OnDecodingErrorDetected(Eq("Invalid relative index.")));
+ // Set dynamic table capacity to 1024.
+ DecodeEncoderStreamData(QuicTextUtils::HexDecode("3fe107"));
// Add literal entry with name "foo" and value "bar".
DecodeEncoderStreamData(QuicTextUtils::HexDecode("6294e703626172"));
@@ -486,6 +484,8 @@ TEST_P(QpackDecoderTest, InvalidNegativeBase) {
}
TEST_P(QpackDecoderTest, InvalidDynamicEntryByRelativeIndex) {
+ // Set dynamic table capacity to 1024.
+ DecodeEncoderStreamData(QuicTextUtils::HexDecode("3fe107"));
// Add literal entry with name "foo" and value "bar".
DecodeEncoderStreamData(QuicTextUtils::HexDecode("6294e703626172"));
@@ -566,7 +566,7 @@ TEST_P(QpackDecoderTest, TableCapacityMustNotExceedMaximum) {
DecodeEncoderStreamData(QuicTextUtils::HexDecode("3fe10f"));
}
-TEST_P(QpackDecoderTest, SetMaximumDynamicTableCapacity) {
+TEST_P(QpackDecoderTest, SetDynamicTableCapacity) {
// Update dynamic table capacity to 128, which does not exceed the maximum.
DecodeEncoderStreamData(QuicTextUtils::HexDecode("3f61"));
}
@@ -594,6 +594,8 @@ TEST_P(QpackDecoderTest, WrappedRequiredInsertCount) {
// Maximum dynamic table capacity is 1024.
// MaxEntries is 1024 / 32 = 32.
+ // Set dynamic table capacity to 1024.
+ DecodeEncoderStreamData(QuicTextUtils::HexDecode("3fe107"));
// Add literal entry with name "foo" and a 600 byte long value. This will fit
// in the dynamic table once but not twice.
DecodeEncoderStreamData(
@@ -620,6 +622,8 @@ TEST_P(QpackDecoderTest, WrappedRequiredInsertCount) {
}
TEST_P(QpackDecoderTest, NonZeroRequiredInsertCountButNoDynamicEntries) {
+ // Set dynamic table capacity to 1024.
+ DecodeEncoderStreamData(QuicTextUtils::HexDecode("3fe107"));
// Add literal entry with name "foo" and value "bar".
DecodeEncoderStreamData(QuicTextUtils::HexDecode("6294e703626172"));
@@ -633,6 +637,8 @@ TEST_P(QpackDecoderTest, NonZeroRequiredInsertCountButNoDynamicEntries) {
}
TEST_P(QpackDecoderTest, AddressEntryNotAllowedByRequiredInsertCount) {
+ // Set dynamic table capacity to 1024.
+ DecodeEncoderStreamData(QuicTextUtils::HexDecode("3fe107"));
// Add literal entry with name "foo" and value "bar".
DecodeEncoderStreamData(QuicTextUtils::HexDecode("6294e703626172"));
@@ -689,6 +695,8 @@ TEST_P(QpackDecoderTest, AddressEntryNotAllowedByRequiredInsertCount) {
}
TEST_P(QpackDecoderTest, PromisedRequiredInsertCountLargerThanActual) {
+ // Set dynamic table capacity to 1024.
+ DecodeEncoderStreamData(QuicTextUtils::HexDecode("3fe107"));
// Add literal entry with name "foo" and value "bar".
DecodeEncoderStreamData(QuicTextUtils::HexDecode("6294e703626172"));
// Duplicate entry twice so that decoding of header blocks with Required
@@ -757,6 +765,8 @@ TEST_P(QpackDecoderTest, BlockedDecoding) {
EXPECT_CALL(decoder_stream_sender_delegate_,
WriteStreamData(Eq(kHeaderAcknowledgement)));
+ // Set dynamic table capacity to 1024.
+ DecodeEncoderStreamData(QuicTextUtils::HexDecode("3fe107"));
// Add literal entry with name "foo" and value "bar".
DecodeEncoderStreamData(QuicTextUtils::HexDecode("6294e703626172"));
}
@@ -776,6 +786,10 @@ TEST_P(QpackDecoderTest, BlockedDecodingUnblockedBeforeEndOfHeaderBlock) {
// the already consumed part of the header block.
EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("bar")));
EXPECT_CALL(handler_, OnHeaderDecoded(Eq(":method"), Eq("GET")));
+
+ // Set dynamic table capacity to 1024.
+ DecodeEncoderStreamData(QuicTextUtils::HexDecode("3fe107"));
+ // Add literal entry with name "foo" and value "bar".
DecodeEncoderStreamData(QuicTextUtils::HexDecode("6294e703626172"));
Mock::VerifyAndClearExpectations(&handler_);
@@ -825,6 +839,21 @@ TEST_P(QpackDecoderTest, BlockedDecodingAndEvictedEntries) {
DecodeEncoderStreamData(QuicTextUtils::HexDecode("6294e70362617a"));
}
+TEST_P(QpackDecoderTest, TooManyBlockedStreams) {
+ // Required Insert Count 1 and Delta Base 0.
+ // Without any dynamic table entries received, decoding is blocked.
+ std::string data = QuicTextUtils::HexDecode("0200");
+
+ auto progressive_decoder1 = CreateProgressiveDecoder(/* stream_id = */ 1);
+ progressive_decoder1->Decode(data);
+
+ EXPECT_CALL(handler_, OnDecodingErrorDetected(Eq(
+ "Limit on number of blocked streams exceeded.")));
+
+ auto progressive_decoder2 = CreateProgressiveDecoder(/* stream_id = */ 2);
+ progressive_decoder2->Decode(data);
+}
+
} // namespace
} // namespace test
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.cc
index 173270d75b6..eaf66648cb0 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.cc
@@ -64,13 +64,16 @@ const std::string& TestHeadersHandler::error_message() const {
}
void QpackDecode(
+ uint64_t maximum_dynamic_table_capacity,
+ uint64_t maximum_blocked_streams,
QpackDecoder::EncoderStreamErrorDelegate* encoder_stream_error_delegate,
QpackStreamSenderDelegate* decoder_stream_sender_delegate,
QpackProgressiveDecoder::HeadersHandlerInterface* handler,
const FragmentSizeGenerator& fragment_size_generator,
QuicStringPiece data) {
- QpackDecoder decoder(encoder_stream_error_delegate,
- decoder_stream_sender_delegate);
+ QpackDecoder decoder(maximum_dynamic_table_capacity, maximum_blocked_streams,
+ encoder_stream_error_delegate);
+ decoder.set_qpack_stream_sender_delegate(decoder_stream_sender_delegate);
auto progressive_decoder =
decoder.CreateProgressiveDecoder(/* stream_id = */ 1, handler);
while (!data.empty()) {
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.h
index d5f494cfd37..6505b60a1fe 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.h
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.h
@@ -89,6 +89,8 @@ class NoOpHeadersHandler
};
void QpackDecode(
+ uint64_t maximum_dynamic_table_capacity,
+ uint64_t maximum_blocked_streams,
QpackDecoder::EncoderStreamErrorDelegate* encoder_stream_error_delegate,
QpackStreamSenderDelegate* decoder_stream_sender_delegate,
QpackProgressiveDecoder::HeadersHandlerInterface* handler,
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.cc
index 3ffe9d07a5f..d1736f81bb6 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.cc
@@ -4,37 +4,112 @@
#include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h"
-#include <list>
+#include <algorithm>
+#include <utility>
#include "net/third_party/quiche/src/quic/core/qpack/qpack_constants.h"
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_index_conversions.h"
#include "net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder.h"
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_required_insert_count.h"
#include "net/third_party/quiche/src/quic/core/qpack/value_splitting_header_list.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h"
namespace quic {
+namespace {
+
+// Fraction to calculate draining index. The oldest |kDrainingFraction| entries
+// will not be referenced in header blocks. A new entry (duplicate or literal
+// with name reference) will be added to the dynamic table instead. This allows
+// the number of references to the draining entry to go to zero faster, so that
+// it can be evicted. See
+// https://quicwg.org/base-drafts/draft-ietf-quic-qpack.html#avoiding-blocked-insertions.
+// TODO(bnc): Fine tune.
+const float kDrainingFraction = 0.25;
+
+} // anonymous namespace
+
QpackEncoder::QpackEncoder(
- DecoderStreamErrorDelegate* decoder_stream_error_delegate,
- QpackStreamSenderDelegate* encoder_stream_sender_delegate)
+ DecoderStreamErrorDelegate* decoder_stream_error_delegate)
: decoder_stream_error_delegate_(decoder_stream_error_delegate),
decoder_stream_receiver_(this),
- encoder_stream_sender_(encoder_stream_sender_delegate) {
+ maximum_blocked_streams_(0) {
DCHECK(decoder_stream_error_delegate_);
- DCHECK(encoder_stream_sender_delegate);
}
QpackEncoder::~QpackEncoder() {}
-std::string QpackEncoder::EncodeHeaderList(
- QuicStreamId /* stream_id */,
- const spdy::SpdyHeaderBlock* header_list) {
- // First pass.
+// static
+QpackEncoder::InstructionWithValues QpackEncoder::EncodeIndexedHeaderField(
+ bool is_static,
+ uint64_t index,
+ QpackBlockingManager::IndexSet* referred_indices) {
+ InstructionWithValues instruction{QpackIndexedHeaderFieldInstruction(), {}};
+ instruction.values.s_bit = is_static;
+ instruction.values.varint = index;
+ // Add |index| to |*referred_indices| only if entry is in the dynamic table.
+ if (!is_static) {
+ referred_indices->insert(index);
+ }
+ return instruction;
+}
- // Encode into |instructions| which will be serialized during the second pass.
- std::list<InstructionWithValues> instructions;
+// static
+QpackEncoder::InstructionWithValues
+QpackEncoder::EncodeLiteralHeaderFieldWithNameReference(
+ bool is_static,
+ uint64_t index,
+ QuicStringPiece value,
+ QpackBlockingManager::IndexSet* referred_indices) {
+ InstructionWithValues instruction{
+ QpackLiteralHeaderFieldNameReferenceInstruction(), {}};
+ instruction.values.s_bit = is_static;
+ instruction.values.varint = index;
+ instruction.values.value = value;
+ // Add |index| to |*referred_indices| only if entry is in the dynamic table.
+ if (!is_static) {
+ referred_indices->insert(index);
+ }
+ return instruction;
+}
+
+// static
+QpackEncoder::InstructionWithValues QpackEncoder::EncodeLiteralHeaderField(
+ QuicStringPiece name,
+ QuicStringPiece value) {
+ InstructionWithValues instruction{QpackLiteralHeaderFieldInstruction(), {}};
+ instruction.values.name = name;
+ instruction.values.value = value;
+ return instruction;
+}
- for (const auto& header : ValueSplittingHeaderList(header_list)) {
+QpackEncoder::Instructions QpackEncoder::FirstPassEncode(
+ const spdy::SpdyHeaderBlock& header_list,
+ QpackBlockingManager::IndexSet* referred_indices) {
+ Instructions instructions;
+ instructions.reserve(header_list.size());
+
+ // The index of the oldest entry that must not be evicted.
+ uint64_t smallest_blocking_index =
+ blocking_manager_.smallest_blocking_index();
+ // Entries with index larger than or equal to |known_received_count| are
+ // blocking.
+ const uint64_t known_received_count =
+ blocking_manager_.known_received_count();
+ // Only entries with index greater than or equal to |draining_index| are
+ // allowed to be referenced.
+ const uint64_t draining_index =
+ header_table_.draining_index(kDrainingFraction);
+ // Blocking references are allowed if the number of blocked streams is less
+ // than the limit.
+ // TODO(b/112770235): Also allow blocking if given stream is already blocked.
+ const bool blocking_allowed =
+ maximum_blocked_streams_ > blocking_manager_.blocked_stream_count();
+
+ for (const auto& header : ValueSplittingHeaderList(&header_list)) {
+ // These strings are owned by |header_list|.
QuicStringPiece name = header.first;
QuicStringPiece value = header.second;
@@ -46,48 +121,172 @@ std::string QpackEncoder::EncodeHeaderList(
switch (match_type) {
case QpackHeaderTable::MatchType::kNameAndValue:
- DCHECK(is_static) << "Dynamic table entries not supported yet.";
+ if (is_static) {
+ // Refer to entry directly.
+ instructions.push_back(
+ EncodeIndexedHeaderField(is_static, index, referred_indices));
+
+ break;
+ }
- instructions.push_back({QpackIndexedHeaderFieldInstruction(), {}});
- instructions.back().values.s_bit = is_static;
- instructions.back().values.varint = index;
+ if (blocking_allowed || index < known_received_count) {
+ if (index >= draining_index) {
+ // If allowed, refer to entry directly.
+ instructions.push_back(
+ EncodeIndexedHeaderField(is_static, index, referred_indices));
+ smallest_blocking_index = std::min(smallest_blocking_index, index);
+
+ break;
+ }
+
+ if (blocking_allowed &&
+ QpackEntry::Size(name, value) <=
+ header_table_.MaxInsertSizeWithoutEvictingGivenEntry(
+ std::min(smallest_blocking_index, index))) {
+ // If allowed, duplicate entry and refer to it.
+ encoder_stream_sender_.SendDuplicate(
+ QpackAbsoluteIndexToEncoderStreamRelativeIndex(
+ index, header_table_.inserted_entry_count()));
+ auto entry = header_table_.InsertEntry(name, value);
+ blocking_manager_.OnReferenceSentOnEncoderStream(
+ entry->InsertionIndex(), index);
+ instructions.push_back(EncodeIndexedHeaderField(
+ is_static, entry->InsertionIndex(), referred_indices));
+ smallest_blocking_index = std::min(smallest_blocking_index, index);
+
+ break;
+ }
+ }
+
+ // Encode entry as string literals.
+ // TODO(b/112770235): Use already acknowledged entry with lower index if
+ // exists.
+ // TODO(b/112770235): Use static entry name with literal value if
+ // dynamic entry exists but cannot be used.
+ instructions.push_back(EncodeLiteralHeaderField(name, value));
break;
+
case QpackHeaderTable::MatchType::kName:
- DCHECK(is_static) << "Dynamic table entries not supported yet.";
+ if (is_static) {
+ if (blocking_allowed &&
+ QpackEntry::Size(name, value) <=
+ header_table_.MaxInsertSizeWithoutEvictingGivenEntry(
+ smallest_blocking_index)) {
+ // If allowed, insert entry into dynamic table and refer to it.
+ encoder_stream_sender_.SendInsertWithNameReference(is_static, index,
+ value);
+ auto entry = header_table_.InsertEntry(name, value);
+ instructions.push_back(EncodeIndexedHeaderField(
+ /* is_static = */ false, entry->InsertionIndex(),
+ referred_indices));
+ smallest_blocking_index = std::min<uint64_t>(
+ smallest_blocking_index, entry->InsertionIndex());
+
+ break;
+ }
+
+ // Emit literal field with name reference.
+ instructions.push_back(EncodeLiteralHeaderFieldWithNameReference(
+ is_static, index, value, referred_indices));
+
+ break;
+ }
+
+ if (blocking_allowed &&
+ QpackEntry::Size(name, value) <=
+ header_table_.MaxInsertSizeWithoutEvictingGivenEntry(
+ std::min(smallest_blocking_index, index))) {
+ // If allowed, insert entry with name reference and refer to it.
+ encoder_stream_sender_.SendInsertWithNameReference(
+ is_static,
+ QpackAbsoluteIndexToEncoderStreamRelativeIndex(
+ index, header_table_.inserted_entry_count()),
+ value);
+ auto entry = header_table_.InsertEntry(name, value);
+ blocking_manager_.OnReferenceSentOnEncoderStream(
+ entry->InsertionIndex(), index);
+ instructions.push_back(EncodeIndexedHeaderField(
+ is_static, entry->InsertionIndex(), referred_indices));
+ smallest_blocking_index = std::min(smallest_blocking_index, index);
+
+ break;
+ }
+
+ if ((blocking_allowed || index < known_received_count) &&
+ index >= draining_index) {
+ // If allowed, refer to entry name directly, with literal value.
+ instructions.push_back(EncodeLiteralHeaderFieldWithNameReference(
+ is_static, index, value, referred_indices));
+ smallest_blocking_index = std::min(smallest_blocking_index, index);
+
+ break;
+ }
- instructions.push_back(
- {QpackLiteralHeaderFieldNameReferenceInstruction(), {}});
- instructions.back().values.s_bit = is_static;
- instructions.back().values.varint = index;
- instructions.back().values.value = value;
+ // Encode entry as string literals.
+ // TODO(b/112770235): Use already acknowledged entry with lower index if
+ // exists.
+ // TODO(b/112770235): Use static entry name with literal value if
+ // dynamic entry exists but cannot be used.
+ instructions.push_back(EncodeLiteralHeaderField(name, value));
break;
+
case QpackHeaderTable::MatchType::kNoMatch:
- instructions.push_back({QpackLiteralHeaderFieldInstruction(), {}});
- instructions.back().values.name = name;
- instructions.back().values.value = value;
+ if (blocking_allowed &&
+ QpackEntry::Size(name, value) <=
+ header_table_.MaxInsertSizeWithoutEvictingGivenEntry(
+ smallest_blocking_index)) {
+ // If allowed, insert entry and refer to it.
+ encoder_stream_sender_.SendInsertWithoutNameReference(name, value);
+ auto entry = header_table_.InsertEntry(name, value);
+ instructions.push_back(EncodeIndexedHeaderField(
+ /* is_static = */ false, entry->InsertionIndex(),
+ referred_indices));
+ smallest_blocking_index = std::min<uint64_t>(smallest_blocking_index,
+ entry->InsertionIndex());
+
+ break;
+ }
+
+ // Encode entry as string literals.
+ instructions.push_back(EncodeLiteralHeaderField(name, value));
break;
}
}
- // Second pass.
+ return instructions;
+}
+
+std::string QpackEncoder::SecondPassEncode(
+ QpackEncoder::Instructions instructions,
+ uint64_t required_insert_count) const {
QpackInstructionEncoder instruction_encoder;
std::string encoded_headers;
// Header block prefix.
- // TODO(bnc): Implement dynamic entries and set Required Insert Count and
- // Delta Base accordingly.
QpackInstructionEncoder::Values values;
- values.varint = 0; // Encoded required insert count.
+ values.varint = QpackEncodeRequiredInsertCount(required_insert_count,
+ header_table_.max_entries());
values.varint2 = 0; // Delta Base.
values.s_bit = false; // Delta Base sign.
+ const uint64_t base = required_insert_count;
instruction_encoder.Encode(QpackPrefixInstruction(), values,
&encoded_headers);
- for (const auto& instruction : instructions) {
+ for (auto& instruction : instructions) {
+ // Dynamic table references must be transformed from absolute to relative
+ // indices.
+ if ((instruction.instruction == QpackIndexedHeaderFieldInstruction() ||
+ instruction.instruction ==
+ QpackLiteralHeaderFieldNameReferenceInstruction()) &&
+ !instruction.values.s_bit) {
+ instruction.values.varint =
+ QpackAbsoluteIndexToRequestStreamRelativeIndex(
+ instruction.values.varint, base);
+ }
instruction_encoder.Encode(instruction.instruction, instruction.values,
&encoded_headers);
}
@@ -95,20 +294,72 @@ std::string QpackEncoder::EncodeHeaderList(
return encoded_headers;
}
-void QpackEncoder::DecodeDecoderStreamData(QuicStringPiece data) {
- decoder_stream_receiver_.Decode(data);
+std::string QpackEncoder::EncodeHeaderList(
+ QuicStreamId stream_id,
+ const spdy::SpdyHeaderBlock& header_list) {
+ // Keep track of all dynamic table indices that this header block refers to so
+ // that it can be passed to QpackBlockingManager.
+ QpackBlockingManager::IndexSet referred_indices;
+
+ // First pass: encode into |instructions|.
+ Instructions instructions = FirstPassEncode(header_list, &referred_indices);
+
+ const uint64_t required_insert_count =
+ referred_indices.empty()
+ ? 0
+ : QpackBlockingManager::RequiredInsertCount(referred_indices);
+ if (!referred_indices.empty()) {
+ blocking_manager_.OnHeaderBlockSent(stream_id, std::move(referred_indices));
+ }
+
+ // Second pass.
+ return SecondPassEncode(std::move(instructions), required_insert_count);
+}
+
+void QpackEncoder::SetMaximumDynamicTableCapacity(
+ uint64_t maximum_dynamic_table_capacity) {
+ header_table_.SetMaximumDynamicTableCapacity(maximum_dynamic_table_capacity);
+}
+
+void QpackEncoder::SetDynamicTableCapacity(uint64_t dynamic_table_capacity) {
+ encoder_stream_sender_.SendSetDynamicTableCapacity(dynamic_table_capacity);
+ bool success = header_table_.SetDynamicTableCapacity(dynamic_table_capacity);
+ DCHECK(success);
+}
+
+void QpackEncoder::SetMaximumBlockedStreams(uint64_t maximum_blocked_streams) {
+ maximum_blocked_streams_ = maximum_blocked_streams;
}
-void QpackEncoder::OnInsertCountIncrement(uint64_t /*increment*/) {
- // TODO(bnc): Implement dynamic table management for encoding.
+void QpackEncoder::OnInsertCountIncrement(uint64_t increment) {
+ if (increment == 0) {
+ decoder_stream_error_delegate_->OnDecoderStreamError(
+ "Invalid increment value 0.");
+ return;
+ }
+
+ blocking_manager_.OnInsertCountIncrement(increment);
+
+ if (blocking_manager_.known_received_count() >
+ header_table_.inserted_entry_count()) {
+ decoder_stream_error_delegate_->OnDecoderStreamError(QuicStrCat(
+ "Increment value ", increment, " raises known received count to ",
+ blocking_manager_.known_received_count(),
+ " exceeding inserted entry count ",
+ header_table_.inserted_entry_count()));
+ }
}
-void QpackEncoder::OnHeaderAcknowledgement(QuicStreamId /*stream_id*/) {
- // TODO(bnc): Implement dynamic table management for encoding.
+void QpackEncoder::OnHeaderAcknowledgement(QuicStreamId stream_id) {
+ if (!blocking_manager_.OnHeaderAcknowledgement(stream_id)) {
+ decoder_stream_error_delegate_->OnDecoderStreamError(
+ QuicStrCat("Header Acknowledgement received for stream ", stream_id,
+ " with no outstanding header blocks."));
+ }
}
-void QpackEncoder::OnStreamCancellation(QuicStreamId /*stream_id*/) {
- // TODO(bnc): Implement dynamic table management for encoding.
+void QpackEncoder::OnStreamCancellation(QuicStreamId stream_id) {
+ blocking_manager_.OnStreamCancellation(stream_id);
}
void QpackEncoder::OnErrorDetected(QuicStringPiece error_message) {
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h
index 39600e89fcd..4aa69c138f1 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h
@@ -8,7 +8,9 @@
#include <cstdint>
#include <memory>
#include <string>
+#include <vector>
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.h"
#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_receiver.h"
#include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.h"
#include "net/third_party/quiche/src/quic/core/qpack/qpack_header_table.h"
@@ -20,10 +22,16 @@ namespace spdy {
class SpdyHeaderBlock;
-}
+} // namespace spdy
namespace quic {
+namespace test {
+
+class QpackEncoderPeer;
+
+} // namespace test
+
// QPACK encoder class. Exactly one instance should exist per QUIC connection.
class QUIC_EXPORT_PRIVATE QpackEncoder
: public QpackDecoderStreamReceiver::Delegate {
@@ -38,16 +46,27 @@ class QUIC_EXPORT_PRIVATE QpackEncoder
virtual void OnDecoderStreamError(QuicStringPiece error_message) = 0;
};
- QpackEncoder(DecoderStreamErrorDelegate* decoder_stream_error_delegate,
- QpackStreamSenderDelegate* encoder_stream_sender_delegate);
+ QpackEncoder(DecoderStreamErrorDelegate* decoder_stream_error_delegate);
~QpackEncoder() override;
// Encode a header list.
std::string EncodeHeaderList(QuicStreamId stream_id,
- const spdy::SpdyHeaderBlock* header_list);
+ const spdy::SpdyHeaderBlock& header_list);
+
+ // Set maximum dynamic table capacity to |maximum_dynamic_table_capacity|,
+ // measured in bytes. Called when SETTINGS_QPACK_MAX_TABLE_CAPACITY is
+ // received. Encoder needs to know this value so that it can calculate
+ // MaxEntries, used as a modulus to encode Required Insert Count.
+ void SetMaximumDynamicTableCapacity(uint64_t maximum_dynamic_table_capacity);
- // Decode data received on the decoder stream.
- void DecodeDecoderStreamData(QuicStringPiece data);
+ // Set dynamic table capacity to |dynamic_table_capacity|.
+ // |dynamic_table_capacity| must not exceed maximum dynamic table capacity.
+ // Also sends Set Dynamic Table Capacity instruction on encoder stream.
+ void SetDynamicTableCapacity(uint64_t dynamic_table_capacity);
+
+ // Set maximum number of blocked streams.
+ // Called when SETTINGS_QPACK_BLOCKED_STREAMS is received.
+ void SetMaximumBlockedStreams(uint64_t maximum_blocked_streams);
// QpackDecoderStreamReceiver::Delegate implementation
void OnInsertCountIncrement(uint64_t increment) override;
@@ -55,7 +74,18 @@ class QUIC_EXPORT_PRIVATE QpackEncoder
void OnStreamCancellation(QuicStreamId stream_id) override;
void OnErrorDetected(QuicStringPiece error_message) override;
+ // delegate must be set if dynamic table capacity is not zero.
+ void set_qpack_stream_sender_delegate(QpackStreamSenderDelegate* delegate) {
+ encoder_stream_sender_.set_qpack_stream_sender_delegate(delegate);
+ }
+
+ QpackStreamReceiver* decoder_stream_receiver() {
+ return &decoder_stream_receiver_;
+ }
+
private:
+ friend class test::QpackEncoderPeer;
+
// TODO(bnc): Consider moving this class to QpackInstructionEncoder or
// qpack_constants, adding factory methods, one for each instruction, and
// changing QpackInstructionEncoder::Encoder() to take an
@@ -66,11 +96,51 @@ class QUIC_EXPORT_PRIVATE QpackEncoder
const QpackInstruction* instruction;
QpackInstructionEncoder::Values values;
};
+ using Instructions = std::vector<InstructionWithValues>;
+
+ // Generate indexed header field instruction
+ // and optionally update |*referred_indices|.
+ static InstructionWithValues EncodeIndexedHeaderField(
+ bool is_static,
+ uint64_t index,
+ QpackBlockingManager::IndexSet* referred_indices);
+
+ // Generate literal header field with name reference instruction
+ // and optionally update |*referred_indices|.
+ static InstructionWithValues EncodeLiteralHeaderFieldWithNameReference(
+ bool is_static,
+ uint64_t index,
+ QuicStringPiece value,
+ QpackBlockingManager::IndexSet* referred_indices);
+
+ // Generate literal header field instruction.
+ static InstructionWithValues EncodeLiteralHeaderField(QuicStringPiece name,
+ QuicStringPiece value);
+
+ // Performs first pass of two-pass encoding: represent each header field in
+ // |*header_list| as a reference to an existing entry, the name of an existing
+ // entry with a literal value, or a literal name and value pair. Sends
+ // necessary instructions on the encoder stream. Records absolute indices of
+ // referred dynamic table entries in |*referred_indices|. Returns list of
+ // header field representations, with all dynamic table entries referred to
+ // with absolute indices. Returned Instructions object may have
+ // QuicStringPieces pointing to strings owned by |*header_list|.
+ Instructions FirstPassEncode(
+ const spdy::SpdyHeaderBlock& header_list,
+ QpackBlockingManager::IndexSet* referred_indices);
+
+ // Performs second pass of two-pass encoding: serializes representations
+ // generated in first pass, transforming absolute indices of dynamic table
+ // entries to relative indices.
+ std::string SecondPassEncode(Instructions instructions,
+ uint64_t required_insert_count) const;
DecoderStreamErrorDelegate* const decoder_stream_error_delegate_;
QpackDecoderStreamReceiver decoder_stream_receiver_;
QpackEncoderStreamSender encoder_stream_sender_;
QpackHeaderTable header_table_;
+ uint64_t maximum_blocked_streams_;
+ QpackBlockingManager blocking_manager_;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.cc
index dce183ae17b..e6209fd2c5c 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.cc
@@ -13,11 +13,7 @@
namespace quic {
-QpackEncoderStreamSender::QpackEncoderStreamSender(
- QpackStreamSenderDelegate* delegate)
- : delegate_(delegate) {
- DCHECK(delegate_);
-}
+QpackEncoderStreamSender::QpackEncoderStreamSender() : delegate_(nullptr) {}
void QpackEncoderStreamSender::SendInsertWithNameReference(
bool is_static,
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.h
index bf3a79fc0a1..3c410d570b0 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.h
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.h
@@ -17,8 +17,7 @@ namespace quic {
// This class serializes instructions for transmission on the encoder stream.
class QUIC_EXPORT_PRIVATE QpackEncoderStreamSender {
public:
- explicit QpackEncoderStreamSender(QpackStreamSenderDelegate* delegate);
- QpackEncoderStreamSender() = delete;
+ QpackEncoderStreamSender();
QpackEncoderStreamSender(const QpackEncoderStreamSender&) = delete;
QpackEncoderStreamSender& operator=(const QpackEncoderStreamSender&) = delete;
@@ -37,8 +36,13 @@ class QUIC_EXPORT_PRIVATE QpackEncoderStreamSender {
// 5.2.4. Set Dynamic Table Capacity
void SendSetDynamicTableCapacity(uint64_t capacity);
+ // delegate must be set if dynamic table capacity is not zero.
+ void set_qpack_stream_sender_delegate(QpackStreamSenderDelegate* delegate) {
+ delegate_ = delegate;
+ }
+
private:
- QpackStreamSenderDelegate* const delegate_;
+ QpackStreamSenderDelegate* delegate_;
QpackInstructionEncoder instruction_encoder_;
QpackInstructionEncoder::Values values_;
};
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender_test.cc
index 01f1cbf4992..4a15d1f2ca1 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender_test.cc
@@ -17,7 +17,9 @@ namespace {
class QpackEncoderStreamSenderTest : public QuicTest {
protected:
- QpackEncoderStreamSenderTest() : stream_(&delegate_) {}
+ QpackEncoderStreamSenderTest() {
+ stream_.set_qpack_stream_sender_delegate(&delegate_);
+ }
~QpackEncoderStreamSenderTest() override = default;
StrictMock<MockQpackStreamSenderDelegate> delegate_;
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test.cc
index 544b6701f64..0da6f3eb3a3 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test.cc
@@ -7,10 +7,14 @@
#include <string>
#include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test_utils.h"
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.h"
#include "net/third_party/quiche/src/quic/core/qpack/qpack_utils.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
+#include "net/third_party/quiche/src/quic/test_tools/qpack_encoder_peer.h"
+#include "net/third_party/quiche/src/quic/test_tools/qpack_header_table_peer.h"
+using ::testing::_;
using ::testing::Eq;
using ::testing::StrictMock;
using ::testing::Values;
@@ -21,22 +25,25 @@ namespace {
class QpackEncoderTest : public QuicTest {
protected:
- QpackEncoderTest() = default;
+ QpackEncoderTest() : encoder_(&decoder_stream_error_delegate_) {
+ encoder_.set_qpack_stream_sender_delegate(&encoder_stream_sender_delegate_);
+ encoder_.SetMaximumBlockedStreams(1);
+ }
+
~QpackEncoderTest() override = default;
- std::string Encode(const spdy::SpdyHeaderBlock* header_list) {
- QpackEncoder encoder(&decoder_stream_error_delegate_,
- &encoder_stream_sender_delegate_);
- return encoder.EncodeHeaderList(/* stream_id = */ 1, header_list);
+ std::string Encode(const spdy::SpdyHeaderBlock& header_list) {
+ return encoder_.EncodeHeaderList(/* stream_id = */ 1, header_list);
}
StrictMock<MockDecoderStreamErrorDelegate> decoder_stream_error_delegate_;
- NoopQpackStreamSenderDelegate encoder_stream_sender_delegate_;
+ StrictMock<MockQpackStreamSenderDelegate> encoder_stream_sender_delegate_;
+ QpackEncoder encoder_;
};
TEST_F(QpackEncoderTest, Empty) {
spdy::SpdyHeaderBlock header_list;
- std::string output = Encode(&header_list);
+ std::string output = Encode(header_list);
EXPECT_EQ(QuicTextUtils::HexDecode("0000"), output);
}
@@ -44,7 +51,7 @@ TEST_F(QpackEncoderTest, Empty) {
TEST_F(QpackEncoderTest, EmptyName) {
spdy::SpdyHeaderBlock header_list;
header_list[""] = "foo";
- std::string output = Encode(&header_list);
+ std::string output = Encode(header_list);
EXPECT_EQ(QuicTextUtils::HexDecode("0000208294e7"), output);
}
@@ -52,7 +59,7 @@ TEST_F(QpackEncoderTest, EmptyName) {
TEST_F(QpackEncoderTest, EmptyValue) {
spdy::SpdyHeaderBlock header_list;
header_list["foo"] = "";
- std::string output = Encode(&header_list);
+ std::string output = Encode(header_list);
EXPECT_EQ(QuicTextUtils::HexDecode("00002a94e700"), output);
}
@@ -60,7 +67,7 @@ TEST_F(QpackEncoderTest, EmptyValue) {
TEST_F(QpackEncoderTest, EmptyNameAndValue) {
spdy::SpdyHeaderBlock header_list;
header_list[""] = "";
- std::string output = Encode(&header_list);
+ std::string output = Encode(header_list);
EXPECT_EQ(QuicTextUtils::HexDecode("00002000"), output);
}
@@ -68,7 +75,7 @@ TEST_F(QpackEncoderTest, EmptyNameAndValue) {
TEST_F(QpackEncoderTest, Simple) {
spdy::SpdyHeaderBlock header_list;
header_list["foo"] = "bar";
- std::string output = Encode(&header_list);
+ std::string output = Encode(header_list);
EXPECT_EQ(QuicTextUtils::HexDecode("00002a94e703626172"), output);
}
@@ -78,7 +85,7 @@ TEST_F(QpackEncoderTest, Multiple) {
header_list["foo"] = "bar";
// 'Z' would be Huffman encoded to 8 bits, so no Huffman encoding is used.
header_list["ZZZZZZZ"] = std::string(127, 'Z');
- std::string output = Encode(&header_list);
+ std::string output = Encode(header_list);
EXPECT_EQ(
QuicTextUtils::HexDecode(
@@ -102,7 +109,7 @@ TEST_F(QpackEncoderTest, StaticTable) {
header_list["accept-encoding"] = "gzip, deflate, br";
header_list["location"] = "";
- std::string output = Encode(&header_list);
+ std::string output = Encode(header_list);
EXPECT_EQ(QuicTextUtils::HexDecode("0000d1dfcc"), output);
}
{
@@ -111,7 +118,7 @@ TEST_F(QpackEncoderTest, StaticTable) {
header_list["accept-encoding"] = "compress";
header_list["location"] = "foo";
- std::string output = Encode(&header_list);
+ std::string output = Encode(header_list);
EXPECT_EQ(QuicTextUtils::HexDecode("0000d45f108621e9aec2a11f5c8294e7"),
output);
}
@@ -120,7 +127,7 @@ TEST_F(QpackEncoderTest, StaticTable) {
header_list[":method"] = "TRACE";
header_list["accept-encoding"] = "";
- std::string output = Encode(&header_list);
+ std::string output = Encode(header_list);
EXPECT_EQ(QuicTextUtils::HexDecode("00005f000554524143455f1000"), output);
}
}
@@ -129,16 +136,16 @@ TEST_F(QpackEncoderTest, DecoderStreamError) {
EXPECT_CALL(decoder_stream_error_delegate_,
OnDecoderStreamError(Eq("Encoded integer too large.")));
- QpackEncoder encoder(&decoder_stream_error_delegate_,
- &encoder_stream_sender_delegate_);
- encoder.DecodeDecoderStreamData(
+ QpackEncoder encoder(&decoder_stream_error_delegate_);
+ encoder.set_qpack_stream_sender_delegate(&encoder_stream_sender_delegate_);
+ encoder.decoder_stream_receiver()->Decode(
QuicTextUtils::HexDecode("ffffffffffffffffffffff"));
}
TEST_F(QpackEncoderTest, SplitAlongNullCharacter) {
spdy::SpdyHeaderBlock header_list;
header_list["foo"] = QuicStringPiece("bar\0bar\0baz", 11);
- std::string output = Encode(&header_list);
+ std::string output = Encode(header_list);
EXPECT_EQ(QuicTextUtils::HexDecode("0000" // prefix
"2a94e703626172" // foo: bar
@@ -148,6 +155,286 @@ TEST_F(QpackEncoderTest, SplitAlongNullCharacter) {
output);
}
+TEST_F(QpackEncoderTest, ZeroInsertCountIncrement) {
+ // Encoder receives insert count increment with forbidden value 0.
+ EXPECT_CALL(decoder_stream_error_delegate_,
+ OnDecoderStreamError(Eq("Invalid increment value 0.")));
+ encoder_.OnInsertCountIncrement(0);
+}
+
+TEST_F(QpackEncoderTest, TooLargeInsertCountIncrement) {
+ // Encoder receives insert count increment with value that increases Known
+ // Received Count to a value (one) which is larger than the number of dynamic
+ // table insertions sent (zero).
+ EXPECT_CALL(
+ decoder_stream_error_delegate_,
+ OnDecoderStreamError(Eq("Increment value 1 raises known received count "
+ "to 1 exceeding inserted entry count 0")));
+ encoder_.OnInsertCountIncrement(1);
+}
+
+TEST_F(QpackEncoderTest, InvalidHeaderAcknowledgement) {
+ // Encoder receives header acknowledgement for a stream on which no header
+ // block with dynamic table entries was ever sent.
+ EXPECT_CALL(
+ decoder_stream_error_delegate_,
+ OnDecoderStreamError(Eq("Header Acknowledgement received for stream 0 "
+ "with no outstanding header blocks.")));
+ encoder_.OnHeaderAcknowledgement(/* stream_id = */ 0);
+}
+
+TEST_F(QpackEncoderTest, DynamicTable) {
+ encoder_.SetMaximumBlockedStreams(1);
+ encoder_.SetMaximumDynamicTableCapacity(4096);
+
+ // Set Dynamic Table Capacity instruction.
+ EXPECT_CALL(encoder_stream_sender_delegate_,
+ WriteStreamData(Eq(QuicTextUtils::HexDecode("3fe11f"))));
+ encoder_.SetDynamicTableCapacity(4096);
+
+ spdy::SpdyHeaderBlock header_list;
+ header_list["foo"] = "bar";
+ header_list.AppendValueOrAddHeader("foo",
+ "baz"); // name matches dynamic entry
+ header_list["cookie"] = "baz"; // name matches static entry
+
+ // Insert three entries into the dynamic table.
+ EXPECT_CALL(encoder_stream_sender_delegate_,
+ WriteStreamData(Eq(QuicTextUtils::HexDecode(
+ "62" // insert without name reference
+ "94e7" // Huffman-encoded name "foo"
+ "03626172")))); // value "bar"
+ EXPECT_CALL(encoder_stream_sender_delegate_,
+ WriteStreamData(Eq(QuicTextUtils::HexDecode(
+ "80" // insert with name reference, dynamic index 0
+ "0362617a")))); // value "baz"
+ EXPECT_CALL(encoder_stream_sender_delegate_,
+ WriteStreamData(Eq(QuicTextUtils::HexDecode(
+ "c5" // insert with name reference, static index 5
+ "0362617a")))); // value "baz"
+
+ EXPECT_EQ(QuicTextUtils::HexDecode(
+ "0400" // prefix
+ "828180"), // dynamic entries with relative index 0, 1, and 2
+ Encode(header_list));
+}
+
+// There is no room in the dynamic table after inserting the first entry.
+TEST_F(QpackEncoderTest, SmallDynamicTable) {
+ encoder_.SetMaximumBlockedStreams(1);
+ encoder_.SetMaximumDynamicTableCapacity(QpackEntry::Size("foo", "bar"));
+
+ // Set Dynamic Table Capacity instruction.
+ EXPECT_CALL(encoder_stream_sender_delegate_,
+ WriteStreamData(Eq(QuicTextUtils::HexDecode("3f07"))));
+ encoder_.SetDynamicTableCapacity(QpackEntry::Size("foo", "bar"));
+
+ spdy::SpdyHeaderBlock header_list;
+ header_list["foo"] = "bar";
+ header_list.AppendValueOrAddHeader("foo",
+ "baz"); // name matches dynamic entry
+ header_list["cookie"] = "baz"; // name matches static entry
+ header_list["bar"] = "baz"; // no match
+
+ // Insert one entry into the dynamic table.
+ EXPECT_CALL(encoder_stream_sender_delegate_,
+ WriteStreamData(Eq(QuicTextUtils::HexDecode(
+ "62" // insert without name reference
+ "94e7" // Huffman-encoded name "foo"
+ "03626172")))); // value "bar"
+
+ EXPECT_EQ(QuicTextUtils::HexDecode("0200" // prefix
+ "80" // dynamic entry 0
+ "40" // reference to dynamic entry 0 name
+ "0362617a" // with literal value "baz"
+ "55" // reference to static entry 5 name
+ "0362617a" // with literal value "baz"
+ "23626172" // literal name "bar"
+ "0362617a"), // with literal value "baz"
+ Encode(header_list));
+}
+
+TEST_F(QpackEncoderTest, BlockedStream) {
+ encoder_.SetMaximumBlockedStreams(1);
+ encoder_.SetMaximumDynamicTableCapacity(4096);
+
+ // Set Dynamic Table Capacity instruction.
+ EXPECT_CALL(encoder_stream_sender_delegate_,
+ WriteStreamData(Eq(QuicTextUtils::HexDecode("3fe11f"))));
+ encoder_.SetDynamicTableCapacity(4096);
+
+ spdy::SpdyHeaderBlock header_list1;
+ header_list1["foo"] = "bar";
+
+ // Insert one entry into the dynamic table.
+ EXPECT_CALL(encoder_stream_sender_delegate_,
+ WriteStreamData(Eq(QuicTextUtils::HexDecode(
+ "62" // insert without name reference
+ "94e7" // Huffman-encoded name "foo"
+ "03626172")))); // value "bar"
+
+ EXPECT_EQ(QuicTextUtils::HexDecode("0200" // prefix
+ "80"), // dynamic entry 0
+ encoder_.EncodeHeaderList(/* stream_id = */ 1, header_list1));
+
+ // Stream 1 is blocked. Stream 2 is not allowed to block.
+ spdy::SpdyHeaderBlock header_list2;
+ header_list2["foo"] = "bar"; // name and value match dynamic entry
+ header_list2.AppendValueOrAddHeader("foo",
+ "baz"); // name matches dynamic entry
+ header_list2["cookie"] = "baz"; // name matches static entry
+ header_list2["bar"] = "baz"; // no match
+
+ EXPECT_EQ(QuicTextUtils::HexDecode("0000" // prefix
+ "2a94e7" // literal name "foo"
+ "03626172" // with literal value "bar"
+ "2a94e7" // literal name "foo"
+ "0362617a" // with literal value "baz"
+ "55" // name of static entry 5
+ "0362617a" // with literal value "baz"
+ "23626172" // literal name "bar"
+ "0362617a"), // with literal value "baz"
+ encoder_.EncodeHeaderList(/* stream_id = */ 2, header_list2));
+
+ // Peer acknowledges receipt of one dynamic table entry.
+ // Stream 1 is no longer blocked.
+ encoder_.OnInsertCountIncrement(1);
+
+ // Insert three entries into the dynamic table.
+ EXPECT_CALL(encoder_stream_sender_delegate_,
+ WriteStreamData(Eq(QuicTextUtils::HexDecode(
+ "80" // insert with name reference, dynamic index 0
+ "0362617a")))); // value "baz"
+ EXPECT_CALL(encoder_stream_sender_delegate_,
+ WriteStreamData(Eq(QuicTextUtils::HexDecode(
+ "c5" // insert with name reference, static index 5
+ "0362617a")))); // value "baz"
+ EXPECT_CALL(encoder_stream_sender_delegate_,
+ WriteStreamData(Eq(QuicTextUtils::HexDecode(
+ "43" // insert without name reference
+ "626172" // name "bar"
+ "0362617a")))); // value "baz"
+ EXPECT_EQ(QuicTextUtils::HexDecode("0500" // prefix
+ "83828180"), // dynamic entries
+ encoder_.EncodeHeaderList(/* stream_id = */ 3, header_list2));
+
+ // Stream 3 is blocked. Stream 4 is not allowed to block, but it can
+ // reference already acknowledged dynamic entry 0.
+ EXPECT_EQ(QuicTextUtils::HexDecode("0200" // prefix
+ "80" // dynamic entry 0
+ "2a94e7" // literal name "foo"
+ "0362617a" // with literal value "baz"
+ "2c21cfd4c5" // literal name "cookie"
+ "0362617a" // with literal value "baz"
+ "23626172" // literal name "bar"
+ "0362617a"), // with literal value "baz"
+ encoder_.EncodeHeaderList(/* stream_id = */ 4, header_list2));
+
+ // Peer acknowledges receipt of two more dynamic table entries.
+ // Stream 3 is still blocked.
+ encoder_.OnInsertCountIncrement(2);
+
+ // Stream 5 is not allowed to block, but it can reference already acknowledged
+ // dynamic entries 0, 1, and 2.
+ EXPECT_EQ(QuicTextUtils::HexDecode("0400" // prefix
+ "828180" // dynamic entries
+ "23626172" // literal name "bar"
+ "0362617a"), // with literal value "baz"
+ encoder_.EncodeHeaderList(/* stream_id = */ 5, header_list2));
+
+ // Peer acknowledges decoding header block on stream 3.
+ // Stream 3 is not blocked any longer.
+ encoder_.OnHeaderAcknowledgement(3);
+
+ EXPECT_EQ(QuicTextUtils::HexDecode("0500" // prefix
+ "83828180"), // dynamic entries
+ encoder_.EncodeHeaderList(/* stream_id = */ 6, header_list2));
+}
+
+TEST_F(QpackEncoderTest, Draining) {
+ // TODO(b/112770235): Remove when already blocking stream can emit blocking
+ // references.
+ encoder_.SetMaximumBlockedStreams(2);
+
+ spdy::SpdyHeaderBlock header_list1;
+ header_list1["one"] = "foo";
+ header_list1["two"] = "foo";
+ header_list1["three"] = "foo";
+ header_list1["four"] = "foo";
+ header_list1["five"] = "foo";
+ header_list1["six"] = "foo";
+ header_list1["seven"] = "foo";
+ header_list1["eight"] = "foo";
+ header_list1["nine"] = "foo";
+ header_list1["ten"] = "foo";
+
+ // Make just enough room in the dynamic table for the header list plus the
+ // first entry duplicated. This will ensure that the oldest entries are
+ // draining.
+ uint64_t maximum_dynamic_table_capacity = 0;
+ for (const auto& header_field : header_list1) {
+ maximum_dynamic_table_capacity +=
+ QpackEntry::Size(header_field.first, header_field.second);
+ }
+ maximum_dynamic_table_capacity += QpackEntry::Size("one", "foo");
+ encoder_.SetMaximumDynamicTableCapacity(maximum_dynamic_table_capacity);
+
+ // Set Dynamic Table Capacity instruction.
+ EXPECT_CALL(encoder_stream_sender_delegate_, WriteStreamData(_));
+ encoder_.SetDynamicTableCapacity(maximum_dynamic_table_capacity);
+
+ // Insert ten entries into the dynamic table.
+ EXPECT_CALL(encoder_stream_sender_delegate_, WriteStreamData(_)).Times(10);
+
+ EXPECT_EQ(
+ QuicTextUtils::HexDecode("0b00" // prefix
+ "89888786858483828180"), // dynamic entries
+ Encode(header_list1));
+
+ // Entry is identical to oldest one, which is draining. It will be
+ // duplicated and referenced.
+ spdy::SpdyHeaderBlock header_list2;
+ header_list2["one"] = "foo";
+
+ // Duplicate oldest entry.
+ EXPECT_CALL(encoder_stream_sender_delegate_,
+ WriteStreamData(Eq(QuicTextUtils::HexDecode("09"))));
+
+ EXPECT_EQ(QuicTextUtils::HexDecode("0c00" // prefix
+ "80"), // most recent dynamic table entry
+ Encode(header_list2));
+
+ spdy::SpdyHeaderBlock header_list3;
+ // Entry is identical to second oldest one, which is draining. There is no
+ // room to duplicate, it will be encoded with string literals.
+ header_list3.AppendValueOrAddHeader("two", "foo");
+ // Entry has name identical to second oldest one, which is draining. There is
+ // no room to insert new entry, it will be encoded with string literals.
+ header_list3.AppendValueOrAddHeader("two", "bar");
+
+ EXPECT_EQ(QuicTextUtils::HexDecode("0000" // prefix
+ "2374776f" // literal name "two"
+ "8294e7" // literal value "foo"
+ "2374776f" // literal name "two"
+ "03626172"), // literal value "bar"
+ Encode(header_list3));
+}
+
+TEST_F(QpackEncoderTest, DynamicTableCapacityLessThanMaximum) {
+ encoder_.SetMaximumDynamicTableCapacity(1024);
+
+ // Set Dynamic Table Capacity instruction.
+ EXPECT_CALL(encoder_stream_sender_delegate_,
+ WriteStreamData(Eq(QuicTextUtils::HexDecode("3e"))));
+ encoder_.SetDynamicTableCapacity(30);
+
+ QpackHeaderTable* header_table = QpackEncoderPeer::header_table(&encoder_);
+
+ EXPECT_EQ(1024u,
+ QpackHeaderTablePeer::maximum_dynamic_table_capacity(header_table));
+ EXPECT_EQ(30u, QpackHeaderTablePeer::dynamic_table_capacity(header_table));
+}
+
} // namespace
} // namespace test
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.cc
index 6fa64125a1a..bb28f722f3e 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.cc
@@ -141,6 +141,28 @@ const QpackEntry* QpackHeaderTable::InsertEntry(QuicStringPiece name,
return new_entry;
}
+uint64_t QpackHeaderTable::MaxInsertSizeWithoutEvictingGivenEntry(
+ uint64_t index) const {
+ DCHECK_LE(dropped_entry_count_, index);
+
+ if (index > inserted_entry_count()) {
+ // All entries are allowed to be evicted.
+ return dynamic_table_capacity_;
+ }
+
+ // Initialize to current available capacity.
+ uint64_t max_insert_size = dynamic_table_capacity_ - dynamic_table_size_;
+
+ for (const auto& entry : dynamic_entries_) {
+ if (entry.InsertionIndex() >= index) {
+ break;
+ }
+ max_insert_size += entry.Size();
+ }
+
+ return max_insert_size;
+}
+
bool QpackHeaderTable::SetDynamicTableCapacity(uint64_t capacity) {
if (capacity > maximum_dynamic_table_capacity_) {
return false;
@@ -162,7 +184,6 @@ void QpackHeaderTable::SetMaximumDynamicTableCapacity(
DCHECK_EQ(0u, maximum_dynamic_table_capacity_);
DCHECK_EQ(0u, max_entries_);
- dynamic_table_capacity_ = maximum_dynamic_table_capacity;
maximum_dynamic_table_capacity_ = maximum_dynamic_table_capacity;
max_entries_ = maximum_dynamic_table_capacity / 32;
}
@@ -173,6 +194,31 @@ void QpackHeaderTable::RegisterObserver(Observer* observer,
observers_.push({observer, required_insert_count});
}
+uint64_t QpackHeaderTable::draining_index(float draining_fraction) const {
+ DCHECK_LE(0.0, draining_fraction);
+ DCHECK_LE(draining_fraction, 1.0);
+
+ const uint64_t required_space = draining_fraction * dynamic_table_capacity_;
+ uint64_t space_above_draining_index =
+ dynamic_table_capacity_ - dynamic_table_size_;
+
+ if (dynamic_entries_.empty() ||
+ space_above_draining_index >= required_space) {
+ return dropped_entry_count_;
+ }
+
+ auto it = dynamic_entries_.begin();
+ while (space_above_draining_index < required_space) {
+ space_above_draining_index += it->Size();
+ ++it;
+ if (it == dynamic_entries_.end()) {
+ return inserted_entry_count();
+ }
+ }
+
+ return it->InsertionIndex();
+}
+
bool QpackHeaderTable::ObserverWithThreshold::operator>(
const ObserverWithThreshold& other) const {
return required_insert_count > other.required_insert_count;
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.h
index 39d7326758b..f251894f781 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.h
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.h
@@ -17,6 +17,12 @@
namespace quic {
+namespace test {
+
+class QpackHeaderTablePeer;
+
+} // namespace test
+
using QpackEntry = spdy::HpackEntry;
// This class manages the QPACK static and dynamic tables. For dynamic entries,
@@ -70,6 +76,12 @@ class QUIC_EXPORT_PRIVATE QpackHeaderTable {
// is larger than the capacity of the dynamic table.
const QpackEntry* InsertEntry(QuicStringPiece name, QuicStringPiece value);
+ // Returns the size of the largest entry that could be inserted into the
+ // dynamic table without evicting entry |index|. |index| might be larger than
+ // inserted_entry_count(), in which case the capacity of the table is
+ // returned. |index| must not be smaller than dropped_entry_count().
+ uint64_t MaxInsertSizeWithoutEvictingGivenEntry(uint64_t index) const;
+
// Change dynamic table capacity to |capacity|. Returns true on success.
// Returns false is |capacity| exceeds maximum dynamic table capacity.
bool SetDynamicTableCapacity(uint64_t capacity);
@@ -99,7 +111,17 @@ class QUIC_EXPORT_PRIVATE QpackHeaderTable {
// The number of entries dropped from the dynamic table.
uint64_t dropped_entry_count() const { return dropped_entry_count_; }
+ // Returns the draining index described at
+ // https://quicwg.org/base-drafts/draft-ietf-quic-qpack.html#avoiding-blocked-insertions.
+ // Entries with an index larger than or equal to the draining index take up
+ // approximately |1.0 - draining_fraction| of dynamic table capacity. The
+ // remaining capacity is taken up by draining entries and unused space.
+ // The returned index might not be the index of a valid entry.
+ uint64_t draining_index(float draining_fraction) const;
+
private:
+ friend class test::QpackHeaderTablePeer;
+
// Evict entries from the dynamic table until table size is less than or equal
// to current value of |dynamic_table_capacity_|.
void EvictDownToCurrentCapacity();
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table_test.cc
index ff7ef48d4fc..00f36e5286d 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table_test.cc
@@ -30,6 +30,7 @@ class QpackHeaderTableTest : public QuicTest {
QpackHeaderTableTest() {
table_.SetMaximumDynamicTableCapacity(
kMaximumDynamicTableCapacityForTesting);
+ table_.SetDynamicTableCapacity(kMaximumDynamicTableCapacityForTesting);
}
~QpackHeaderTableTest() override = default;
@@ -365,6 +366,56 @@ TEST_F(QpackHeaderTableTest, EvictOldestOfSameName) {
/* expected_is_static = */ false, 2u);
}
+// Returns the size of the largest entry that could be inserted into the
+// dynamic table without evicting entry |index|.
+TEST_F(QpackHeaderTableTest, MaxInsertSizeWithoutEvictingGivenEntry) {
+ const uint64_t dynamic_table_capacity = 100;
+ QpackHeaderTable table;
+ table.SetMaximumDynamicTableCapacity(dynamic_table_capacity);
+ EXPECT_TRUE(table.SetDynamicTableCapacity(dynamic_table_capacity));
+
+ // Empty table can take an entry up to its capacity.
+ EXPECT_EQ(dynamic_table_capacity,
+ table.MaxInsertSizeWithoutEvictingGivenEntry(0));
+
+ const uint64_t entry_size1 = QpackEntry::Size("foo", "bar");
+ EXPECT_TRUE(table.InsertEntry("foo", "bar"));
+ EXPECT_EQ(dynamic_table_capacity - entry_size1,
+ table.MaxInsertSizeWithoutEvictingGivenEntry(0));
+ // Table can take an entry up to its capacity if all entries are allowed to be
+ // evicted.
+ EXPECT_EQ(dynamic_table_capacity,
+ table.MaxInsertSizeWithoutEvictingGivenEntry(1));
+
+ const uint64_t entry_size2 = QpackEntry::Size("baz", "foobar");
+ EXPECT_TRUE(table.InsertEntry("baz", "foobar"));
+ // Table can take an entry up to its capacity if all entries are allowed to be
+ // evicted.
+ EXPECT_EQ(dynamic_table_capacity,
+ table.MaxInsertSizeWithoutEvictingGivenEntry(2));
+ // Second entry must stay.
+ EXPECT_EQ(dynamic_table_capacity - entry_size2,
+ table.MaxInsertSizeWithoutEvictingGivenEntry(1));
+ // First and second entry must stay.
+ EXPECT_EQ(dynamic_table_capacity - entry_size2 - entry_size1,
+ table.MaxInsertSizeWithoutEvictingGivenEntry(0));
+
+ // Third entry evicts first one.
+ const uint64_t entry_size3 = QpackEntry::Size("last", "entry");
+ EXPECT_TRUE(table.InsertEntry("last", "entry"));
+ EXPECT_EQ(1u, table.dropped_entry_count());
+ // Table can take an entry up to its capacity if all entries are allowed to be
+ // evicted.
+ EXPECT_EQ(dynamic_table_capacity,
+ table.MaxInsertSizeWithoutEvictingGivenEntry(3));
+ // Third entry must stay.
+ EXPECT_EQ(dynamic_table_capacity - entry_size3,
+ table.MaxInsertSizeWithoutEvictingGivenEntry(2));
+ // Second and third entry must stay.
+ EXPECT_EQ(dynamic_table_capacity - entry_size3 - entry_size2,
+ table.MaxInsertSizeWithoutEvictingGivenEntry(1));
+}
+
TEST_F(QpackHeaderTableTest, Observer) {
StrictMock<MockObserver> observer1;
RegisterObserver(&observer1, 1);
@@ -404,6 +455,44 @@ TEST_F(QpackHeaderTableTest, Observer) {
Mock::VerifyAndClearExpectations(&observer5);
}
+TEST_F(QpackHeaderTableTest, DrainingIndex) {
+ QpackHeaderTable table;
+ table.SetMaximumDynamicTableCapacity(kMaximumDynamicTableCapacityForTesting);
+ EXPECT_TRUE(
+ table.SetDynamicTableCapacity(4 * QpackEntry::Size("foo", "bar")));
+
+ // Empty table: no draining entry.
+ EXPECT_EQ(0u, table.draining_index(0.0));
+ EXPECT_EQ(0u, table.draining_index(1.0));
+
+ // Table with one entry.
+ EXPECT_TRUE(table.InsertEntry("foo", "bar"));
+ // Any entry can be referenced if none of the table is draining.
+ EXPECT_EQ(0u, table.draining_index(0.0));
+ // No entry can be referenced if all of the table is draining.
+ EXPECT_EQ(1u, table.draining_index(1.0));
+
+ // Table with two entries is at half capacity.
+ EXPECT_TRUE(table.InsertEntry("foo", "bar"));
+ // Any entry can be referenced if at most half of the table is draining,
+ // because current entries only take up half of total capacity.
+ EXPECT_EQ(0u, table.draining_index(0.0));
+ EXPECT_EQ(0u, table.draining_index(0.5));
+ // No entry can be referenced if all of the table is draining.
+ EXPECT_EQ(2u, table.draining_index(1.0));
+
+ // Table with four entries is full.
+ EXPECT_TRUE(table.InsertEntry("foo", "bar"));
+ EXPECT_TRUE(table.InsertEntry("foo", "bar"));
+ // Any entry can be referenced if none of the table is draining.
+ EXPECT_EQ(0u, table.draining_index(0.0));
+ // In a full table with identically sized entries, |draining_fraction| of all
+ // entries are draining.
+ EXPECT_EQ(2u, table.draining_index(0.5));
+ // No entry can be referenced if all of the table is draining.
+ EXPECT_EQ(4u, table.draining_index(1.0));
+}
+
} // namespace
} // namespace test
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_index_conversions.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_index_conversions.cc
new file mode 100644
index 00000000000..8f1d52f6f34
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_index_conversions.cc
@@ -0,0 +1,62 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_index_conversions.h"
+
+#include <limits>
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
+
+namespace quic {
+
+uint64_t QpackAbsoluteIndexToEncoderStreamRelativeIndex(
+ uint64_t absolute_index,
+ uint64_t inserted_entry_count) {
+ DCHECK_LT(absolute_index, inserted_entry_count);
+
+ return inserted_entry_count - absolute_index - 1;
+}
+
+uint64_t QpackAbsoluteIndexToRequestStreamRelativeIndex(uint64_t absolute_index,
+ uint64_t base) {
+ DCHECK_LT(absolute_index, base);
+
+ return base - absolute_index - 1;
+}
+
+bool QpackEncoderStreamRelativeIndexToAbsoluteIndex(
+ uint64_t relative_index,
+ uint64_t inserted_entry_count,
+ uint64_t* absolute_index) {
+ if (relative_index >= inserted_entry_count) {
+ return false;
+ }
+
+ *absolute_index = inserted_entry_count - relative_index - 1;
+ return true;
+}
+
+bool QpackRequestStreamRelativeIndexToAbsoluteIndex(uint64_t relative_index,
+ uint64_t base,
+ uint64_t* absolute_index) {
+ if (relative_index >= base) {
+ return false;
+ }
+
+ *absolute_index = base - relative_index - 1;
+ return true;
+}
+
+bool QpackPostBaseIndexToAbsoluteIndex(uint64_t post_base_index,
+ uint64_t base,
+ uint64_t* absolute_index) {
+ if (post_base_index >= std::numeric_limits<uint64_t>::max() - base) {
+ return false;
+ }
+
+ *absolute_index = base + post_base_index;
+ return true;
+}
+
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_index_conversions.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_index_conversions.h
new file mode 100644
index 00000000000..2348ac70964
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_index_conversions.h
@@ -0,0 +1,59 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Utility methods to convert between absolute indexing (used in the dynamic
+// table), relative indexing used on the encoder stream, and relative indexing
+// and post-base indexing used on request streams (in header blocks). See:
+// https://quicwg.org/base-drafts/draft-ietf-quic-qpack.html#indexing
+// https://quicwg.org/base-drafts/draft-ietf-quic-qpack.html#relative-indexing
+// https://quicwg.org/base-drafts/draft-ietf-quic-qpack.html#post-base
+
+#ifndef QUICHE_QUIC_CORE_QPACK_QPACK_INDEX_CONVERSIONS_H_
+#define QUICHE_QUIC_CORE_QPACK_QPACK_INDEX_CONVERSIONS_H_
+
+#include <cstdint>
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
+
+namespace quic {
+
+// Conversion functions used in the encoder do not check for overflow/underflow.
+// Since the maximum index is limited by maximum dynamic table capacity
+// (represented on uint64_t) divided by minimum header field size (defined to be
+// 32 bytes), overflow is not possible. The caller is responsible for providing
+// input that does not underflow.
+
+QUIC_EXPORT_PRIVATE uint64_t
+QpackAbsoluteIndexToEncoderStreamRelativeIndex(uint64_t absolute_index,
+ uint64_t inserted_entry_count);
+
+QUIC_EXPORT_PRIVATE uint64_t
+QpackAbsoluteIndexToRequestStreamRelativeIndex(uint64_t absolute_index,
+ uint64_t base);
+
+// Conversion functions used in the decoder operate on input received from the
+// network. These functions return false on overflow or underflow.
+
+QUIC_EXPORT_PRIVATE bool QpackEncoderStreamRelativeIndexToAbsoluteIndex(
+ uint64_t relative_index,
+ uint64_t inserted_entry_count,
+ uint64_t* absolute_index);
+
+// On success, |*absolute_index| is guaranteed to be strictly less than
+// std::numeric_limits<uint64_t>::max().
+QUIC_EXPORT_PRIVATE bool QpackRequestStreamRelativeIndexToAbsoluteIndex(
+ uint64_t relative_index,
+ uint64_t base,
+ uint64_t* absolute_index);
+
+// On success, |*absolute_index| is guaranteed to be strictly less than
+// std::numeric_limits<uint64_t>::max().
+QUIC_EXPORT_PRIVATE bool QpackPostBaseIndexToAbsoluteIndex(
+ uint64_t post_base_index,
+ uint64_t base,
+ uint64_t* absolute_index);
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_CORE_QPACK_QPACK_INDEX_CONVERSIONS_H_
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_index_conversions_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_index_conversions_test.cc
new file mode 100644
index 00000000000..214dff5f27d
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_index_conversions_test.cc
@@ -0,0 +1,99 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_index_conversions.h"
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+
+namespace quic {
+namespace test {
+namespace {
+
+struct {
+ uint64_t relative_index;
+ uint64_t inserted_entry_count;
+ uint64_t expected_absolute_index;
+} kEncoderStreamRelativeIndexTestData[] = {{0, 1, 0}, {0, 2, 1}, {1, 2, 0},
+ {0, 10, 9}, {5, 10, 4}, {9, 10, 0}};
+
+TEST(QpackIndexConversions, EncoderStreamRelativeIndex) {
+ for (const auto& test_data : kEncoderStreamRelativeIndexTestData) {
+ uint64_t absolute_index = 42;
+ EXPECT_TRUE(QpackEncoderStreamRelativeIndexToAbsoluteIndex(
+ test_data.relative_index, test_data.inserted_entry_count,
+ &absolute_index));
+ EXPECT_EQ(test_data.expected_absolute_index, absolute_index);
+
+ EXPECT_EQ(test_data.relative_index,
+ QpackAbsoluteIndexToEncoderStreamRelativeIndex(
+ absolute_index, test_data.inserted_entry_count));
+ }
+}
+
+struct {
+ uint64_t relative_index;
+ uint64_t base;
+ uint64_t expected_absolute_index;
+} kRequestStreamRelativeIndexTestData[] = {{0, 1, 0}, {0, 2, 1}, {1, 2, 0},
+ {0, 10, 9}, {5, 10, 4}, {9, 10, 0}};
+
+TEST(QpackIndexConversions, RequestStreamRelativeIndex) {
+ for (const auto& test_data : kRequestStreamRelativeIndexTestData) {
+ uint64_t absolute_index = 42;
+ EXPECT_TRUE(QpackRequestStreamRelativeIndexToAbsoluteIndex(
+ test_data.relative_index, test_data.base, &absolute_index));
+ EXPECT_EQ(test_data.expected_absolute_index, absolute_index);
+
+ EXPECT_EQ(test_data.relative_index,
+ QpackAbsoluteIndexToRequestStreamRelativeIndex(absolute_index,
+ test_data.base));
+ }
+}
+
+struct {
+ uint64_t post_base_index;
+ uint64_t base;
+ uint64_t expected_absolute_index;
+} kPostBaseIndexTestData[] = {{0, 1, 1}, {1, 0, 1}, {2, 0, 2},
+ {1, 1, 2}, {0, 2, 2}, {1, 2, 3}};
+
+TEST(QpackIndexConversions, PostBaseIndex) {
+ for (const auto& test_data : kPostBaseIndexTestData) {
+ uint64_t absolute_index = 42;
+ EXPECT_TRUE(QpackPostBaseIndexToAbsoluteIndex(
+ test_data.post_base_index, test_data.base, &absolute_index));
+ EXPECT_EQ(test_data.expected_absolute_index, absolute_index);
+ }
+}
+
+TEST(QpackIndexConversions, EncoderStreamRelativeIndexUnderflow) {
+ uint64_t absolute_index;
+ EXPECT_FALSE(QpackEncoderStreamRelativeIndexToAbsoluteIndex(
+ /* relative_index = */ 10,
+ /* inserted_entry_count = */ 10, &absolute_index));
+ EXPECT_FALSE(QpackEncoderStreamRelativeIndexToAbsoluteIndex(
+ /* relative_index = */ 12,
+ /* inserted_entry_count = */ 10, &absolute_index));
+}
+
+TEST(QpackIndexConversions, RequestStreamRelativeIndexUnderflow) {
+ uint64_t absolute_index;
+ EXPECT_FALSE(QpackRequestStreamRelativeIndexToAbsoluteIndex(
+ /* relative_index = */ 10,
+ /* base = */ 10, &absolute_index));
+ EXPECT_FALSE(QpackRequestStreamRelativeIndexToAbsoluteIndex(
+ /* relative_index = */ 12,
+ /* base = */ 10, &absolute_index));
+}
+
+TEST(QpackIndexConversions, QpackPostBaseIndexToAbsoluteIndexOverflow) {
+ uint64_t absolute_index;
+ EXPECT_FALSE(QpackPostBaseIndexToAbsoluteIndex(
+ /* post_base_index = */ 20,
+ /* base = */ std::numeric_limits<uint64_t>::max() - 10, &absolute_index));
+}
+
+} // namespace
+} // namespace test
+} // namespace quic
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 e364edc1484..51d98ffa93b 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.cc
@@ -8,6 +8,7 @@
#include <limits>
#include "net/third_party/quiche/src/quic/core/qpack/qpack_constants.h"
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_index_conversions.h"
#include "net/third_party/quiche/src/quic/core/qpack/qpack_required_insert_count.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
@@ -16,6 +17,7 @@ namespace quic {
QpackProgressiveDecoder::QpackProgressiveDecoder(
QuicStreamId stream_id,
+ BlockedStreamLimitEnforcer* enforcer,
QpackHeaderTable* header_table,
QpackDecoderStreamSender* decoder_stream_sender,
HeadersHandlerInterface* handler)
@@ -23,6 +25,7 @@ QpackProgressiveDecoder::QpackProgressiveDecoder(
prefix_decoder_(
QuicMakeUnique<QpackInstructionDecoder>(QpackPrefixLanguage(), this)),
instruction_decoder_(QpackRequestStreamLanguage(), this),
+ enforcer_(enforcer),
header_table_(header_table),
decoder_stream_sender_(decoder_stream_sender),
handler_(handler),
@@ -116,6 +119,7 @@ void QpackProgressiveDecoder::OnInsertCountReachedThreshold() {
}
blocked_ = false;
+ enforcer_->OnStreamUnblocked(stream_id_);
if (!decoding_) {
FinishDecoding();
@@ -125,8 +129,8 @@ void QpackProgressiveDecoder::OnInsertCountReachedThreshold() {
bool QpackProgressiveDecoder::DoIndexedHeaderFieldInstruction() {
if (!instruction_decoder_.s_bit()) {
uint64_t absolute_index;
- if (!RequestStreamRelativeIndexToAbsoluteIndex(
- instruction_decoder_.varint(), &absolute_index)) {
+ if (!QpackRequestStreamRelativeIndexToAbsoluteIndex(
+ instruction_decoder_.varint(), base_, &absolute_index)) {
OnError("Invalid relative index.");
return false;
}
@@ -164,8 +168,8 @@ bool QpackProgressiveDecoder::DoIndexedHeaderFieldInstruction() {
bool QpackProgressiveDecoder::DoIndexedHeaderFieldPostBaseInstruction() {
uint64_t absolute_index;
- if (!PostBaseIndexToAbsoluteIndex(instruction_decoder_.varint(),
- &absolute_index)) {
+ if (!QpackPostBaseIndexToAbsoluteIndex(instruction_decoder_.varint(), base_,
+ &absolute_index)) {
OnError("Invalid post-base index.");
return false;
}
@@ -193,8 +197,8 @@ bool QpackProgressiveDecoder::DoIndexedHeaderFieldPostBaseInstruction() {
bool QpackProgressiveDecoder::DoLiteralHeaderFieldNameReferenceInstruction() {
if (!instruction_decoder_.s_bit()) {
uint64_t absolute_index;
- if (!RequestStreamRelativeIndexToAbsoluteIndex(
- instruction_decoder_.varint(), &absolute_index)) {
+ if (!QpackRequestStreamRelativeIndexToAbsoluteIndex(
+ instruction_decoder_.varint(), base_, &absolute_index)) {
OnError("Invalid relative index.");
return false;
}
@@ -232,8 +236,8 @@ bool QpackProgressiveDecoder::DoLiteralHeaderFieldNameReferenceInstruction() {
bool QpackProgressiveDecoder::DoLiteralHeaderFieldPostBaseInstruction() {
uint64_t absolute_index;
- if (!PostBaseIndexToAbsoluteIndex(instruction_decoder_.varint(),
- &absolute_index)) {
+ if (!QpackPostBaseIndexToAbsoluteIndex(instruction_decoder_.varint(), base_,
+ &absolute_index)) {
OnError("Invalid post-base index.");
return false;
}
@@ -286,6 +290,10 @@ bool QpackProgressiveDecoder::DoPrefixInstruction() {
if (required_insert_count_ > header_table_->inserted_entry_count()) {
blocked_ = true;
+ if (!enforcer_->OnStreamBlocked(stream_id_)) {
+ OnError("Limit on number of blocked streams exceeded.");
+ return false;
+ }
header_table_->RegisterObserver(this, required_insert_count_);
}
@@ -316,7 +324,10 @@ void QpackProgressiveDecoder::FinishDecoding() {
return;
}
- decoder_stream_sender_->SendHeaderAcknowledgement(stream_id_);
+ if (required_insert_count_ > 0) {
+ decoder_stream_sender_->SendHeaderAcknowledgement(stream_id_);
+ }
+
handler_->OnDecodingCompleted();
}
@@ -340,27 +351,4 @@ bool QpackProgressiveDecoder::DeltaBaseToBase(bool sign,
return true;
}
-bool QpackProgressiveDecoder::RequestStreamRelativeIndexToAbsoluteIndex(
- uint64_t relative_index,
- uint64_t* absolute_index) const {
- if (relative_index == std::numeric_limits<uint64_t>::max() ||
- relative_index + 1 > base_) {
- return false;
- }
-
- *absolute_index = base_ - 1 - relative_index;
- return true;
-}
-
-bool QpackProgressiveDecoder::PostBaseIndexToAbsoluteIndex(
- uint64_t post_base_index,
- uint64_t* absolute_index) const {
- if (post_base_index >= std::numeric_limits<uint64_t>::max() - base_) {
- return false;
- }
-
- *absolute_index = base_ + post_base_index;
- return true;
-}
-
} // namespace quic
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 3abf4279fa2..5c116b1d525 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
@@ -49,8 +49,26 @@ class QUIC_EXPORT_PRIVATE QpackProgressiveDecoder
virtual void OnDecodingErrorDetected(QuicStringPiece error_message) = 0;
};
+ // Interface for keeping track of blocked streams for the purpose of enforcing
+ // the limit communicated to peer via QPACK_BLOCKED_STREAMS settings.
+ class QUIC_EXPORT_PRIVATE BlockedStreamLimitEnforcer {
+ public:
+ virtual ~BlockedStreamLimitEnforcer() {}
+
+ // Called when the stream becomes blocked. Returns true if allowed. Returns
+ // false if limit is violated, in which case QpackProgressiveDecoder signals
+ // an error.
+ // Stream must not be already blocked.
+ virtual bool OnStreamBlocked(QuicStreamId stream_id) = 0;
+
+ // Called when the stream becomes unblocked.
+ // Stream must be blocked.
+ virtual void OnStreamUnblocked(QuicStreamId stream_id) = 0;
+ };
+
QpackProgressiveDecoder() = delete;
QpackProgressiveDecoder(QuicStreamId stream_id,
+ BlockedStreamLimitEnforcer* enforcer,
QpackHeaderTable* header_table,
QpackDecoderStreamSender* decoder_stream_sender,
HeadersHandlerInterface* handler);
@@ -89,18 +107,6 @@ class QUIC_EXPORT_PRIVATE QpackProgressiveDecoder
// failure due to overflow/underflow.
bool DeltaBaseToBase(bool sign, uint64_t delta_base, uint64_t* base);
- // The request stream can use relative index (but different from the kind of
- // relative index used on the encoder stream), and post-base index.
- // These methods convert relative index and post-base index to absolute index
- // (one based). They return true on success, or false if conversion fails due
- // to overflow/underflow. On success, |*absolute_index| is guaranteed to be
- // strictly less than std::numeric_limits<uint64_t>::max().
- bool RequestStreamRelativeIndexToAbsoluteIndex(
- uint64_t relative_index,
- uint64_t* absolute_index) const;
- bool PostBaseIndexToAbsoluteIndex(uint64_t post_base_index,
- uint64_t* absolute_index) const;
-
const QuicStreamId stream_id_;
// |prefix_decoder_| only decodes a handful of bytes then it can be
@@ -109,6 +115,7 @@ class QUIC_EXPORT_PRIVATE QpackProgressiveDecoder
std::unique_ptr<QpackInstructionDecoder> prefix_decoder_;
QpackInstructionDecoder instruction_decoder_;
+ BlockedStreamLimitEnforcer* const enforcer_;
QpackHeaderTable* const header_table_;
QpackDecoderStreamSender* const decoder_stream_sender_;
HeadersHandlerInterface* const handler_;
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 d5f35fb901c..59203986b7d 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
@@ -7,8 +7,10 @@
#include "net/third_party/quiche/src/quic/core/quic_session.h"
namespace quic {
-QpackReceiveStream::QpackReceiveStream(PendingStream* pending)
- : QuicStream(pending, READ_UNIDIRECTIONAL, /*is_static=*/true) {}
+QpackReceiveStream::QpackReceiveStream(PendingStream* pending,
+ QpackStreamReceiver* receiver)
+ : QuicStream(pending, READ_UNIDIRECTIONAL, /*is_static=*/true),
+ receiver_(receiver) {}
void QpackReceiveStream::OnStreamReset(const QuicRstStreamFrame& /*frame*/) {
// TODO(renjietang) Change the error code to H/3 specific
@@ -18,4 +20,15 @@ void QpackReceiveStream::OnStreamReset(const QuicRstStreamFrame& /*frame*/) {
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
}
+void QpackReceiveStream::OnDataAvailable() {
+ iovec iov;
+ while (!reading_stopped() && sequencer()->GetReadableRegion(&iov)) {
+ DCHECK(!sequencer()->IsClosed());
+
+ receiver_->Decode(QuicStringPiece(
+ reinterpret_cast<const char*>(iov.iov_base), iov.iov_len));
+ sequencer()->MarkConsumed(iov.iov_len);
+ }
+}
+
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_receive_stream.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_receive_stream.h
index db18f7c6462..0613871625e 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_receive_stream.h
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_receive_stream.h
@@ -5,6 +5,7 @@
#ifndef QUICHE_QUIC_CORE_QPACK_QPACK_RECEIVE_STREAM_H_
#define QUICHE_QUIC_CORE_QPACK_QPACK_RECEIVE_STREAM_H_
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_stream_receiver.h"
#include "net/third_party/quiche/src/quic/core/quic_stream.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
@@ -18,7 +19,7 @@ class QUIC_EXPORT_PRIVATE QpackReceiveStream : public QuicStream {
public:
// Construct receive stream from pending stream, the |pending| object needs
// to be deleted after the construction.
- explicit QpackReceiveStream(PendingStream* pending);
+ QpackReceiveStream(PendingStream* pending, QpackStreamReceiver* receiver);
QpackReceiveStream(const QpackReceiveStream&) = delete;
QpackReceiveStream& operator=(const QpackReceiveStream&) = delete;
~QpackReceiveStream() override = default;
@@ -27,9 +28,13 @@ class QUIC_EXPORT_PRIVATE QpackReceiveStream : public QuicStream {
// closed before connection.
void OnStreamReset(const QuicRstStreamFrame& frame) override;
- // Implementation of QuicStream. Unimplemented yet.
- // TODO(bnc): Feed data to QPACK.
- void OnDataAvailable() override {}
+ // Implementation of QuicStream.
+ void OnDataAvailable() override;
+
+ void SetUnblocked() { sequencer()->SetUnblocked(); }
+
+ private:
+ QpackStreamReceiver* receiver_;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_receive_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_receive_stream_test.cc
index 121043fc576..df081d1765b 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_receive_stream_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_receive_stream_test.cc
@@ -55,13 +55,16 @@ class QpackReceiveStreamTest : public QuicTestWithParam<TestParams> {
SupportedVersions(GetParam().version))),
session_(connection_) {
session_.Initialize();
- PendingStream* pending =
- new PendingStream(QuicUtils::GetFirstUnidirectionalStreamId(
- GetParam().version.transport_version,
- QuicUtils::InvertPerspective(perspective())),
- &session_);
- qpack_receive_stream_ = QuicMakeUnique<QpackReceiveStream>(pending);
- delete pending;
+ QuicStreamId id = perspective() == Perspective::IS_SERVER
+ ? GetNthClientInitiatedUnidirectionalStreamId(
+ session_.transport_version(), 3)
+ : GetNthServerInitiatedUnidirectionalStreamId(
+ session_.transport_version(), 3);
+ char type[] = {0x03};
+ QuicStreamFrame data1(id, false, 0, QuicStringPiece(type, 1));
+ session_.OnStreamFrame(data1);
+ qpack_receive_stream_ =
+ QuicSpdySessionPeer::GetQpackDecoderReceiveStream(&session_);
}
Perspective perspective() const { return GetParam().perspective; }
@@ -70,7 +73,7 @@ class QpackReceiveStreamTest : public QuicTestWithParam<TestParams> {
MockAlarmFactory alarm_factory_;
StrictMock<MockQuicConnection>* connection_;
StrictMock<MockQuicSpdySession> session_;
- std::unique_ptr<QpackReceiveStream> qpack_receive_stream_;
+ QpackReceiveStream* qpack_receive_stream_;
};
INSTANTIATE_TEST_SUITE_P(Tests,
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_round_trip_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_round_trip_test.cc
index 1e9de2d7651..9441b825c5f 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_round_trip_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_round_trip_test.cc
@@ -29,17 +29,20 @@ class QpackRoundTripTest : public QuicTestWithParam<FragmentMode> {
const spdy::SpdyHeaderBlock& header_list) {
NoopDecoderStreamErrorDelegate decoder_stream_error_delegate;
NoopQpackStreamSenderDelegate encoder_stream_sender_delegate;
- QpackEncoder encoder(&decoder_stream_error_delegate,
- &encoder_stream_sender_delegate);
+ QpackEncoder encoder(&decoder_stream_error_delegate);
+ encoder.set_qpack_stream_sender_delegate(&encoder_stream_sender_delegate);
std::string encoded_header_block =
- encoder.EncodeHeaderList(/* stream_id = */ 1, &header_list);
+ encoder.EncodeHeaderList(/* stream_id = */ 1, header_list);
TestHeadersHandler handler;
NoopEncoderStreamErrorDelegate encoder_stream_error_delegate;
NoopQpackStreamSenderDelegate decoder_stream_sender_delegate;
- QpackDecode(&encoder_stream_error_delegate, &decoder_stream_sender_delegate,
- &handler, FragmentModeToFragmentSizeGenerator(GetParam()),
- encoded_header_block);
+ // TODO(b/112770235): Test dynamic table and blocked streams.
+ QpackDecode(
+ /* maximum_dynamic_table_capacity = */ 0,
+ /* maximum_blocked_streams = */ 0, &encoder_stream_error_delegate,
+ &decoder_stream_sender_delegate, &handler,
+ FragmentModeToFragmentSizeGenerator(GetParam()), encoded_header_block);
EXPECT_TRUE(handler.decoding_completed());
EXPECT_FALSE(handler.decoding_error_detected());
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 34bba650a83..50fe687cdd3 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
@@ -25,6 +25,11 @@ void QpackSendStream::OnStreamReset(const QuicRstStreamFrame& /*frame*/) {
void QpackSendStream::WriteStreamData(QuicStringPiece data) {
QuicConnection::ScopedPacketFlusher flusher(session()->connection());
+ MaybeSendStreamType();
+ WriteOrBufferData(data, false, nullptr);
+}
+
+void QpackSendStream::MaybeSendStreamType() {
if (!stream_type_sent_) {
char type[sizeof(http3_stream_type_)];
QuicDataWriter writer(QUIC_ARRAYSIZE(type), type);
@@ -33,7 +38,6 @@ void QpackSendStream::WriteStreamData(QuicStringPiece data) {
nullptr);
stream_type_sent_ = true;
}
- WriteOrBufferData(data, false, nullptr);
}
} // namespace quic
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 136a7cc56b2..09c6020cf49 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
@@ -42,6 +42,10 @@ class QUIC_EXPORT_PRIVATE QpackSendStream : public QuicStream,
// before the first instruction so that the peer can open an qpack stream.
void WriteStreamData(QuicStringPiece data) override;
+ // TODO(b/112770235): Remove this method once QuicStreamIdManager supports
+ // creating HTTP/3 unidirectional streams dynamically.
+ void MaybeSendStreamType();
+
private:
const uint64_t http3_stream_type_;
bool stream_type_sent_;
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 46037c95442..8431afc3a04 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
@@ -56,9 +56,10 @@ class QpackSendStreamTest : public QuicTestWithParam<TestParams> {
SupportedVersions(GetParam().version))),
session_(connection_) {
session_.Initialize();
- qpack_send_stream_ = QuicMakeUnique<QpackSendStream>(
- QuicSpdySessionPeer::GetNextOutgoingUnidirectionalStreamId(&session_),
- &session_, kQpackEncoderStream);
+
+ qpack_send_stream_ =
+ QuicSpdySessionPeer::GetQpackDecoderSendStream(&session_);
+
ON_CALL(session_, WritevData(_, _, _, _, _))
.WillByDefault(Invoke(MockQuicSession::ConsumeData));
}
@@ -69,7 +70,7 @@ class QpackSendStreamTest : public QuicTestWithParam<TestParams> {
MockAlarmFactory alarm_factory_;
StrictMock<MockQuicConnection>* connection_;
StrictMock<MockQuicSpdySession> session_;
- std::unique_ptr<QpackSendStream> qpack_send_stream_;
+ QpackSendStream* qpack_send_stream_;
};
INSTANTIATE_TEST_SUITE_P(Tests,
@@ -89,6 +90,8 @@ TEST_P(QpackSendStreamTest, WriteStreamTypeOnlyFirstTime) {
EXPECT_CALL(session_, WritevData(_, _, data.length(), _, _));
qpack_send_stream_->WriteStreamData(QuicStringPiece(data));
+ EXPECT_CALL(session_, WritevData(_, _, _, _, _)).Times(0);
+ qpack_send_stream_->MaybeSendStreamType();
}
TEST_P(QpackSendStreamTest, ResetQpackStream) {
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_buffered_packet_store_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_buffered_packet_store_test.cc
index a00f2139d37..dbf6c16e627 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_buffered_packet_store_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_buffered_packet_store_test.cc
@@ -55,7 +55,7 @@ class QuicBufferedPacketStoreTest : public QuicTest {
packet_time_(QuicTime::Zero() + QuicTime::Delta::FromMicroseconds(42)),
packet_(packet_content_.data(), packet_content_.size(), packet_time_),
invalid_version_(UnsupportedQuicVersion()),
- valid_version_(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_44) {}
+ valid_version_(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46) {}
protected:
QuicBufferedPacketStoreVisitor visitor_;
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_config.cc b/chromium/net/third_party/quiche/src/quic/core/quic_config.cc
index e24e84b8e7d..22aef80fb03 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_config.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_config.cc
@@ -413,7 +413,9 @@ QuicConfig::QuicConfig()
alternate_server_address_(kASAD, PRESENCE_OPTIONAL),
support_max_header_list_size_(kSMHL, PRESENCE_OPTIONAL),
stateless_reset_token_(kSRST, PRESENCE_OPTIONAL),
- max_incoming_unidirectional_streams_(kMIUS, PRESENCE_OPTIONAL) {
+ max_incoming_unidirectional_streams_(kMIUS, PRESENCE_OPTIONAL),
+ max_ack_delay_ms_(kMAD, PRESENCE_OPTIONAL),
+ ack_delay_exponent_(kADE, PRESENCE_OPTIONAL) {
SetDefaults();
}
@@ -540,6 +542,38 @@ uint32_t QuicConfig::ReceivedMaxIncomingUnidirectionalStreams() {
return max_incoming_unidirectional_streams_.GetReceivedValue();
}
+void QuicConfig::SetMaxAckDelayToSendMs(uint32_t max_ack_delay_ms) {
+ return max_ack_delay_ms_.SetSendValue(max_ack_delay_ms);
+}
+
+uint32_t QuicConfig::GetMaxAckDelayToToSendMs() const {
+ return max_ack_delay_ms_.GetSendValue();
+}
+
+bool QuicConfig::HasReceivedMaxAckDelayMs() const {
+ return max_ack_delay_ms_.HasReceivedValue();
+}
+
+uint32_t QuicConfig::ReceivedMaxAckDelayMs() const {
+ return max_ack_delay_ms_.GetReceivedValue();
+}
+
+void QuicConfig::SetAckDelayExponentToSend(uint32_t exponent) {
+ ack_delay_exponent_.SetSendValue(exponent);
+}
+
+uint32_t QuicConfig::GetAckDelayExponentToSend() {
+ return ack_delay_exponent_.GetSendValue();
+}
+
+bool QuicConfig::HasReceivedAckDelayExponent() const {
+ return ack_delay_exponent_.HasReceivedValue();
+}
+
+uint32_t QuicConfig::ReceivedAckDelayExponent() const {
+ return ack_delay_exponent_.GetReceivedValue();
+}
+
bool QuicConfig::HasSetBytesForConnectionIdToSend() const {
return bytes_for_connection_id_.HasSendValue();
}
@@ -692,7 +726,9 @@ void QuicConfig::SetDefaults() {
SetInitialStreamFlowControlWindowToSend(kMinimumFlowControlSendWindow);
SetInitialSessionFlowControlWindowToSend(kMinimumFlowControlSendWindow);
+ SetMaxAckDelayToSendMs(kDefaultDelayedAckTimeMs);
SetSupportMaxHeaderListSize();
+ SetAckDelayExponentToSend(kDefaultAckDelayExponent);
}
void QuicConfig::ToHandshakeMessage(
@@ -706,6 +742,11 @@ void QuicConfig::ToHandshakeMessage(
max_incoming_bidirectional_streams_.ToHandshakeMessage(out);
if (VersionHasIetfQuicFrames(transport_version)) {
max_incoming_unidirectional_streams_.ToHandshakeMessage(out);
+ ack_delay_exponent_.ToHandshakeMessage(out);
+ }
+ if (GetQuicReloadableFlag(quic_negotiate_ack_delay_time)) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_negotiate_ack_delay_time, 1, 4);
+ max_ack_delay_ms_.ToHandshakeMessage(out);
}
bytes_for_connection_id_.ToHandshakeMessage(out);
initial_round_trip_time_us_.ToHandshakeMessage(out);
@@ -777,6 +818,17 @@ QuicErrorCode QuicConfig::ProcessPeerHello(
error = stateless_reset_token_.ProcessPeerHello(peer_hello, hello_type,
error_details);
}
+
+ if (GetQuicReloadableFlag(quic_negotiate_ack_delay_time) &&
+ error == QUIC_NO_ERROR) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_negotiate_ack_delay_time, 2, 4);
+ error = max_ack_delay_ms_.ProcessPeerHello(peer_hello, hello_type,
+ error_details);
+ }
+ if (error == QUIC_NO_ERROR) {
+ error = ack_delay_exponent_.ProcessPeerHello(peer_hello, hello_type,
+ error_details);
+ }
return error;
}
@@ -805,7 +857,11 @@ bool QuicConfig::FillTransportParameters(TransportParameters* params) const {
max_incoming_bidirectional_streams_.GetSendValue());
params->initial_max_streams_uni.set_value(
max_incoming_unidirectional_streams_.GetSendValue());
- params->max_ack_delay.set_value(kDefaultDelayedAckTimeMs);
+ if (GetQuicReloadableFlag(quic_negotiate_ack_delay_time)) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_negotiate_ack_delay_time, 3, 4);
+ params->max_ack_delay.set_value(kDefaultDelayedAckTimeMs);
+ }
+ params->ack_delay_exponent.set_value(ack_delay_exponent_.GetSendValue());
params->disable_migration =
connection_migration_disabled_.HasSendValue() &&
connection_migration_disabled_.GetSendValue() != 0;
@@ -887,7 +943,14 @@ QuicErrorCode QuicConfig::ProcessTransportParameters(
initial_stream_flow_control_window_bytes_.SetReceivedValue(
std::min<uint64_t>(params.initial_max_stream_data_bidi_local.value(),
std::numeric_limits<uint32_t>::max()));
-
+ if (GetQuicReloadableFlag(quic_negotiate_ack_delay_time)) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_negotiate_ack_delay_time, 4, 4);
+ max_ack_delay_ms_.SetReceivedValue(std::min<uint32_t>(
+ params.max_ack_delay.value(), std::numeric_limits<uint32_t>::max()));
+ }
+ if (params.ack_delay_exponent.IsValid()) {
+ ack_delay_exponent_.SetReceivedValue(params.ack_delay_exponent.value());
+ }
connection_migration_disabled_.SetReceivedValue(
params.disable_migration ? 1u : 0u);
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_config.h b/chromium/net/third_party/quiche/src/quic/core/quic_config.h
index ae15b6aae38..b4a4ca9ceaf 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_config.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_config.h
@@ -414,6 +414,21 @@ class QUIC_EXPORT_PRIVATE QuicConfig {
QuicUint128 ReceivedStatelessResetToken() const;
+ // Manage the IETF QUIC Max ACK Delay transport parameter.
+ // The sent value is the delay that this node uses
+ // (QuicSentPacketManager::local_max_ack_delay_).
+ // The received delay is the value received from
+ // the peer (QuicSentPacketManager::peer_max_ack_delay_).
+ void SetMaxAckDelayToSendMs(uint32_t max_ack_delay_ms);
+ uint32_t GetMaxAckDelayToToSendMs() const;
+ bool HasReceivedMaxAckDelayMs() const;
+ uint32_t ReceivedMaxAckDelayMs() const;
+
+ void SetAckDelayExponentToSend(uint32_t exponent);
+ uint32_t GetAckDelayExponentToSend();
+ bool HasReceivedAckDelayExponent() const;
+ uint32_t ReceivedAckDelayExponent() const;
+
bool negotiated() const;
void SetCreateSessionTagIndicators(QuicTagVector tags);
@@ -501,6 +516,18 @@ class QUIC_EXPORT_PRIVATE QuicConfig {
// Maximum number of incoming unidirectional streams that the connection can
// support.
QuicFixedUint32 max_incoming_unidirectional_streams_;
+
+ // Maximum ack delay. The sent value is the value used on this node.
+ // The received value is the value received from the peer and used by
+ // the peer.
+ QuicFixedUint32 max_ack_delay_ms_;
+
+ // ack_delay_exponent parameter negotiated in IETF QUIC transport
+ // parameter negotiation. The sent exponent is the exponent that this
+ // node uses when serializing an ACK frame (and the peer should use when
+ // deserializing the frame); the received exponent is the value the peer uses
+ // to serialize frames and this node uses to deserialize them.
+ QuicFixedUint32 ack_delay_exponent_;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_config_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_config_test.cc
index 84e89c17d2d..630e67ad1a4 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_config_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_config_test.cc
@@ -56,6 +56,8 @@ TEST_P(QuicConfigTest, ToHandshakeMessage) {
}
TEST_P(QuicConfigTest, ProcessClientHello) {
+ const uint32_t kTestMaxAckDelayMs =
+ static_cast<uint32_t>(kDefaultDelayedAckTimeMs + 1);
QuicConfig client_config;
QuicTagVector cgst;
cgst.push_back(kQBIC);
@@ -70,6 +72,7 @@ TEST_P(QuicConfigTest, ProcessClientHello) {
QuicTagVector copt;
copt.push_back(kTBBR);
client_config.SetConnectionOptionsToSend(copt);
+ client_config.SetMaxAckDelayToSendMs(kTestMaxAckDelayMs);
CryptoHandshakeMessage msg;
client_config.ToHandshakeMessage(&msg, GetParam());
@@ -99,6 +102,12 @@ TEST_P(QuicConfigTest, ProcessClientHello) {
2 * kInitialStreamFlowControlWindowForTest);
EXPECT_EQ(config_.ReceivedInitialSessionFlowControlWindowBytes(),
2 * kInitialSessionFlowControlWindowForTest);
+ if (GetQuicReloadableFlag(quic_negotiate_ack_delay_time)) {
+ EXPECT_TRUE(config_.HasReceivedMaxAckDelayMs());
+ EXPECT_EQ(kTestMaxAckDelayMs, config_.ReceivedMaxAckDelayMs());
+ } else {
+ EXPECT_FALSE(config_.HasReceivedMaxAckDelayMs());
+ }
}
TEST_P(QuicConfigTest, ProcessServerHello) {
@@ -106,6 +115,8 @@ TEST_P(QuicConfigTest, ProcessServerHello) {
host.FromString("127.0.3.1");
const QuicSocketAddress kTestServerAddress = QuicSocketAddress(host, 1234);
const QuicUint128 kTestResetToken = MakeQuicUint128(0, 10111100001);
+ const uint32_t kTestMaxAckDelayMs =
+ static_cast<uint32_t>(kDefaultDelayedAckTimeMs + 1);
QuicConfig server_config;
QuicTagVector cgst;
cgst.push_back(kQBIC);
@@ -119,6 +130,7 @@ TEST_P(QuicConfigTest, ProcessServerHello) {
2 * kInitialSessionFlowControlWindowForTest);
server_config.SetAlternateServerAddressToSend(kTestServerAddress);
server_config.SetStatelessResetTokenToSend(kTestResetToken);
+ server_config.SetMaxAckDelayToSendMs(kTestMaxAckDelayMs);
CryptoHandshakeMessage msg;
server_config.ToHandshakeMessage(&msg, GetParam());
std::string error_details;
@@ -137,6 +149,12 @@ TEST_P(QuicConfigTest, ProcessServerHello) {
EXPECT_EQ(kTestServerAddress, config_.ReceivedAlternateServerAddress());
EXPECT_TRUE(config_.HasReceivedStatelessResetToken());
EXPECT_EQ(kTestResetToken, config_.ReceivedStatelessResetToken());
+ if (GetQuicReloadableFlag(quic_negotiate_ack_delay_time)) {
+ EXPECT_TRUE(config_.HasReceivedMaxAckDelayMs());
+ EXPECT_EQ(kTestMaxAckDelayMs, config_.ReceivedMaxAckDelayMs());
+ } else {
+ EXPECT_FALSE(config_.HasReceivedMaxAckDelayMs());
+ }
}
TEST_P(QuicConfigTest, MissingOptionalValuesInCHLO) {
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 22ee18a7e8d..257ef29a2d7 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
@@ -247,6 +247,7 @@ QuicConnection::QuicConnection(
max_tracked_packets_(GetQuicFlag(FLAGS_quic_max_tracked_packet_count)),
pending_version_negotiation_packet_(false),
send_ietf_version_negotiation_packet_(false),
+ send_version_negotiation_packet_with_prefixed_lengths_(false),
idle_timeout_connection_close_behavior_(
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET),
close_connection_after_five_rtos_(false),
@@ -320,7 +321,11 @@ QuicConnection::QuicConnection(
processing_ack_frame_(false),
supports_release_time_(false),
release_time_into_future_(QuicTime::Delta::Zero()),
- retry_has_been_parsed_(false) {
+ retry_has_been_parsed_(false),
+ max_consecutive_ptos_(0),
+ bytes_received_before_address_validation_(0),
+ bytes_sent_before_address_validation_(0),
+ address_validated_(false) {
QUIC_DLOG(INFO) << ENDPOINT << "Created connection with server connection ID "
<< server_connection_id
<< " and version: " << ParsedQuicVersionToString(version());
@@ -418,6 +423,16 @@ void QuicConnection::SetFromConfig(const QuicConfig& config) {
if (config.HasClientSentConnectionOption(k5RTO, perspective_)) {
close_connection_after_five_rtos_ = true;
}
+ if (sent_packet_manager_.pto_enabled()) {
+ if (config.HasClientSentConnectionOption(k7PTO, perspective_)) {
+ max_consecutive_ptos_ = 6;
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_pto, 3, 4);
+ }
+ if (config.HasClientSentConnectionOption(k8PTO, perspective_)) {
+ max_consecutive_ptos_ = 7;
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_pto, 4, 4);
+ }
+ }
if (config.HasClientSentConnectionOption(kNSTP, perspective_)) {
no_stop_waiting_frames_ = true;
}
@@ -425,6 +440,9 @@ void QuicConnection::SetFromConfig(const QuicConfig& config) {
stateless_reset_token_received_ = true;
received_stateless_reset_token_ = config.ReceivedStatelessResetToken();
}
+ if (config.HasReceivedAckDelayExponent()) {
+ framer_.set_peer_ack_delay_exponent(config.ReceivedAckDelayExponent());
+ }
if (GetQuicReloadableFlag(quic_send_timestamps) &&
config.HasClientSentConnectionOption(kSTMP, perspective_)) {
QUIC_RELOADABLE_FLAG_COUNT(quic_send_timestamps);
@@ -570,9 +588,11 @@ void QuicConnection::OnVersionNegotiationPacket(
}
if (QuicContainsValue(packet.versions, version())) {
- const std::string error_details =
- "Server already supports client's version and should have accepted the "
- "connection.";
+ const std::string error_details = QuicStrCat(
+ "Server already supports client's version ",
+ ParsedQuicVersionToString(version()),
+ " and should have accepted the connection instead of sending {",
+ ParsedQuicVersionVectorToString(packet.versions), "}.");
QUIC_DLOG(WARNING) << error_details;
CloseConnection(QUIC_INVALID_VERSION_NEGOTIATION_PACKET, error_details,
ConnectionCloseBehavior::SILENT_CLOSE);
@@ -748,14 +768,17 @@ bool QuicConnection::OnUnauthenticatedHeader(const QuicPacketHeader& header) {
void QuicConnection::OnDecryptedPacket(EncryptionLevel level) {
last_decrypted_packet_level_ = level;
last_packet_decrypted_ = true;
+ if (EnforceAntiAmplificationLimit() &&
+ last_decrypted_packet_level_ >= ENCRYPTION_HANDSHAKE) {
+ // Address is validated by successfully processing a HANDSHAKE packet.
+ address_validated_ = true;
+ }
// Once the server receives a forward secure packet, the handshake is
// confirmed.
if (level == ENCRYPTION_FORWARD_SECURE &&
perspective_ == Perspective::IS_SERVER) {
- sent_packet_manager_.SetHandshakeConfirmed();
- // This may have changed the retransmission timer, so re-arm it.
- SetRetransmissionAlarm();
+ OnHandshakeComplete();
}
}
@@ -1161,18 +1184,40 @@ bool QuicConnection::OnConnectionCloseFrame(
if (debug_visitor_ != nullptr) {
debug_visitor_->OnConnectionCloseFrame(frame);
}
- QUIC_DLOG(INFO) << ENDPOINT << "Received ConnectionClose for connection: "
- << connection_id() << ", with error: "
- << QuicErrorCodeToString(frame.quic_error_code) << " ("
- << frame.error_details << ")";
- if (frame.close_type == GOOGLE_QUIC_CONNECTION_CLOSE &&
- frame.quic_error_code == QUIC_BAD_MULTIPATH_FLAG) {
+ switch (frame.close_type) {
+ case GOOGLE_QUIC_CONNECTION_CLOSE:
+ QUIC_DLOG(INFO) << ENDPOINT << "Received ConnectionClose for connection: "
+ << connection_id() << ", with error: "
+ << QuicErrorCodeToString(frame.extracted_error_code)
+ << " (" << frame.error_details << ")";
+ break;
+ case IETF_QUIC_TRANSPORT_CONNECTION_CLOSE:
+ QUIC_DLOG(INFO) << ENDPOINT
+ << "Received Transport ConnectionClose for connection: "
+ << connection_id() << ", with error: "
+ << QuicErrorCodeToString(frame.extracted_error_code)
+ << " (" << frame.error_details << ")"
+ << ", transport error code: "
+ << frame.transport_error_code << ", error frame type: "
+ << frame.transport_close_frame_type;
+ break;
+ case IETF_QUIC_APPLICATION_CONNECTION_CLOSE:
+ QUIC_DLOG(INFO) << ENDPOINT
+ << "Received Application ConnectionClose for connection: "
+ << connection_id() << ", with error: "
+ << QuicErrorCodeToString(frame.extracted_error_code)
+ << " (" << frame.error_details << ")"
+ << ", application error code: "
+ << frame.application_error_code;
+ break;
+ }
+
+ if (frame.extracted_error_code == QUIC_BAD_MULTIPATH_FLAG) {
QUIC_LOG_FIRST_N(ERROR, 10) << "Unexpected QUIC_BAD_MULTIPATH_FLAG error."
<< " last_received_header: " << last_header_
<< " encryption_level: " << encryption_level_;
}
- TearDownLocalConnectionState(frame.quic_error_code, frame.error_details,
- ConnectionCloseSource::FROM_PEER);
+ TearDownLocalConnectionState(frame, ConnectionCloseSource::FROM_PEER);
return connected_;
}
@@ -1215,9 +1260,9 @@ bool QuicConnection::OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) {
if (debug_visitor_ != nullptr) {
debug_visitor_->OnWindowUpdateFrame(frame, time_of_last_received_packet_);
}
- QUIC_DLOG(INFO) << ENDPOINT << "WINDOW_UPDATE_FRAME received for stream: "
- << frame.stream_id
- << " with byte offset: " << frame.byte_offset;
+ QUIC_DVLOG(1) << ENDPOINT << "WINDOW_UPDATE_FRAME received for stream: "
+ << frame.stream_id
+ << " with byte offset: " << frame.byte_offset;
visitor_->OnWindowUpdateFrame(frame);
should_last_packet_instigate_acks_ = true;
return connected_;
@@ -1290,28 +1335,29 @@ void QuicConnection::OnPacketComplete() {
<< ENDPOINT << "Received a padded PING packet. is_probing: "
<< IsCurrentPacketConnectivityProbing();
- if (perspective_ == Perspective::IS_CLIENT) {
- QUIC_DVLOG(1) << ENDPOINT
- << "Received a speculative connectivity probing packet for "
+ if (IsCurrentPacketConnectivityProbing()) {
+ QUIC_DVLOG(1) << ENDPOINT << "Received a connectivity probing packet for "
<< GetServerConnectionIdAsRecipient(last_header_,
perspective_)
<< " from ip:port: " << last_packet_source_address_.ToString()
<< " to ip:port: "
<< last_packet_destination_address_.ToString();
- // TODO(zhongyi): change the method name.
- visitor_->OnConnectivityProbeReceived(last_packet_destination_address_,
- last_packet_source_address_);
- } else if (IsCurrentPacketConnectivityProbing()) {
- // This node is not a client (is a server) AND the received packet was
- // connectivity-probing, send an appropriate response.
- QUIC_DVLOG(1) << ENDPOINT << "Received a connectivity probing packet for "
+ visitor_->OnPacketReceived(last_packet_destination_address_,
+ last_packet_source_address_,
+ /*is_connectivity_probe=*/true);
+ } else if (perspective_ == Perspective::IS_CLIENT) {
+ // This node is a client, notify that a speculative connectivity probing
+ // packet has been received anyway.
+ QUIC_DVLOG(1) << ENDPOINT
+ << "Received a speculative connectivity probing packet for "
<< GetServerConnectionIdAsRecipient(last_header_,
perspective_)
<< " from ip:port: " << last_packet_source_address_.ToString()
<< " to ip:port: "
<< last_packet_destination_address_.ToString();
- visitor_->OnConnectivityProbeReceived(last_packet_destination_address_,
- last_packet_source_address_);
+ visitor_->OnPacketReceived(last_packet_destination_address_,
+ last_packet_source_address_,
+ /*is_connectivity_probe=*/false);
} else {
// This node is not a client (is a server) AND the received packet was
// NOT connectivity-probing. If the packet had PATH CHALLENGES, send
@@ -1357,8 +1403,7 @@ void QuicConnection::OnPacketComplete() {
uber_received_packet_manager_.MaybeUpdateAckTimeout(
should_last_packet_instigate_acks_, last_decrypted_packet_level_,
last_header_.packet_number, time_of_last_received_packet_,
- clock_->ApproximateNow(), sent_packet_manager_.GetRttStats(),
- sent_packet_manager_.local_max_ack_delay());
+ clock_->ApproximateNow(), sent_packet_manager_.GetRttStats());
} else {
QUIC_DLOG(INFO) << ENDPOINT << "Not updating ACK timeout for "
<< QuicUtils::EncryptionLevelToString(
@@ -1452,9 +1497,11 @@ void QuicConnection::MaybeSendInResponseToPacket() {
}
}
-void QuicConnection::SendVersionNegotiationPacket(bool ietf_quic) {
+void QuicConnection::SendVersionNegotiationPacket(bool ietf_quic,
+ bool has_length_prefix) {
pending_version_negotiation_packet_ = true;
send_ietf_version_negotiation_packet_ = ietf_quic;
+ send_version_negotiation_packet_with_prefixed_lengths_ = has_length_prefix;
if (HandleWriteBlocked()) {
return;
@@ -1466,7 +1513,7 @@ void QuicConnection::SendVersionNegotiationPacket(bool ietf_quic) {
<< "}, " << (ietf_quic ? "" : "!") << "ietf_quic";
std::unique_ptr<QuicEncryptedPacket> version_packet(
packet_generator_.SerializeVersionNegotiationPacket(
- ietf_quic, framer_.supported_versions()));
+ ietf_quic, has_length_prefix, framer_.supported_versions()));
QUIC_DVLOG(2) << ENDPOINT << "Sending version negotiation packet: {"
<< ParsedQuicVersionVectorToString(framer_.supported_versions())
<< "}, " << (ietf_quic ? "" : "!") << "ietf_quic:" << std::endl
@@ -1498,7 +1545,9 @@ size_t QuicConnection::SendCryptoData(EncryptionLevel level,
QUIC_BUG << "Attempt to send empty crypto frame";
return 0;
}
-
+ if (!ShouldGeneratePacket(HAS_RETRANSMITTABLE_DATA, IS_HANDSHAKE)) {
+ return 0;
+ }
ScopedPacketFlusher flusher(this);
return packet_generator_.ConsumeCryptoData(level, write_length, offset);
}
@@ -1522,6 +1571,18 @@ QuicConsumedData QuicConnection::SendStreamData(QuicStreamId id,
}
bool QuicConnection::SendControlFrame(const QuicFrame& frame) {
+ if (SupportsMultiplePacketNumberSpaces() &&
+ (encryption_level_ == ENCRYPTION_INITIAL ||
+ encryption_level_ == ENCRYPTION_HANDSHAKE) &&
+ frame.type != PING_FRAME) {
+ // Allow PING frame to be sent without APPLICATION key. For example, when
+ // anti-amplification limit is used, client needs to send something to avoid
+ // handshake deadlock.
+ QUIC_DVLOG(1) << ENDPOINT << "Failed to send control frame: " << frame
+ << " at encryption level: "
+ << QuicUtils::EncryptionLevelToString(encryption_level_);
+ return false;
+ }
ScopedPacketFlusher flusher(this);
const bool consumed =
packet_generator_.ConsumeRetransmittableControlFrame(frame);
@@ -1605,6 +1666,45 @@ void QuicConnection::OnCoalescedPacket(const QuicEncryptedPacket& packet) {
QueueCoalescedPacket(packet);
}
+void QuicConnection::OnUndecryptablePacket(const QuicEncryptedPacket& packet,
+ EncryptionLevel decryption_level,
+ bool has_decryption_key) {
+ QUIC_DVLOG(1) << ENDPOINT << "Received undecryptable packet of length "
+ << packet.length() << " with"
+ << (has_decryption_key ? "" : "out") << " key at level "
+ << QuicUtils::EncryptionLevelToString(decryption_level)
+ << " while connection is at encryption level "
+ << QuicUtils::EncryptionLevelToString(encryption_level_);
+ DCHECK(GetQuicRestartFlag(quic_framer_uses_undecryptable_upcall));
+ QUIC_RESTART_FLAG_COUNT_N(quic_framer_uses_undecryptable_upcall, 1, 7);
+ DCHECK(EncryptionLevelIsValid(decryption_level));
+ ++stats_.undecryptable_packets_received;
+
+ bool should_enqueue = true;
+ if (encryption_level_ == ENCRYPTION_FORWARD_SECURE) {
+ // We do not expect to install any further keys.
+ should_enqueue = false;
+ } else if (undecryptable_packets_.size() >= max_undecryptable_packets_) {
+ // We do not queue more than max_undecryptable_packets_ packets.
+ should_enqueue = false;
+ } else if (has_decryption_key) {
+ // We already have the key for this decryption level, therefore no
+ // future keys will allow it be decrypted.
+ should_enqueue = false;
+ } else if (version().KnowsWhichDecrypterToUse() &&
+ decryption_level <= encryption_level_) {
+ // On versions that know which decrypter to use, we install keys in order
+ // so we will not get newer keys for lower encryption levels.
+ should_enqueue = false;
+ }
+
+ if (should_enqueue) {
+ QueueUndecryptablePacket(packet);
+ } else if (debug_visitor_ != nullptr) {
+ debug_visitor_->OnUndecryptablePacket();
+ }
+}
+
void QuicConnection::ProcessUdpPacket(const QuicSocketAddress& self_address,
const QuicSocketAddress& peer_address,
const QuicReceivedPacket& packet) {
@@ -1647,6 +1747,9 @@ void QuicConnection::ProcessUdpPacket(const QuicSocketAddress& self_address,
stats_.bytes_received += packet.length();
++stats_.packets_received;
+ if (EnforceAntiAmplificationLimit()) {
+ bytes_received_before_address_validation_ += last_size_;
+ }
// Ensure the time coming from the packet reader is within 2 minutes of now.
if (std::abs((packet.receipt_time() - clock_->ApproximateNow()).ToSeconds()) >
@@ -1664,7 +1767,8 @@ void QuicConnection::ProcessUdpPacket(const QuicSocketAddress& self_address,
if (!framer_.ProcessPacket(packet)) {
// If we are unable to decrypt this packet, it might be
// because the CHLO or SHLO packet was lost.
- if (framer_.error() == QUIC_DECRYPTION_FAILURE) {
+ if (framer_.error() == QUIC_DECRYPTION_FAILURE &&
+ !GetQuicRestartFlag(quic_framer_uses_undecryptable_upcall)) {
++stats_.undecryptable_packets_received;
if (encryption_level_ != ENCRYPTION_FORWARD_SECURE &&
undecryptable_packets_.size() < max_undecryptable_packets_) {
@@ -1672,6 +1776,8 @@ void QuicConnection::ProcessUdpPacket(const QuicSocketAddress& self_address,
} else if (debug_visitor_ != nullptr) {
debug_visitor_->OnUndecryptablePacket();
}
+ } else if (GetQuicRestartFlag(quic_framer_uses_undecryptable_upcall)) {
+ QUIC_RESTART_FLAG_COUNT_N(quic_framer_uses_undecryptable_upcall, 2, 7);
}
QUIC_DVLOG(1) << ENDPOINT
<< "Unable to process packet. Last packet processed: "
@@ -1865,7 +1971,9 @@ void QuicConnection::WriteQueuedPackets() {
DCHECK(!writer_->IsWriteBlocked());
if (pending_version_negotiation_packet_) {
- SendVersionNegotiationPacket(send_ietf_version_negotiation_packet_);
+ SendVersionNegotiationPacket(
+ send_ietf_version_negotiation_packet_,
+ send_version_negotiation_packet_with_prefixed_lengths_);
}
QUIC_CLIENT_HISTOGRAM_COUNTS("QuicSession.NumQueuedPacketsBeforeWrite",
@@ -1961,6 +2069,11 @@ bool QuicConnection::ShouldGeneratePacket(
// We should serialize handshake packets immediately to ensure that they
// end up sent at the right encryption level.
if (handshake == IS_HANDSHAKE) {
+ if (LimitedByAmplificationFactor()) {
+ // Server is constrained by the amplification restriction.
+ QUIC_DVLOG(1) << ENDPOINT << "Constrained by amplification restriction";
+ return false;
+ }
return true;
}
@@ -2181,11 +2294,16 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) {
QUIC_DVLOG(1) << ENDPOINT << "time we began writing last sent packet: "
<< packet_send_time.ToDebuggingValue();
- bool reset_retransmission_alarm = sent_packet_manager_.OnPacketSent(
+ if (EnforceAntiAmplificationLimit()) {
+ // Include bytes sent even if they are not in flight.
+ bytes_sent_before_address_validation_ += packet->encrypted_length;
+ }
+
+ const bool in_flight = sent_packet_manager_.OnPacketSent(
packet, packet->original_packet_number, packet_send_time,
packet->transmission_type, IsRetransmittable(*packet));
- if (reset_retransmission_alarm || !retransmission_alarm_->IsSet()) {
+ if (in_flight || !retransmission_alarm_->IsSet()) {
SetRetransmissionAlarm();
}
SetPingAlarm();
@@ -2426,14 +2544,11 @@ void QuicConnection::OnPathDegradingTimeout() {
}
void QuicConnection::OnRetransmissionTimeout() {
- DCHECK(!sent_packet_manager_.unacked_packets().empty());
+ DCHECK(!sent_packet_manager_.unacked_packets().empty() ||
+ (sent_packet_manager_.handshake_mode_disabled() &&
+ !sent_packet_manager_.handshake_confirmed()));
const QuicPacketNumber previous_created_packet_number =
packet_generator_.packet_number();
- const size_t previous_crypto_retransmit_count =
- stats_.crypto_retransmit_count;
- const size_t previous_loss_timeout_count = stats_.loss_timeout_count;
- const size_t previous_tlp_count = stats_.tlp_count;
- const size_t pervious_rto_count = stats_.rto_count;
if (close_connection_after_five_rtos_ &&
sent_packet_manager_.GetConsecutiveRtoCount() >= 4) {
// Close on the 5th consecutive RTO, so after 4 previous RTOs have occurred.
@@ -2441,8 +2556,17 @@ void QuicConnection::OnRetransmissionTimeout() {
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
return;
}
+ if (sent_packet_manager_.pto_enabled() && max_consecutive_ptos_ > 0 &&
+ sent_packet_manager_.GetConsecutivePtoCount() >= max_consecutive_ptos_) {
+ CloseConnection(QUIC_TOO_MANY_RTOS,
+ QuicStrCat(max_consecutive_ptos_ + 1,
+ "consecutive retransmission timeouts"),
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return;
+ }
- sent_packet_manager_.OnRetransmissionTimeout();
+ const auto retransmission_mode =
+ sent_packet_manager_.OnRetransmissionTimeout();
WriteIfNotBlocked();
// A write failure can result in the connection being closed, don't attempt to
@@ -2451,34 +2575,52 @@ void QuicConnection::OnRetransmissionTimeout() {
return;
}
- // In the TLP case, the SentPacketManager gives the connection the opportunity
- // to send new data before retransmitting.
- if (sent_packet_manager_.MaybeRetransmitTailLossProbe()) {
+ // In the PTO and TLP cases, the SentPacketManager gives the connection the
+ // opportunity to send new data before retransmitting.
+ if (sent_packet_manager_.pto_enabled()) {
+ sent_packet_manager_.MaybeSendProbePackets();
+ } else if (sent_packet_manager_.MaybeRetransmitTailLossProbe()) {
// Send the pending retransmission now that it's been queued.
WriteIfNotBlocked();
}
if (sent_packet_manager_.fix_rto_retransmission()) {
- // Making sure at least one packet is created when retransmission timer
- // fires in TLP, RTO or HANDSHAKE mode. It is possible that loss algorithm
- // invokes timer based loss but the packet does not need to be
- // retransmitted.
- QUIC_BUG_IF(stats_.loss_timeout_count == previous_loss_timeout_count &&
- packet_generator_.packet_number() ==
- previous_created_packet_number)
- << "previous_crypto_retransmit_count: "
- << previous_crypto_retransmit_count
- << ", crypto_retransmit_count: " << stats_.crypto_retransmit_count
- << ", previous_loss_timeout_count: " << previous_loss_timeout_count
- << ", loss_timeout_count: " << stats_.loss_timeout_count
- << ", previous_tlp_count: " << previous_tlp_count
- << ", tlp_count: " << stats_.tlp_count
- << ", pervious_rto_count: " << pervious_rto_count
- << ", rto_count: " << stats_.rto_count
- << ", previous_created_packet_number: "
- << previous_created_packet_number
- << ", packet_number: " << packet_generator_.packet_number()
- << ", session has data to write: " << visitor_->WillingAndAbleToWrite();
+ if (packet_generator_.packet_number() == previous_created_packet_number &&
+ (retransmission_mode == QuicSentPacketManager::TLP_MODE ||
+ retransmission_mode == QuicSentPacketManager::RTO_MODE ||
+ retransmission_mode == QuicSentPacketManager::PTO_MODE) &&
+ !visitor_->WillingAndAbleToWrite()) {
+ // Send PING if timer fires in RTO or PTO mode but there is no data to
+ // send.
+ // When TLP fires, either new data or tail loss probe should be sent.
+ // There is corner case where TLP fires after RTO because packets get
+ // acked. Two packets are marked RTO_RETRANSMITTED, but the first packet
+ // is retransmitted as two packets because of packet number length
+ // increases (please see QuicConnectionTest.RtoPacketAsTwo).
+ QUIC_BUG_IF(retransmission_mode == QuicSentPacketManager::TLP_MODE &&
+ stats_.rto_count == 0);
+ DCHECK_LT(0u, sent_packet_manager_.pending_timer_transmission_count());
+ visitor_->SendPing();
+ }
+ if (retransmission_mode == QuicSentPacketManager::PTO_MODE) {
+ sent_packet_manager_.AdjustPendingTimerTransmissions();
+ }
+ if (retransmission_mode != QuicSentPacketManager::LOSS_MODE) {
+ // When timer fires in TLP or RTO mode, ensure 1) at least one packet is
+ // created, or there is data to send and available credit (such that
+ // packets will be sent eventually).
+ QUIC_BUG_IF(
+ packet_generator_.packet_number() == previous_created_packet_number &&
+ (!visitor_->WillingAndAbleToWrite() ||
+ sent_packet_manager_.pending_timer_transmission_count() == 0u))
+ << "retransmission_mode: " << retransmission_mode
+ << ", packet_number: " << packet_generator_.packet_number()
+ << ", session has data to write: "
+ << visitor_->WillingAndAbleToWrite()
+ << ", writer is blocked: " << writer_->IsWriteBlocked()
+ << ", pending_timer_transmission_count: "
+ << sent_packet_manager_.pending_timer_transmission_count();
+ }
}
// Ensure the retransmission alarm is always set if there are unacked packets
@@ -2502,6 +2644,9 @@ void QuicConnection::SetDiversificationNonce(
}
void QuicConnection::SetDefaultEncryptionLevel(EncryptionLevel level) {
+ QUIC_DVLOG(1) << ENDPOINT << "Setting default encryption level from "
+ << QuicUtils::EncryptionLevelToString(encryption_level_)
+ << " to " << QuicUtils::EncryptionLevelToString(level);
if (level != encryption_level_ && packet_generator_.HasPendingFrames()) {
// Flush all queued frames when encryption level changes.
ScopedPacketFlusher flusher(this);
@@ -2557,6 +2702,16 @@ const QuicDecrypter* QuicConnection::alternative_decrypter() const {
void QuicConnection::QueueUndecryptablePacket(
const QuicEncryptedPacket& packet) {
+ if (GetQuicRestartFlag(quic_framer_uses_undecryptable_upcall)) {
+ QUIC_RESTART_FLAG_COUNT_N(quic_framer_uses_undecryptable_upcall, 3, 7);
+ for (const auto& saved_packet : undecryptable_packets_) {
+ if (packet.data() == saved_packet->data() &&
+ packet.length() == saved_packet->length()) {
+ QUIC_DVLOG(1) << ENDPOINT << "Not queueing known undecryptable packet";
+ return;
+ }
+ }
+ }
QUIC_DVLOG(1) << ENDPOINT << "Queueing undecryptable packet.";
undecryptable_packets_.push_back(packet.Clone());
}
@@ -2611,21 +2766,26 @@ void QuicConnection::QueueCoalescedPacket(const QuicEncryptedPacket& packet) {
void QuicConnection::MaybeProcessCoalescedPackets() {
bool processed = false;
- for (const auto& packet : coalesced_packets_) {
+ while (connected_ && !coalesced_packets_.empty()) {
+ // Making sure there are no pending frames when processing the next
+ // coalesced packet because the queued ack frame may change.
+ packet_generator_.FlushAllQueuedFrames();
if (!connected_) {
return;
}
- // }
- // while (connected_ && !coalesced_packets_.empty()) {
+ std::unique_ptr<QuicEncryptedPacket> packet =
+ std::move(coalesced_packets_.front());
+ coalesced_packets_.pop_front();
+
QUIC_DVLOG(1) << ENDPOINT << "Processing coalesced packet";
- // QuicEncryptedPacket* packet = coalesced_packets_.front().get();
if (framer_.ProcessPacket(*packet)) {
processed = true;
} else {
// If we are unable to decrypt this packet, it might be
// because the CHLO or SHLO packet was lost.
- if (framer_.error() == QUIC_DECRYPTION_FAILURE) {
+ if (framer_.error() == QUIC_DECRYPTION_FAILURE &&
+ !GetQuicRestartFlag(quic_framer_uses_undecryptable_upcall)) {
++stats_.undecryptable_packets_received;
if (encryption_level_ != ENCRYPTION_FORWARD_SECURE &&
undecryptable_packets_.size() < max_undecryptable_packets_) {
@@ -2633,11 +2793,11 @@ void QuicConnection::MaybeProcessCoalescedPackets() {
} else if (debug_visitor_ != nullptr) {
debug_visitor_->OnUndecryptablePacket();
}
+ } else if (GetQuicRestartFlag(quic_framer_uses_undecryptable_upcall)) {
+ QUIC_RESTART_FLAG_COUNT_N(quic_framer_uses_undecryptable_upcall, 4, 7);
}
}
- // coalesced_packets_.pop_front();
}
- coalesced_packets_.clear();
if (processed) {
MaybeProcessUndecryptablePackets();
}
@@ -2679,12 +2839,21 @@ void QuicConnection::SendConnectionClosePacket(QuicErrorCode error,
!GetUpdatedAckFrame().ack_frame->packets.Empty()) {
SendAck();
}
- QuicConnectionCloseFrame* frame =
- new QuicConnectionCloseFrame(error, details);
- // If version99/IETF QUIC set the close type. Default close type is Google
- // QUIC.
+ QuicConnectionCloseFrame* frame;
if (VersionHasIetfQuicFrames(transport_version())) {
- frame->close_type = IETF_QUIC_TRANSPORT_CONNECTION_CLOSE;
+ QuicErrorCodeToIetfMapping mapping =
+ QuicErrorCodeToTransportErrorCode(error);
+ if (mapping.is_transport_close_) {
+ frame = new QuicConnectionCloseFrame(
+ error, details, mapping.transport_error_code_,
+ framer_.current_received_frame_type());
+ } else {
+ // Maps to an application close.
+ frame = new QuicConnectionCloseFrame(error, details,
+ mapping.application_error_code_);
+ }
+ } else {
+ frame = new QuicConnectionCloseFrame(error, details);
}
packet_generator_.ConsumeRetransmittableControlFrame(QuicFrame(frame));
packet_generator_.FlushAllQueuedFrames();
@@ -2698,6 +2867,13 @@ void QuicConnection::TearDownLocalConnectionState(
QuicErrorCode error,
const std::string& error_details,
ConnectionCloseSource source) {
+ QuicConnectionCloseFrame frame(error, error_details);
+ return TearDownLocalConnectionState(frame, source);
+}
+
+void QuicConnection::TearDownLocalConnectionState(
+ const QuicConnectionCloseFrame& frame,
+ ConnectionCloseSource source) {
if (!connected_) {
QUIC_DLOG(INFO) << "Connection is already closed.";
return;
@@ -2707,9 +2883,6 @@ void QuicConnection::TearDownLocalConnectionState(
FlushPackets();
connected_ = false;
DCHECK(visitor_ != nullptr);
- // TODO(fkastenholz): When the IETF Transport Connection Close information
- // gets plumbed in, expand this constructor to include that information.
- QuicConnectionCloseFrame frame(error, error_details);
visitor_->OnConnectionClosed(frame, source);
if (debug_visitor_ != nullptr) {
debug_visitor_->OnConnectionClosed(frame, source);
@@ -2879,8 +3052,14 @@ void QuicConnection::SetRetransmissionAlarm() {
pending_retransmission_alarm_ = true;
return;
}
- QuicTime retransmission_time = sent_packet_manager_.GetRetransmissionTime();
- retransmission_alarm_->Update(retransmission_time,
+ if (LimitedByAmplificationFactor()) {
+ // Do not set retransmission timer if connection is anti-amplification limit
+ // throttled. Otherwise, nothing can be sent when timer fires.
+ retransmission_alarm_->Cancel();
+ return;
+ }
+
+ retransmission_alarm_->Update(sent_packet_manager_.GetRetransmissionTime(),
QuicTime::Delta::FromMilliseconds(1));
}
@@ -3403,6 +3582,9 @@ void QuicConnection::MaybeEnableSessionDecidesWhatToWrite() {
transport_version() > QUIC_VERSION_39;
sent_packet_manager_.SetSessionDecideWhatToWrite(
enable_session_decides_what_to_write);
+ if (version().SupportsAntiAmplificationLimit()) {
+ sent_packet_manager_.DisableHandshakeMode();
+ }
packet_generator_.SetCanSetTransmissionType(
enable_session_decides_what_to_write);
}
@@ -3538,6 +3720,7 @@ EncryptionLevel QuicConnection::GetConnectionCloseEncryptionLevel() const {
void QuicConnection::SendAllPendingAcks() {
DCHECK(SupportsMultiplePacketNumberSpaces());
QUIC_DVLOG(1) << ENDPOINT << "Trying to send all pending ACKs";
+ ack_alarm_->Cancel();
// Latches current encryption level.
const EncryptionLevel current_encryption_level = encryption_level_;
for (int8_t i = INITIAL_DATA; i <= APPLICATION_DATA; ++i) {
@@ -3651,6 +3834,18 @@ QuicPacketNumber QuicConnection::GetLargestReceivedPacket() const {
last_decrypted_packet_level_);
}
+bool QuicConnection::EnforceAntiAmplificationLimit() const {
+ return version().SupportsAntiAmplificationLimit() &&
+ perspective_ == Perspective::IS_SERVER && !address_validated_;
+}
+
+bool QuicConnection::LimitedByAmplificationFactor() const {
+ return EnforceAntiAmplificationLimit() &&
+ bytes_sent_before_address_validation_ >=
+ GetQuicFlag(FLAGS_quic_anti_amplification_factor) *
+ bytes_received_before_address_validation_;
+}
+
size_t QuicConnection::min_received_before_ack_decimation() const {
return uber_received_packet_manager_.min_received_before_ack_decimation();
}
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 59a3656364d..6a5062aadbb 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
@@ -134,10 +134,14 @@ class QUIC_EXPORT_PRIVATE QuicConnectionVisitorInterface {
virtual void OnSuccessfulVersionNegotiation(
const ParsedQuicVersion& version) = 0;
- // Called when a connectivity probe has been received by the connection.
- virtual void OnConnectivityProbeReceived(
- const QuicSocketAddress& self_address,
- const QuicSocketAddress& peer_address) = 0;
+ // Called when a packet has been received by the connection, after being
+ // validated and parsed. Only called when the client receives a valid packet
+ // or the server receives a connectivity probing packet.
+ // |is_connectivity_probe| is true if the received packet is a connectivity
+ // probe.
+ virtual void OnPacketReceived(const QuicSocketAddress& self_address,
+ const QuicSocketAddress& peer_address,
+ bool is_connectivity_probe) = 0;
// Called when a blocked socket becomes writable.
virtual void OnCanWrite() = 0;
@@ -476,6 +480,9 @@ class QUIC_EXPORT_PRIVATE QuicConnection
void OnDecryptedPacket(EncryptionLevel level) override;
bool OnPacketHeader(const QuicPacketHeader& header) override;
void OnCoalescedPacket(const QuicEncryptedPacket& packet) override;
+ void OnUndecryptablePacket(const QuicEncryptedPacket& packet,
+ EncryptionLevel decryption_level,
+ bool has_decryption_key) override;
bool OnStreamFrame(const QuicStreamFrame& frame) override;
bool OnCryptoFrame(const QuicCryptoFrame& frame) override;
bool OnAckFrameStart(QuicPacketNumber largest_acked,
@@ -526,9 +533,10 @@ class QUIC_EXPORT_PRIVATE QuicConnection
// ack_frame().
const QuicFrame GetUpdatedAckFrame();
- // Called by the crypto stream when the handshake completes. In the server's
- // case this is when the SHLO has been ACKed. Clients call this on receipt of
- // the SHLO.
+ // Called when the handshake completes. On the client side, handshake
+ // completes on receipt of SHLO. On the server side, handshake completes when
+ // SHLO gets ACKed (or a forward secure packet gets decrypted successfully).
+ // TODO(fayang): Add a guard that this only gets called once.
void OnHandshakeComplete();
// Accessors
@@ -683,6 +691,10 @@ class QUIC_EXPORT_PRIVATE QuicConnection
// Returns the underlying sent packet manager.
QuicSentPacketManager& sent_packet_manager() { return sent_packet_manager_; }
+ UberReceivedPacketManager& received_packet_manager() {
+ return uber_received_packet_manager_;
+ }
+
bool CanWrite(HasRetransmittableData retransmittable);
// When the flusher is out of scope, only the outermost flusher will cause a
@@ -961,6 +973,8 @@ class QUIC_EXPORT_PRIVATE QuicConnection
void TearDownLocalConnectionState(QuicErrorCode error,
const std::string& details,
ConnectionCloseSource source);
+ void TearDownLocalConnectionState(const QuicConnectionCloseFrame& frame,
+ ConnectionCloseSource source);
// Writes the given packet to socket, encrypted with packet's
// encryption_level. Returns true on successful write, and false if the writer
@@ -980,7 +994,7 @@ class QUIC_EXPORT_PRIVATE QuicConnection
const QuicStopWaitingFrame& stop_waiting);
// Sends a version negotiation packet to the peer.
- void SendVersionNegotiationPacket(bool ietf_quic);
+ void SendVersionNegotiationPacket(bool ietf_quic, bool has_length_prefix);
// Clears any accumulated frames from the last received packet.
void ClearLastFrames();
@@ -1120,6 +1134,12 @@ class QUIC_EXPORT_PRIVATE QuicConnection
// Whether incoming_connection_ids_ contains connection_id.
bool HasIncomingConnectionId(QuicConnectionId connection_id);
+ // Whether connection enforces anti-amplification limit.
+ bool EnforceAntiAmplificationLimit() const;
+
+ // Whether connection is limited by amplification factor.
+ bool LimitedByAmplificationFactor() const;
+
QuicFramer framer_;
// Contents received in the current packet, especially used to identify
@@ -1217,6 +1237,7 @@ class QUIC_EXPORT_PRIVATE QuicConnection
bool pending_version_negotiation_packet_;
// Used when pending_version_negotiation_packet_ is true.
bool send_ietf_version_negotiation_packet_;
+ bool send_version_negotiation_packet_with_prefixed_lengths_;
// When packets could not be sent because the socket was not writable,
// they are added to this list. All corresponding frames are in
@@ -1424,6 +1445,24 @@ class QUIC_EXPORT_PRIVATE QuicConnection
// Indicates whether a RETRY packet has been parsed.
bool retry_has_been_parsed_;
+
+ // If max_consecutive_ptos_ > 0, close connection if consecutive PTOs is
+ // greater than max_consecutive_ptos.
+ size_t max_consecutive_ptos_;
+
+ // Bytes received before address validation. Only used when
+ // EnforceAntiAmplificationLimit returns true.
+ size_t bytes_received_before_address_validation_;
+
+ // Bytes sent before address validation. Only used when
+ // EnforceAntiAmplificationLimit returns true.
+ size_t bytes_sent_before_address_validation_;
+
+ // True if peer address has been validated. Address is considered validated
+ // when 1) an address token is received and validated, or 2) a HANDSHAKE
+ // packet has been successfully processed. Only used when
+ // EnforceAntiAmplificationLimit returns true.
+ bool address_validated_;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_connection_id.cc b/chromium/net/third_party/quiche/src/quic/core/quic_connection_id.cc
index c560bcca98f..67b5d1325c6 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_connection_id.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_connection_id.cc
@@ -53,22 +53,18 @@ class QuicConnectionIdHasher {
QuicConnectionId::QuicConnectionId() : QuicConnectionId(nullptr, 0) {}
QuicConnectionId::QuicConnectionId(const char* data, uint8_t length) {
- static_assert(
- kQuicMaxConnectionIdLength <= std::numeric_limits<uint8_t>::max(),
- "kQuicMaxConnectionIdLength too high");
- if (length > kQuicMaxConnectionIdLength) {
- QUIC_BUG << "Attempted to create connection ID of length " << length;
- length = kQuicMaxConnectionIdLength;
+ static_assert(kQuicMaxConnectionIdAllVersionsLength <=
+ std::numeric_limits<uint8_t>::max(),
+ "kQuicMaxConnectionIdAllVersionsLength too high");
+ if (length > kQuicMaxConnectionIdAllVersionsLength) {
+ QUIC_BUG << "Attempted to create connection ID of length "
+ << static_cast<int>(length);
+ length = kQuicMaxConnectionIdAllVersionsLength;
}
length_ = length;
if (length_ == 0) {
return;
}
- if (!GetQuicRestartFlag(quic_use_allocated_connection_ids)) {
- memcpy(data_, data, length_);
- return;
- }
- QUIC_RESTART_FLAG_COUNT_N(quic_use_allocated_connection_ids, 1, 6);
if (length_ <= sizeof(data_short_)) {
memcpy(data_short_, data, length_);
return;
@@ -79,10 +75,6 @@ QuicConnectionId::QuicConnectionId(const char* data, uint8_t length) {
}
QuicConnectionId::~QuicConnectionId() {
- if (!GetQuicRestartFlag(quic_use_allocated_connection_ids)) {
- return;
- }
- QUIC_RESTART_FLAG_COUNT_N(quic_use_allocated_connection_ids, 2, 6);
if (length_ > sizeof(data_short_)) {
free(data_long_);
data_long_ = nullptr;
@@ -99,10 +91,6 @@ QuicConnectionId& QuicConnectionId::operator=(const QuicConnectionId& other) {
}
const char* QuicConnectionId::data() const {
- if (!GetQuicRestartFlag(quic_use_allocated_connection_ids)) {
- return data_;
- }
- QUIC_RESTART_FLAG_COUNT_N(quic_use_allocated_connection_ids, 3, 6);
if (length_ <= sizeof(data_short_)) {
return data_short_;
}
@@ -110,10 +98,6 @@ const char* QuicConnectionId::data() const {
}
char* QuicConnectionId::mutable_data() {
- if (!GetQuicRestartFlag(quic_use_allocated_connection_ids)) {
- return data_;
- }
- QUIC_RESTART_FLAG_COUNT_N(quic_use_allocated_connection_ids, 4, 6);
if (length_ <= sizeof(data_short_)) {
return data_short_;
}
@@ -125,30 +109,32 @@ uint8_t QuicConnectionId::length() const {
}
void QuicConnectionId::set_length(uint8_t length) {
- if (GetQuicRestartFlag(quic_use_allocated_connection_ids)) {
- QUIC_RESTART_FLAG_COUNT_N(quic_use_allocated_connection_ids, 5, 6);
- char temporary_data[sizeof(data_short_)];
- if (length > sizeof(data_short_)) {
- if (length_ <= sizeof(data_short_)) {
- // Copy data from data_short_ to data_long_.
- memcpy(temporary_data, data_short_, length_);
- data_long_ = reinterpret_cast<char*>(malloc(length));
- CHECK_NE(nullptr, data_long_);
- memcpy(data_long_, temporary_data, length_);
- } else {
- // Resize data_long_.
- char* realloc_result =
- reinterpret_cast<char*>(realloc(data_long_, length));
- CHECK_NE(nullptr, realloc_result);
- data_long_ = realloc_result;
- }
- } else if (length_ > sizeof(data_short_)) {
- // Copy data from data_long_ to data_short_.
- memcpy(temporary_data, data_long_, length);
- free(data_long_);
- data_long_ = nullptr;
- memcpy(data_short_, temporary_data, length);
+ if (length > kQuicMaxConnectionIdAllVersionsLength) {
+ QUIC_BUG << "Attempted to set connection ID length to "
+ << static_cast<int>(length);
+ length = kQuicMaxConnectionIdAllVersionsLength;
+ }
+ char temporary_data[sizeof(data_short_)];
+ if (length > sizeof(data_short_)) {
+ if (length_ <= sizeof(data_short_)) {
+ // Copy data from data_short_ to data_long_.
+ memcpy(temporary_data, data_short_, length_);
+ data_long_ = reinterpret_cast<char*>(malloc(length));
+ CHECK_NE(nullptr, data_long_);
+ memcpy(data_long_, temporary_data, length_);
+ } else {
+ // Resize data_long_.
+ char* realloc_result =
+ reinterpret_cast<char*>(realloc(data_long_, length));
+ CHECK_NE(nullptr, realloc_result);
+ data_long_ = realloc_result;
}
+ } else if (length_ > sizeof(data_short_)) {
+ // Copy data from data_long_ to data_short_.
+ memcpy(temporary_data, data_long_, length);
+ free(data_long_);
+ data_long_ = nullptr;
+ memcpy(data_short_, temporary_data, length);
}
length_ = length;
}
@@ -160,8 +146,8 @@ bool QuicConnectionId::IsEmpty() const {
size_t QuicConnectionId::Hash() const {
if (!GetQuicRestartFlag(quic_connection_id_use_siphash)) {
uint64_t data_bytes[3] = {0, 0, 0};
- static_assert(sizeof(data_bytes) >= kQuicMaxConnectionIdLength,
- "kQuicMaxConnectionIdLength changed");
+ static_assert(sizeof(data_bytes) >= kQuicMaxConnectionIdAllVersionsLength,
+ "kQuicMaxConnectionIdAllVersionsLength changed");
memcpy(data_bytes, data(), length_);
// This Hash function is designed to return the same value as the host byte
// order representation when the connection ID length is 64 bits.
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_connection_id.h b/chromium/net/third_party/quiche/src/quic/core/quic_connection_id.h
index 6b1b0bc5ff5..431cc741f60 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_connection_id.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_connection_id.h
@@ -25,8 +25,16 @@ enum QuicConnectionIdIncluded : uint8_t {
CONNECTION_ID_ABSENT = 2,
};
-// Connection IDs can be 0-18 bytes per IETF specifications.
-const uint8_t kQuicMaxConnectionIdLength = 18;
+// Maximum connection ID length that we support in any packet or version.
+const uint8_t kQuicMaxConnectionIdAllVersionsLength = 20;
+
+// Maximum connection ID length supported by versions that use the encoding from
+// draft-ietf-quic-invariants-06.
+const uint8_t kQuicMaxConnectionIdWithLengthPrefixLength = 20;
+
+// Maximum connection ID length supported by versions that use the encoding from
+// draft-ietf-quic-invariants-05.
+const uint8_t kQuicMaxConnectionId4BitLength = 18;
// kQuicDefaultConnectionIdLength is the only supported length for QUIC
// versions < v99, and is the default picked for all versions.
@@ -97,15 +105,12 @@ class QUIC_EXPORT_PRIVATE QuicConnectionId {
uint8_t length_; // length of the connection ID, in bytes.
// The connection ID is represented in network byte order.
union {
- // When quic_use_allocated_connection_ids is false, the connection ID is
- // stored in the first |length_| bytes of |data_|.
- char data_[kQuicMaxConnectionIdLength];
- // When quic_use_allocated_connection_ids is true, if the connection ID
- // fits in |data_short_|, it is stored in the first |length_| bytes of
- // |data_short_|. Otherwise it is stored in |data_long_| which is
- // guaranteed to have a size equal to |length_|. A value of 11 was chosen
- // because our commonly used connection ID length is 8 and with the length,
- // the class is padded to 12 bytes anyway.
+ // If the connection ID fits in |data_short_|, it is stored in the
+ // first |length_| bytes of |data_short_|.
+ // Otherwise it is stored in |data_long_| which is guaranteed to have a size
+ // equal to |length_|.
+ // A value of 11 was chosen because our commonly used connection ID length
+ // is 8 and with the length, the class is padded to 12 bytes anyway.
char data_short_[11];
char* data_long_;
};
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_connection_id_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_connection_id_test.cc
index 0d4b190dbd8..d80babbfa66 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_connection_id_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_connection_id_test.cc
@@ -98,10 +98,10 @@ TEST_F(QuicConnectionIdTest, Hash) {
// 32bit platforms.
return;
}
- const char connection_id_bytes[kQuicMaxConnectionIdLength] = {};
- for (uint8_t i = 0; i < kQuicMaxConnectionIdLength - 1; ++i) {
+ const char connection_id_bytes[kQuicMaxConnectionIdAllVersionsLength] = {};
+ for (uint8_t i = 0; i < sizeof(connection_id_bytes) - 1; ++i) {
QuicConnectionId connection_id_i(connection_id_bytes, i);
- for (uint8_t j = i + 1; j < kQuicMaxConnectionIdLength; ++j) {
+ for (uint8_t j = i + 1; j < sizeof(connection_id_bytes); ++j) {
QuicConnectionId connection_id_j(connection_id_bytes, j);
EXPECT_NE(connection_id_i.Hash(), connection_id_j.Hash());
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.cc b/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.cc
index 246b9f1200c..98859acce32 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.cc
@@ -34,6 +34,7 @@ QuicConnectionStats::QuicConnectionStats()
loss_timeout_count(0),
tlp_count(0),
rto_count(0),
+ pto_count(0),
min_rtt_us(0),
srtt_us(0),
max_packet_size(0),
@@ -77,6 +78,7 @@ std::ostream& operator<<(std::ostream& os, const QuicConnectionStats& s) {
os << " loss_timeout_count: " << s.loss_timeout_count;
os << " tlp_count: " << s.tlp_count;
os << " rto_count: " << s.rto_count;
+ os << " pto_count: " << s.pto_count;
os << " min_rtt_us: " << s.min_rtt_us;
os << " srtt_us: " << s.srtt_us;
os << " max_packet_size: " << s.max_packet_size;
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.h b/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.h
index 5317c7a6180..56bb510cda5 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.h
@@ -76,6 +76,7 @@ struct QUIC_EXPORT_PRIVATE QuicConnectionStats {
size_t loss_timeout_count;
size_t tlp_count;
size_t rto_count; // Count of times the rto timer fired.
+ size_t pto_count;
int64_t min_rtt_us; // Minimum RTT in microseconds.
int64_t srtt_us; // Smoothed RTT in microseconds.
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 ee7b6511193..ec096866656 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
@@ -341,7 +341,10 @@ class TestPacketWriter : public QuicPacketWriter {
clock_(clock),
write_pause_time_delta_(QuicTime::Delta::Zero()),
max_packet_size_(kMaxOutgoingPacketSize),
- supports_release_time_(false) {}
+ supports_release_time_(false) {
+ QuicFramerPeer::SetLastSerializedServerConnectionId(framer_.framer(),
+ TestConnectionId());
+ }
TestPacketWriter(const TestPacketWriter&) = delete;
TestPacketWriter& operator=(const TestPacketWriter&) = delete;
@@ -664,6 +667,12 @@ class TestConnection : public QuicConnection {
if (!QuicUtils::IsCryptoStreamId(transport_version(), id) &&
this->encryption_level() == ENCRYPTION_INITIAL) {
this->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+ if (perspective() == Perspective::IS_CLIENT && !IsHandshakeConfirmed()) {
+ OnHandshakeComplete();
+ }
+ if (version().SupportsAntiAmplificationLimit()) {
+ QuicConnectionPeer::SetAddressValidated(this);
+ }
}
struct iovec iov;
MakeIOVector(data, &iov);
@@ -820,6 +829,16 @@ class TestConnection : public QuicConnection {
next_effective_peer_addr_ = QuicMakeUnique<QuicSocketAddress>(addr);
}
+ bool PtoEnabled() {
+ if (QuicConnectionPeer::GetSentPacketManager(this)->pto_enabled()) {
+ // PTO mode is default enabled for T099. And TLP/RTO related tests are
+ // stale.
+ DCHECK_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_99), version());
+ return true;
+ }
+ return false;
+ }
+
SimpleDataProducer* producer() { return &producer_; }
using QuicConnection::active_effective_peer_migration_type;
@@ -1010,7 +1029,7 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> {
EXPECT_CALL(visitor_, ShouldKeepConnectionAlive())
.WillRepeatedly(Return(false));
EXPECT_CALL(visitor_, OnCongestionWindowChange(_)).Times(AnyNumber());
- EXPECT_CALL(visitor_, OnConnectivityProbeReceived(_, _)).Times(AnyNumber());
+ EXPECT_CALL(visitor_, OnPacketReceived(_, _, _)).Times(AnyNumber());
EXPECT_CALL(visitor_, OnForwardProgressConfirmed()).Times(AnyNumber());
EXPECT_CALL(*loss_algorithm_, GetLossTimeout())
@@ -1133,9 +1152,7 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> {
header.destination_connection_id = connection_id_;
header.packet_number_length = packet_number_length_;
header.destination_connection_id_included = connection_id_included_;
- if ((VersionHasIetfInvariantHeader(peer_framer_.transport_version()) ||
- GetQuicRestartFlag(quic_do_not_override_connection_id)) &&
- peer_framer_.perspective() == Perspective::IS_SERVER) {
+ if (peer_framer_.perspective() == Perspective::IS_SERVER) {
header.destination_connection_id_included = CONNECTION_ID_ABSENT;
}
if (level == ENCRYPTION_INITIAL &&
@@ -1146,10 +1163,7 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> {
header.length_length = VARIABLE_LENGTH_INTEGER_LENGTH_2;
}
}
- if ((GetQuicRestartFlag(quic_do_not_override_connection_id) ||
- (level == ENCRYPTION_INITIAL &&
- peer_framer_.version().KnowsWhichDecrypterToUse())) &&
- header.version_flag &&
+ if (header.version_flag &&
peer_framer_.perspective() == Perspective::IS_SERVER) {
header.source_connection_id = connection_id_;
header.source_connection_id_included = CONNECTION_ID_PRESENT;
@@ -1217,6 +1231,7 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> {
} else {
frames.push_back(QuicFrame(frame1_));
}
+ frames.push_back(QuicFrame(QuicPaddingFrame(-1)));
std::unique_ptr<QuicPacket> packet = ConstructPacket(header, frames);
char buffer[kMaxOutgoingPacketSize];
peer_creator_.set_encryption_level(ENCRYPTION_INITIAL);
@@ -1268,8 +1283,10 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> {
StreamSendingState state,
QuicPacketNumber* last_packet) {
QuicByteCount packet_size;
+ // Save the last packet's size.
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
- .WillOnce(SaveArg<3>(&packet_size));
+ .Times(AnyNumber())
+ .WillRepeatedly(SaveArg<3>(&packet_size));
connection_.SendStreamDataWithString(id, data, offset, state);
if (last_packet != nullptr) {
*last_packet = creator_->packet_number();
@@ -1371,8 +1388,7 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> {
}
// Set connection_id to peer's in memory representation as this data packet
// is created by peer_framer.
- if (GetQuicRestartFlag(quic_do_not_override_connection_id) &&
- peer_framer_.perspective() == Perspective::IS_SERVER) {
+ if (peer_framer_.perspective() == Perspective::IS_SERVER) {
header.source_connection_id = connection_id_;
header.source_connection_id_included = connection_id_included_;
header.destination_connection_id_included = CONNECTION_ID_ABSENT;
@@ -1425,8 +1441,7 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> {
QuicPacketHeader header;
// Set connection_id to peer's in memory representation as this connection
// close packet is created by peer_framer.
- if (GetQuicRestartFlag(quic_do_not_override_connection_id) &&
- peer_framer_.perspective() == Perspective::IS_SERVER) {
+ if (peer_framer_.perspective() == Perspective::IS_SERVER) {
header.source_connection_id = connection_id_;
header.destination_connection_id_included = CONNECTION_ID_ABSENT;
if (!VersionHasIetfInvariantHeader(peer_framer_.transport_version())) {
@@ -1441,11 +1456,26 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> {
header.packet_number = QuicPacketNumber(number);
- QuicConnectionCloseFrame qccf(QUIC_PEER_GOING_AWAY, "");
+ QuicErrorCode kQuicErrorCode = QUIC_PEER_GOING_AWAY;
+ // This QuicConnectionCloseFrame will default to being for a Google QUIC
+ // close. If doing IETF QUIC then set fields appropriately for CC/T or CC/A,
+ // depending on the mapping.
+ QuicConnectionCloseFrame qccf(kQuicErrorCode, "");
if (VersionHasIetfQuicFrames(peer_framer_.transport_version())) {
- // Default close-type is Google QUIC. If doing IETF QUIC then
- // set close type to be IETF CC/T.
- qccf.close_type = IETF_QUIC_TRANSPORT_CONNECTION_CLOSE;
+ QuicErrorCodeToIetfMapping mapping =
+ QuicErrorCodeToTransportErrorCode(kQuicErrorCode);
+ if (mapping.is_transport_close_) {
+ // Maps to a transport close
+ qccf.close_type = IETF_QUIC_TRANSPORT_CONNECTION_CLOSE;
+ qccf.transport_error_code = mapping.transport_error_code_;
+ // Frame type is not important for the tests that invoke this method.
+ qccf.transport_close_frame_type = 0;
+ } else {
+ // Maps to an application close.
+ qccf.close_type = IETF_QUIC_APPLICATION_CONNECTION_CLOSE;
+ qccf.application_error_code = mapping.application_error_code_;
+ }
+ qccf.extracted_error_code = kQuicErrorCode;
}
QuicFrames frames;
@@ -1560,7 +1590,32 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> {
const std::vector<QuicConnectionCloseFrame>& connection_close_frames =
writer_->connection_close_frames();
ASSERT_EQ(1u, connection_close_frames.size());
- EXPECT_EQ(expected_code, connection_close_frames[0].quic_error_code);
+ if (!VersionHasIetfQuicFrames(version().transport_version)) {
+ EXPECT_EQ(expected_code, connection_close_frames[0].quic_error_code);
+ EXPECT_EQ(GOOGLE_QUIC_CONNECTION_CLOSE,
+ connection_close_frames[0].close_type);
+ return;
+ }
+
+ QuicErrorCodeToIetfMapping mapping =
+ QuicErrorCodeToTransportErrorCode(expected_code);
+
+ if (mapping.is_transport_close_) {
+ // This Google QUIC Error Code maps to a transport close,
+ EXPECT_EQ(IETF_QUIC_TRANSPORT_CONNECTION_CLOSE,
+ connection_close_frames[0].close_type);
+ EXPECT_EQ(mapping.transport_error_code_,
+ connection_close_frames[0].transport_error_code);
+ // TODO(fkastenholz): when the extracted error code CL lands,
+ // need to test that extracted==expected.
+ } else {
+ // This maps to an application close.
+ EXPECT_EQ(expected_code, connection_close_frames[0].quic_error_code);
+ EXPECT_EQ(IETF_QUIC_APPLICATION_CONNECTION_CLOSE,
+ connection_close_frames[0].close_type);
+ // TODO(fkastenholz): when the extracted error code CL lands,
+ // need to test that extracted==expected.
+ }
}
QuicConnectionId connection_id_;
@@ -1601,6 +1656,36 @@ INSTANTIATE_TEST_SUITE_P(SupportedVersion,
QuicConnectionTest,
::testing::ValuesIn(GetTestParams()));
+// These two tests ensure that the QuicErrorCode mapping works correctly.
+// Both tests expect to see a Google QUIC close if not running IETF QUIC.
+// If running IETF QUIC, the first will generate a transport connection
+// close, the second an application connection close.
+// The connection close codes for the two tests are manually chosen;
+// they are expected to always map to transport- and application-
+// closes, respectively. If that changes, mew codes should be chosen.
+TEST_P(QuicConnectionTest, CloseErrorCodeTestTransport) {
+ EXPECT_TRUE(connection_.connected());
+ EXPECT_CALL(visitor_, OnConnectionClosed(_, _));
+ connection_.CloseConnection(
+ IETF_QUIC_PROTOCOL_VIOLATION, "Should be transport close",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ EXPECT_FALSE(connection_.connected());
+ TestConnectionCloseQuicErrorCode(IETF_QUIC_PROTOCOL_VIOLATION);
+}
+
+// Test that the IETF QUIC Error code mapping function works
+// properly for application connection close codes.
+TEST_P(QuicConnectionTest, CloseErrorCodeTestApplication) {
+ EXPECT_TRUE(connection_.connected());
+ EXPECT_CALL(visitor_, OnConnectionClosed(_, _));
+ connection_.CloseConnection(
+ QUIC_HEADERS_STREAM_DATA_DECOMPRESS_FAILURE,
+ "Should be application close",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ EXPECT_FALSE(connection_.connected());
+ TestConnectionCloseQuicErrorCode(QUIC_HEADERS_STREAM_DATA_DECOMPRESS_FAILURE);
+}
+
TEST_P(QuicConnectionTest, SelfAddressChangeAtClient) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
@@ -1889,7 +1974,7 @@ TEST_P(QuicConnectionTest, ReceivePaddedPingAtServer) {
EXPECT_EQ(kPeerAddress, connection_.effective_peer_address());
EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(0);
- EXPECT_CALL(visitor_, OnConnectivityProbeReceived(_, _)).Times(0);
+ EXPECT_CALL(visitor_, OnPacketReceived(_, _, false)).Times(0);
// Process a padded PING or PATH CHALLENGE packet with no peer address change
// on server side will be ignored.
@@ -2004,7 +2089,7 @@ TEST_P(QuicConnectionTest, ReceiveConnectivityProbingAtServer) {
EXPECT_EQ(kPeerAddress, connection_.effective_peer_address());
EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(0);
- EXPECT_CALL(visitor_, OnConnectivityProbeReceived(_, _)).Times(1);
+ EXPECT_CALL(visitor_, OnPacketReceived(_, _, true)).Times(1);
// Process a padded PING packet from a new peer address on server side
// is effectively receiving a connectivity probing.
@@ -2067,7 +2152,7 @@ TEST_P(QuicConnectionTest, ReceiveReorderedConnectivityProbingAtServer) {
QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 4);
EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(0);
- EXPECT_CALL(visitor_, OnConnectivityProbeReceived(_, _)).Times(1);
+ EXPECT_CALL(visitor_, OnPacketReceived(_, _, true)).Times(1);
// Process a padded PING packet from a new peer address on server side
// is effectively receiving a connectivity probing, even if a newer packet has
@@ -2120,7 +2205,7 @@ TEST_P(QuicConnectionTest, MigrateAfterProbingAtServer) {
EXPECT_EQ(kPeerAddress, connection_.effective_peer_address());
EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(0);
- EXPECT_CALL(visitor_, OnConnectivityProbeReceived(_, _)).Times(1);
+ EXPECT_CALL(visitor_, OnPacketReceived(_, _, true)).Times(1);
// Process a padded PING packet from a new peer address on server side
// is effectively receiving a connectivity probing.
@@ -2175,7 +2260,7 @@ TEST_P(QuicConnectionTest, ReceivePaddedPingAtClient) {
// Client takes all padded PING packet as speculative connectivity
// probing packet, and reports to visitor.
EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(0);
- EXPECT_CALL(visitor_, OnConnectivityProbeReceived(_, _)).Times(1);
+ EXPECT_CALL(visitor_, OnPacketReceived(_, _, false)).Times(1);
OwningSerializedPacketPointer probing_packet = ConstructProbingPacket();
std::unique_ptr<QuicReceivedPacket> received(ConstructReceivedPacket(
@@ -2222,7 +2307,7 @@ TEST_P(QuicConnectionTest, ReceiveConnectivityProbingAtClient) {
// Process a padded PING packet with a different self address on client side
// is effectively receiving a connectivity probing.
EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(0);
- EXPECT_CALL(visitor_, OnConnectivityProbeReceived(_, _)).Times(1);
+ EXPECT_CALL(visitor_, OnPacketReceived(_, _, true)).Times(1);
const QuicSocketAddress kNewSelfAddress =
QuicSocketAddress(QuicIpAddress::Loopback6(), /*port=*/23456);
@@ -3380,7 +3465,12 @@ TEST_P(QuicConnectionTest, CancelRetransmissionAlarmAfterResetStream) {
// Ensure that the data is still in flight, but the retransmission alarm is no
// longer set.
EXPECT_GT(manager_->GetBytesInFlight(), 0u);
- EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
+ if (QuicConnectionPeer::GetSentPacketManager(&connection_)
+ ->fix_rto_retransmission()) {
+ EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
+ } else {
+ EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
+ }
}
TEST_P(QuicConnectionTest, RetransmitForQuicRstStreamNoErrorOnRTO) {
@@ -3543,6 +3633,9 @@ TEST_P(QuicConnectionTest, RetransmitNackedLargestObserved) {
}
TEST_P(QuicConnectionTest, QueueAfterTwoRTOs) {
+ if (connection_.PtoEnabled()) {
+ return;
+ }
connection_.SetMaxTailLossProbes(0);
for (int i = 0; i < 10; ++i) {
@@ -3623,7 +3716,12 @@ TEST_P(QuicConnectionTest, RetransmitWriteBlockedAckedOriginalThenSent) {
writer_->SetWritable();
connection_.OnCanWrite();
- EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
+ if (QuicConnectionPeer::GetSentPacketManager(&connection_)
+ ->fix_rto_retransmission()) {
+ EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
+ } else {
+ EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
+ }
EXPECT_FALSE(QuicConnectionPeer::HasRetransmittableFrames(&connection_, 2));
}
@@ -3875,7 +3973,8 @@ TEST_P(QuicConnectionTest, TLP) {
}
TEST_P(QuicConnectionTest, TailLossProbeDelayForStreamDataInTLPR) {
- if (!connection_.session_decides_what_to_write()) {
+ if (!connection_.session_decides_what_to_write() ||
+ connection_.PtoEnabled()) {
return;
}
@@ -3910,7 +4009,8 @@ TEST_P(QuicConnectionTest, TailLossProbeDelayForStreamDataInTLPR) {
}
TEST_P(QuicConnectionTest, TailLossProbeDelayForNonStreamDataInTLPR) {
- if (!connection_.session_decides_what_to_write()) {
+ if (!connection_.session_decides_what_to_write() ||
+ connection_.PtoEnabled()) {
return;
}
@@ -4051,6 +4151,9 @@ TEST_P(QuicConnectionTest, TailLossProbeDelayForNonStreamDataInTLPR) {
}
TEST_P(QuicConnectionTest, RTO) {
+ if (connection_.PtoEnabled()) {
+ return;
+ }
connection_.SetMaxTailLossProbes(0);
QuicTime default_retransmission_time =
@@ -4072,7 +4175,8 @@ TEST_P(QuicConnectionTest, RTO) {
// Regression test of b/133771183.
TEST_P(QuicConnectionTest, RtoWithNoDataToRetransmit) {
- if (!connection_.session_decides_what_to_write()) {
+ if (!connection_.session_decides_what_to_write() ||
+ connection_.PtoEnabled()) {
return;
}
connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
@@ -4087,25 +4191,25 @@ TEST_P(QuicConnectionTest, RtoWithNoDataToRetransmit) {
// Simulate the retransmission alarm firing.
clock_.AdvanceTime(DefaultRetransmissionTime());
// RTO fires, but there is no packet to be RTOed.
- if (GetQuicReloadableFlag(quic_fix_rto_retransmission)) {
+ if (GetQuicReloadableFlag(quic_fix_rto_retransmission3)) {
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
} else {
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
}
connection_.GetRetransmissionAlarm()->Fire();
- if (GetQuicReloadableFlag(quic_fix_rto_retransmission)) {
+ if (GetQuicReloadableFlag(quic_fix_rto_retransmission3)) {
EXPECT_EQ(1u, writer_->rst_stream_frames().size());
}
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(40);
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(20);
- if (GetQuicReloadableFlag(quic_fix_rto_retransmission)) {
+ if (GetQuicReloadableFlag(quic_fix_rto_retransmission3)) {
EXPECT_CALL(visitor_, WillingAndAbleToWrite())
.WillRepeatedly(Return(false));
} else {
EXPECT_CALL(visitor_, WillingAndAbleToWrite()).WillRepeatedly(Return(true));
}
- if (GetQuicReloadableFlag(quic_fix_rto_retransmission)) {
+ if (GetQuicReloadableFlag(quic_fix_rto_retransmission3)) {
EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(1);
} else {
// Since there is a buffered RST_STREAM, no retransmittable frame is bundled
@@ -4266,6 +4370,9 @@ TEST_P(QuicConnectionTest, BufferNonDecryptablePackets) {
}
TEST_P(QuicConnectionTest, TestRetransmitOrder) {
+ if (connection_.PtoEnabled()) {
+ return;
+ }
connection_.SetMaxTailLossProbes(0);
QuicByteCount first_packet_size;
@@ -4351,6 +4458,9 @@ TEST_P(QuicConnectionTest, SetRTOAfterWritingToSocket) {
}
TEST_P(QuicConnectionTest, DelayRTOWithAckReceipt) {
+ if (connection_.PtoEnabled()) {
+ return;
+ }
connection_.SetMaxTailLossProbes(0);
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
@@ -5054,6 +5164,9 @@ TEST_P(QuicConnectionTest, TimeoutAfterSend) {
}
TEST_P(QuicConnectionTest, TimeoutAfterRetransmission) {
+ if (connection_.PtoEnabled()) {
+ return;
+ }
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
EXPECT_TRUE(connection_.connected());
EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
@@ -5204,6 +5317,9 @@ TEST_P(QuicConnectionTest, NewTimeoutAfterSendSilentClose) {
}
TEST_P(QuicConnectionTest, TimeoutAfterSendSilentCloseAndTLP) {
+ if (connection_.PtoEnabled()) {
+ return;
+ }
// Same test as above, but complete a handshake which enables silent close,
// but sending TLPs causes the connection close to be sent.
EXPECT_TRUE(connection_.connected());
@@ -5430,6 +5546,9 @@ TEST_P(QuicConnectionTest, TimeoutAfterReceiveNotSendWhenUnacked) {
}
TEST_P(QuicConnectionTest, TimeoutAfter5ClientRTOs) {
+ if (connection_.PtoEnabled()) {
+ return;
+ }
connection_.SetMaxTailLossProbes(2);
EXPECT_TRUE(connection_.connected());
EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
@@ -6774,16 +6893,20 @@ TEST_P(QuicConnectionTest, MissingPacketsBeforeLeastUnacked) {
}
TEST_P(QuicConnectionTest, ClientHandlesVersionNegotiation) {
- // Start out with an unsupported version.
- QuicConnectionPeer::GetFramer(&connection_)
- ->set_version_for_tests(QuicVersionReservedForNegotiation());
+ // All supported versions except the one the connection supports.
+ ParsedQuicVersionVector versions;
+ for (auto version : AllSupportedVersions()) {
+ if (version != connection_.version()) {
+ versions.push_back(version);
+ }
+ }
// Send a version negotiation packet.
std::unique_ptr<QuicEncryptedPacket> encrypted(
QuicFramer::BuildVersionNegotiationPacket(
connection_id_, EmptyQuicConnectionId(),
VersionHasIetfInvariantHeader(connection_.transport_version()),
- AllSupportedVersions()));
+ connection_.version().HasLengthPrefixedConnectionIds(), versions));
std::unique_ptr<QuicReceivedPacket> received(
ConstructReceivedPacket(*encrypted, QuicTime::Zero()));
EXPECT_CALL(visitor_, OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF))
@@ -6804,6 +6927,7 @@ TEST_P(QuicConnectionTest, BadVersionNegotiation) {
QuicFramer::BuildVersionNegotiationPacket(
connection_id_, EmptyQuicConnectionId(),
VersionHasIetfInvariantHeader(connection_.transport_version()),
+ connection_.version().HasLengthPrefixedConnectionIds(),
AllSupportedVersions()));
std::unique_ptr<QuicReceivedPacket> received(
ConstructReceivedPacket(*encrypted, QuicTime::Zero()));
@@ -6814,6 +6938,9 @@ TEST_P(QuicConnectionTest, BadVersionNegotiation) {
}
TEST_P(QuicConnectionTest, CheckSendStats) {
+ if (connection_.PtoEnabled()) {
+ return;
+ }
connection_.SetMaxTailLossProbes(0);
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
@@ -6874,8 +7001,7 @@ TEST_P(QuicConnectionTest, CheckSendStats) {
TEST_P(QuicConnectionTest, ProcessFramesIfPacketClosedConnection) {
// Construct a packet with stream frame and connection close frame.
QuicPacketHeader header;
- if (GetQuicRestartFlag(quic_do_not_override_connection_id) &&
- peer_framer_.perspective() == Perspective::IS_SERVER) {
+ if (peer_framer_.perspective() == Perspective::IS_SERVER) {
header.source_connection_id = connection_id_;
header.destination_connection_id_included = CONNECTION_ID_ABSENT;
if (!VersionHasIetfInvariantHeader(peer_framer_.transport_version())) {
@@ -6890,11 +7016,27 @@ TEST_P(QuicConnectionTest, ProcessFramesIfPacketClosedConnection) {
header.packet_number = QuicPacketNumber(1);
header.version_flag = false;
- QuicConnectionCloseFrame qccf(QUIC_PEER_GOING_AWAY, "");
+ QuicErrorCode kQuicErrorCode = QUIC_PEER_GOING_AWAY;
+ // This QuicConnectionCloseFrame will default to being for a Google QUIC
+ // close. If doing IETF QUIC then set fields appropriately for CC/T or CC/A,
+ // depending on the mapping.
+ QuicConnectionCloseFrame qccf(kQuicErrorCode, "");
if (VersionHasIetfQuicFrames(peer_framer_.transport_version())) {
- // Default close-type is Google QUIC. If doing IETF QUIC then
- // set close type to be IETF CC/T.
- qccf.close_type = IETF_QUIC_TRANSPORT_CONNECTION_CLOSE;
+ QuicErrorCodeToIetfMapping mapping =
+ QuicErrorCodeToTransportErrorCode(kQuicErrorCode);
+ if (mapping.is_transport_close_) {
+ // Maps to a transport close
+ qccf.close_type = IETF_QUIC_TRANSPORT_CONNECTION_CLOSE;
+ qccf.transport_error_code = mapping.transport_error_code_;
+ // TODO(fkastenholz) need to change "0" to get the frame type currently
+ // being processed so that it can be inserted into the frame.
+ qccf.transport_close_frame_type = 0;
+ } else {
+ // Maps to an application close.
+ qccf.close_type = IETF_QUIC_APPLICATION_CONNECTION_CLOSE;
+ qccf.application_error_code = mapping.application_error_code_;
+ }
+ // qccf.extracted_error_code = kQuicErrorCode;
}
QuicFrames frames;
@@ -6917,7 +7059,7 @@ TEST_P(QuicConnectionTest, ProcessFramesIfPacketClosedConnection) {
QuicReceivedPacket(buffer, encrypted_length, QuicTime::Zero(), false));
EXPECT_EQ(1, connection_close_frame_count_);
EXPECT_EQ(QUIC_PEER_GOING_AWAY,
- saved_connection_close_frame_.quic_error_code);
+ saved_connection_close_frame_.extracted_error_code);
}
TEST_P(QuicConnectionTest, SelectMutualVersion) {
@@ -7109,6 +7251,7 @@ TEST_P(QuicConnectionTest, SendPingImmediately) {
connection_.set_debug_visitor(&debug_visitor);
CongestionBlockWrites();
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _, _)).Times(1);
EXPECT_CALL(debug_visitor, OnPingSent()).Times(1);
@@ -7120,6 +7263,7 @@ TEST_P(QuicConnectionTest, SendBlockedImmediately) {
MockQuicConnectionDebugVisitor debug_visitor;
connection_.set_debug_visitor(&debug_visitor);
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _, _)).Times(1);
EXPECT_EQ(0u, connection_.GetStats().blocked_frames_sent);
@@ -7128,6 +7272,22 @@ TEST_P(QuicConnectionTest, SendBlockedImmediately) {
EXPECT_FALSE(connection_.HasQueuedData());
}
+TEST_P(QuicConnectionTest, FailedToSendBlockedFrames) {
+ if (!connection_.SupportsMultiplePacketNumberSpaces()) {
+ return;
+ }
+ MockQuicConnectionDebugVisitor debug_visitor;
+ connection_.set_debug_visitor(&debug_visitor);
+ QuicBlockedFrame blocked(1, 3);
+
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+ EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _, _)).Times(0);
+ EXPECT_EQ(0u, connection_.GetStats().blocked_frames_sent);
+ connection_.SendControlFrame(QuicFrame(&blocked));
+ EXPECT_EQ(0u, connection_.GetStats().blocked_frames_sent);
+ EXPECT_FALSE(connection_.HasQueuedData());
+}
+
TEST_P(QuicConnectionTest, SendingUnencryptedStreamDataFails) {
// EXPECT_QUIC_BUG tests are expensive so only run one instance of them.
if (!IsDefaultTestConfiguration()) {
@@ -8443,7 +8603,6 @@ TEST_P(QuicConnectionTest, CancelAckAlarmOnWriteBlocked) {
// Make sure a packet received with the right client connection ID is processed.
TEST_P(QuicConnectionTest, ValidClientConnectionId) {
- SetQuicRestartFlag(quic_do_not_override_connection_id, true);
if (!framer_.version().SupportsClientConnectionIds()) {
return;
}
@@ -8473,7 +8632,6 @@ TEST_P(QuicConnectionTest, ValidClientConnectionId) {
// Make sure a packet received with a different client connection ID is dropped.
TEST_P(QuicConnectionTest, InvalidClientConnectionId) {
- SetQuicRestartFlag(quic_do_not_override_connection_id, true);
if (!framer_.version().SupportsClientConnectionIds()) {
return;
}
@@ -8503,7 +8661,6 @@ TEST_P(QuicConnectionTest, InvalidClientConnectionId) {
// Make sure the first packet received with a different client connection ID on
// the server is processed and it changes the client connection ID.
TEST_P(QuicConnectionTest, UpdateClientConnectionIdFromFirstPacket) {
- SetQuicRestartFlag(quic_do_not_override_connection_id, true);
if (!framer_.version().SupportsClientConnectionIds()) {
return;
}
@@ -8565,6 +8722,488 @@ TEST_P(QuicConnectionTest, CheckConnectedBeforeFlush) {
EXPECT_FALSE(ack_alarm->IsSet());
}
+// Verify that a packet containing three coalesced packets is parsed correctly.
+TEST_P(QuicConnectionTest, CoalescedPacket) {
+ if (!QuicVersionHasLongHeaderLengths(connection_.transport_version())) {
+ // Coalesced packets can only be encoded using long header lengths.
+ return;
+ }
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ EXPECT_TRUE(connection_.connected());
+ if (QuicVersionUsesCryptoFrames(connection_.transport_version())) {
+ EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(3);
+ } else {
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(3);
+ }
+
+ uint64_t packet_numbers[3] = {1, 2, 3};
+ EncryptionLevel encryption_levels[3] = {
+ ENCRYPTION_INITIAL, ENCRYPTION_INITIAL, ENCRYPTION_FORWARD_SECURE};
+ char buffer[kMaxOutgoingPacketSize] = {};
+ size_t total_encrypted_length = 0;
+ for (int i = 0; i < 3; i++) {
+ QuicPacketHeader header =
+ ConstructPacketHeader(packet_numbers[i], encryption_levels[i]);
+ QuicFrames frames;
+ if (QuicVersionUsesCryptoFrames(connection_.transport_version())) {
+ frames.push_back(QuicFrame(&crypto_frame_));
+ } else {
+ frames.push_back(QuicFrame(frame1_));
+ }
+ std::unique_ptr<QuicPacket> packet = ConstructPacket(header, frames);
+ peer_creator_.set_encryption_level(encryption_levels[i]);
+ size_t encrypted_length = peer_framer_.EncryptPayload(
+ encryption_levels[i], QuicPacketNumber(packet_numbers[i]), *packet,
+ buffer + total_encrypted_length,
+ sizeof(buffer) - total_encrypted_length);
+ EXPECT_GT(encrypted_length, 0u);
+ total_encrypted_length += encrypted_length;
+ }
+ connection_.ProcessUdpPacket(
+ kSelfAddress, kPeerAddress,
+ QuicReceivedPacket(buffer, total_encrypted_length, clock_.Now(), false));
+ if (connection_.GetSendAlarm()->IsSet()) {
+ connection_.GetSendAlarm()->Fire();
+ }
+
+ EXPECT_TRUE(connection_.connected());
+}
+
+// Regression test for crbug.com/992831.
+TEST_P(QuicConnectionTest, CoalescedPacketThatSavesFrames) {
+ if (!QuicVersionHasLongHeaderLengths(connection_.transport_version())) {
+ // Coalesced packets can only be encoded using long header lengths.
+ return;
+ }
+ if (connection_.SupportsMultiplePacketNumberSpaces()) {
+ // TODO(b/129151114) Enable this test with multiple packet number spaces.
+ return;
+ }
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ EXPECT_TRUE(connection_.connected());
+ if (QuicVersionUsesCryptoFrames(connection_.transport_version())) {
+ EXPECT_CALL(visitor_, OnCryptoFrame(_))
+ .Times(3)
+ .WillRepeatedly([this](const QuicCryptoFrame& /*frame*/) {
+ // QuicFrame takes ownership of the QuicBlockedFrame.
+ connection_.SendControlFrame(QuicFrame(new QuicBlockedFrame(1, 3)));
+ });
+ } else {
+ EXPECT_CALL(visitor_, OnStreamFrame(_))
+ .Times(3)
+ .WillRepeatedly([this](const QuicStreamFrame& /*frame*/) {
+ // QuicFrame takes ownership of the QuicBlockedFrame.
+ connection_.SendControlFrame(QuicFrame(new QuicBlockedFrame(1, 3)));
+ });
+ }
+
+ uint64_t packet_numbers[3] = {1, 2, 3};
+ EncryptionLevel encryption_levels[3] = {
+ ENCRYPTION_INITIAL, ENCRYPTION_INITIAL, ENCRYPTION_FORWARD_SECURE};
+ char buffer[kMaxOutgoingPacketSize] = {};
+ size_t total_encrypted_length = 0;
+ for (int i = 0; i < 3; i++) {
+ QuicPacketHeader header =
+ ConstructPacketHeader(packet_numbers[i], encryption_levels[i]);
+ QuicFrames frames;
+ if (QuicVersionUsesCryptoFrames(connection_.transport_version())) {
+ frames.push_back(QuicFrame(&crypto_frame_));
+ } else {
+ frames.push_back(QuicFrame(frame1_));
+ }
+ std::unique_ptr<QuicPacket> packet = ConstructPacket(header, frames);
+ peer_creator_.set_encryption_level(encryption_levels[i]);
+ size_t encrypted_length = peer_framer_.EncryptPayload(
+ encryption_levels[i], QuicPacketNumber(packet_numbers[i]), *packet,
+ buffer + total_encrypted_length,
+ sizeof(buffer) - total_encrypted_length);
+ EXPECT_GT(encrypted_length, 0u);
+ total_encrypted_length += encrypted_length;
+ }
+ connection_.ProcessUdpPacket(
+ kSelfAddress, kPeerAddress,
+ QuicReceivedPacket(buffer, total_encrypted_length, clock_.Now(), false));
+ if (connection_.GetSendAlarm()->IsSet()) {
+ connection_.GetSendAlarm()->Fire();
+ }
+
+ EXPECT_TRUE(connection_.connected());
+
+ SendAckPacketToPeer();
+}
+
+// Regresstion test for b/138962304.
+TEST_P(QuicConnectionTest, RtoAndWriteBlocked) {
+ if (!QuicConnectionPeer::GetSentPacketManager(&connection_)
+ ->fix_rto_retransmission()) {
+ return;
+ }
+ EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
+
+ QuicStreamId stream_id = 2;
+ QuicPacketNumber last_data_packet;
+ SendStreamDataToPeer(stream_id, "foo", 0, NO_FIN, &last_data_packet);
+ EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
+
+ // Writer gets blocked.
+ writer_->SetWriteBlocked();
+
+ // Cancel the stream.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+ EXPECT_CALL(visitor_, OnWriteBlocked()).Times(AtLeast(1));
+ EXPECT_CALL(visitor_, WillingAndAbleToWrite())
+ .WillRepeatedly(
+ Invoke(&notifier_, &SimpleSessionNotifier::WillingToWrite));
+ SendRstStream(stream_id, QUIC_ERROR_PROCESSING_STREAM, 3);
+
+ // Retransmission timer fires in RTO mode.
+ connection_.GetRetransmissionAlarm()->Fire();
+ // Verify no packets get flushed when writer is blocked.
+ EXPECT_EQ(0u, connection_.NumQueuedPackets());
+}
+
+// Regresstion test for b/138962304.
+TEST_P(QuicConnectionTest, TlpAndWriteBlocked) {
+ if (!QuicConnectionPeer::GetSentPacketManager(&connection_)
+ ->fix_rto_retransmission()) {
+ return;
+ }
+ EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
+ connection_.SetMaxTailLossProbes(1);
+
+ QuicStreamId stream_id = 2;
+ QuicPacketNumber last_data_packet;
+ SendStreamDataToPeer(stream_id, "foo", 0, NO_FIN, &last_data_packet);
+ SendStreamDataToPeer(4, "foo", 0, NO_FIN, &last_data_packet);
+ EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
+
+ // Writer gets blocked.
+ writer_->SetWriteBlocked();
+
+ // Cancel stream 2.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+ EXPECT_CALL(visitor_, OnWriteBlocked()).Times(AtLeast(1));
+ SendRstStream(stream_id, QUIC_ERROR_PROCESSING_STREAM, 3);
+
+ // Retransmission timer fires in TLP mode.
+ connection_.GetRetransmissionAlarm()->Fire();
+ // Verify one packets is forced flushed when writer is blocked.
+ EXPECT_EQ(1u, connection_.NumQueuedPackets());
+}
+
+// Regresstion test for b/139375344.
+TEST_P(QuicConnectionTest, RtoForcesSendingPing) {
+ if (!QuicConnectionPeer::GetSentPacketManager(&connection_)
+ ->fix_rto_retransmission() ||
+ connection_.PtoEnabled()) {
+ return;
+ }
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ connection_.SetMaxTailLossProbes(2);
+ EXPECT_EQ(0u, connection_.GetStats().tlp_count);
+ EXPECT_EQ(0u, connection_.GetStats().rto_count);
+
+ SendStreamDataToPeer(2, "foo", 0, NO_FIN, nullptr);
+ QuicTime retransmission_time =
+ connection_.GetRetransmissionAlarm()->deadline();
+ EXPECT_NE(QuicTime::Zero(), retransmission_time);
+ // TLP fires.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(2), _, _));
+ clock_.AdvanceTime(retransmission_time - clock_.Now());
+ connection_.GetRetransmissionAlarm()->Fire();
+ EXPECT_EQ(1u, connection_.GetStats().tlp_count);
+ EXPECT_EQ(0u, connection_.GetStats().rto_count);
+ EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
+
+ // Packet 1 gets acked.
+ QuicAckFrame frame = InitAckFrame(1);
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(_, _, _, _, _));
+ ProcessAckPacket(1, &frame);
+ EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
+ retransmission_time = connection_.GetRetransmissionAlarm()->deadline();
+
+ // RTO fires, verify a PING packet gets sent because there is no data to send.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(3), _, _));
+ EXPECT_CALL(visitor_, SendPing()).WillOnce(Invoke([this]() { SendPing(); }));
+ clock_.AdvanceTime(retransmission_time - clock_.Now());
+ connection_.GetRetransmissionAlarm()->Fire();
+ EXPECT_EQ(1u, connection_.GetStats().tlp_count);
+ EXPECT_EQ(1u, connection_.GetStats().rto_count);
+ EXPECT_EQ(1u, writer_->ping_frames().size());
+}
+
+TEST_P(QuicConnectionTest, ProbeTimeout) {
+ if (!connection_.session_decides_what_to_write() ||
+ !GetQuicReloadableFlag(quic_fix_rto_retransmission3)) {
+ return;
+ }
+ SetQuicReloadableFlag(quic_enable_pto, true);
+ SetQuicReloadableFlag(quic_fix_rto_retransmission3, true);
+ QuicConfig config;
+ QuicTagVector connection_options;
+ connection_options.push_back(k2PTO);
+ config.SetConnectionOptionsToSend(connection_options);
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ connection_.SetFromConfig(config);
+ EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
+
+ QuicStreamId stream_id = 2;
+ QuicPacketNumber last_packet;
+ SendStreamDataToPeer(stream_id, "foooooo", 0, NO_FIN, &last_packet);
+ SendStreamDataToPeer(stream_id, "foooooo", 7, NO_FIN, &last_packet);
+ EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
+
+ // Reset stream.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ SendRstStream(stream_id, QUIC_ERROR_PROCESSING_STREAM, 3);
+
+ // Fire the PTO and verify only the RST_STREAM is resent, not stream data.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ connection_.GetRetransmissionAlarm()->Fire();
+ EXPECT_EQ(0u, writer_->stream_frames().size());
+ EXPECT_EQ(1u, writer_->rst_stream_frames().size());
+ EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
+}
+
+TEST_P(QuicConnectionTest, CloseConnectionAfter7ClientPTOs) {
+ if (!connection_.session_decides_what_to_write() ||
+ !GetQuicReloadableFlag(quic_fix_rto_retransmission3)) {
+ return;
+ }
+ SetQuicReloadableFlag(quic_enable_pto, true);
+ QuicConfig config;
+ QuicTagVector connection_options;
+ connection_options.push_back(k2PTO);
+ connection_options.push_back(k7PTO);
+ config.SetConnectionOptionsToSend(connection_options);
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ connection_.SetFromConfig(config);
+ EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
+
+ // Send stream data.
+ SendStreamDataToPeer(
+ GetNthClientInitiatedStreamId(1, connection_.transport_version()), "foo",
+ 0, FIN, nullptr);
+
+ // Fire the retransmission alarm 6 times.
+ for (int i = 0; i < 6; ++i) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
+ connection_.GetRetransmissionAlarm()->Fire();
+ EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet());
+ EXPECT_TRUE(connection_.connected());
+ }
+
+ EXPECT_EQ(0u, connection_.sent_packet_manager().GetConsecutiveTlpCount());
+ EXPECT_EQ(0u, connection_.sent_packet_manager().GetConsecutiveRtoCount());
+ EXPECT_EQ(6u, connection_.sent_packet_manager().GetConsecutivePtoCount());
+ // Closes connection on 7th PTO.
+ EXPECT_CALL(visitor_,
+ OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF));
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
+ connection_.GetRetransmissionAlarm()->Fire();
+ EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet());
+ EXPECT_FALSE(connection_.connected());
+ TestConnectionCloseQuicErrorCode(QUIC_TOO_MANY_RTOS);
+}
+
+TEST_P(QuicConnectionTest, CloseConnectionAfter8ClientPTOs) {
+ if (!connection_.session_decides_what_to_write() ||
+ !GetQuicReloadableFlag(quic_fix_rto_retransmission3)) {
+ return;
+ }
+ SetQuicReloadableFlag(quic_enable_pto, true);
+ QuicConfig config;
+ QuicTagVector connection_options;
+ connection_options.push_back(k2PTO);
+ connection_options.push_back(k8PTO);
+ config.SetConnectionOptionsToSend(connection_options);
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ connection_.SetFromConfig(config);
+ EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
+
+ // Send stream data.
+ SendStreamDataToPeer(
+ GetNthClientInitiatedStreamId(1, connection_.transport_version()), "foo",
+ 0, FIN, nullptr);
+
+ // Fire the retransmission alarm 7 times.
+ for (int i = 0; i < 7; ++i) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
+ connection_.GetRetransmissionAlarm()->Fire();
+ EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet());
+ EXPECT_TRUE(connection_.connected());
+ }
+
+ EXPECT_EQ(0u, connection_.sent_packet_manager().GetConsecutiveTlpCount());
+ EXPECT_EQ(0u, connection_.sent_packet_manager().GetConsecutiveRtoCount());
+ EXPECT_EQ(7u, connection_.sent_packet_manager().GetConsecutivePtoCount());
+ // Closes connection on 8th PTO.
+ EXPECT_CALL(visitor_,
+ OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF));
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
+ connection_.GetRetransmissionAlarm()->Fire();
+ EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet());
+ EXPECT_FALSE(connection_.connected());
+ TestConnectionCloseQuicErrorCode(QUIC_TOO_MANY_RTOS);
+}
+
+TEST_P(QuicConnectionTest, DeprecateHandshakeMode) {
+ if (!connection_.version().SupportsAntiAmplificationLimit()) {
+ return;
+ }
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
+
+ // Send CHLO.
+ connection_.SendCryptoStreamData();
+ EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
+
+ EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+ QuicAckFrame frame1 = InitAckFrame(1);
+ // Received ACK for packet 1.
+ ProcessFramePacketAtLevel(1, QuicFrame(&frame1), ENCRYPTION_INITIAL);
+
+ // Verify retransmission alarm is still set because handshake is not
+ // confirmed although there is nothing in flight.
+ EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
+ EXPECT_EQ(0u, connection_.GetStats().pto_count);
+ EXPECT_EQ(0u, connection_.GetStats().crypto_retransmit_count);
+
+ // PTO fires, verify a PING packet gets sent because there is no data to send.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(2), _, _));
+ EXPECT_CALL(visitor_, SendPing()).WillOnce(Invoke([this]() { SendPing(); }));
+ connection_.GetRetransmissionAlarm()->Fire();
+ EXPECT_EQ(1u, connection_.GetStats().pto_count);
+ EXPECT_EQ(0u, connection_.GetStats().crypto_retransmit_count);
+ EXPECT_EQ(1u, writer_->ping_frames().size());
+}
+
+TEST_P(QuicConnectionTest, AntiAmplificationLimit) {
+ if (!connection_.version().SupportsAntiAmplificationLimit()) {
+ return;
+ }
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber());
+
+ set_perspective(Perspective::IS_SERVER);
+ // Verify no data can be sent at the beginning because bytes received is 0.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+ connection_.SendCryptoDataWithString("foo", 0);
+ EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
+
+ // Receives packet 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) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ connection_.SendCryptoDataWithString("foo", i * 3);
+ // Verify retransmission alarm is not set if throttled by anti-amplification
+ // limit.
+ EXPECT_EQ(i != anti_amplification_factor - 1,
+ connection_.GetRetransmissionAlarm()->IsSet());
+ }
+ // Verify server is throttled by anti-amplification limit.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+ connection_.SendCryptoDataWithString("foo", anti_amplification_factor * 3);
+
+ // Receives packet 2.
+ ProcessCryptoPacketAtLevel(2, ENCRYPTION_INITIAL);
+ // Verify more packets can be sent.
+ for (size_t i = anti_amplification_factor; i < anti_amplification_factor * 2;
+ ++i) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ connection_.SendCryptoDataWithString("foo", i * 3);
+ }
+ // Verify server is throttled by anti-amplification limit.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+ connection_.SendCryptoDataWithString("foo",
+ 2 * anti_amplification_factor * 3);
+
+ ProcessPacket(3);
+ // Verify anti-amplification limit is gone after address validation.
+ for (size_t i = 0; i < 100; ++i) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ connection_.SendStreamDataWithString(3, "first", i * 0, NO_FIN);
+ }
+}
+
+TEST_P(QuicConnectionTest, ConnectionCloseFrameType) {
+ if (!VersionHasIetfQuicFrames(version().transport_version)) {
+ // Test relevent only for IETF QUIC.
+ return;
+ }
+ const QuicErrorCode kQuicErrorCode = IETF_QUIC_PROTOCOL_VIOLATION;
+ // Use the (unknown) frame type of 9999 to avoid triggering any logic
+ // which might be associated with the processing of a known frame type.
+ const uint64_t kTransportCloseFrameType = 9999u;
+ QuicFramerPeer::set_current_received_frame_type(
+ QuicConnectionPeer::GetFramer(&connection_), kTransportCloseFrameType);
+ // Do a transport connection close
+ EXPECT_CALL(visitor_, OnConnectionClosed(_, _));
+ connection_.CloseConnection(
+ kQuicErrorCode, "Some random error message",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ const std::vector<QuicConnectionCloseFrame>& connection_close_frames =
+ writer_->connection_close_frames();
+ ASSERT_EQ(1u, connection_close_frames.size());
+ EXPECT_EQ(IETF_QUIC_TRANSPORT_CONNECTION_CLOSE,
+ connection_close_frames[0].close_type);
+ EXPECT_EQ(kQuicErrorCode, connection_close_frames[0].extracted_error_code);
+ EXPECT_EQ(kTransportCloseFrameType,
+ connection_close_frames[0].transport_close_frame_type);
+}
+
+// Regression test for b/137401387 and b/138962304.
+TEST_P(QuicConnectionTest, RtoPacketAsTwo) {
+ if (!QuicConnectionPeer::GetSentPacketManager(&connection_)
+ ->fix_rto_retransmission() ||
+ connection_.PtoEnabled()) {
+ return;
+ }
+ connection_.SetMaxTailLossProbes(1);
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+ std::string stream_data(3000, 's');
+ // Send packets 1 - 66 and exhaust cwnd.
+ for (size_t i = 0; i < 22; ++i) {
+ // 3 packets for each stream, the first 2 are guaranteed to be full packets.
+ SendStreamDataToPeer(i + 2, stream_data, 0, FIN, nullptr);
+ }
+ CongestionBlockWrites();
+
+ // Fires TLP. Please note, this tail loss probe has 1 byte less stream data
+ // compared to packet 1 because packet number length increases.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(67), _, _));
+ connection_.GetRetransmissionAlarm()->Fire();
+ // Fires RTO. Please note, although packets 2 and 3 *should* be RTOed, but
+ // packet 2 gets RTOed to two packets because packet number length increases.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(68), _, _));
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(69), _, _));
+ connection_.GetRetransmissionAlarm()->Fire();
+
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ // Resets all streams except 2 and ack packets 1 and 2. Now, packet 3 is the
+ // only one containing retransmittable frames.
+ for (size_t i = 1; i < 22; ++i) {
+ notifier_.OnStreamReset(i + 2, QUIC_STREAM_CANCELLED);
+ }
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(_, _, _, _, _));
+ QuicAckFrame frame =
+ InitAckFrame({{QuicPacketNumber(1), QuicPacketNumber(3)}});
+ ProcessAckPacket(1, &frame);
+ CongestionUnblockWrites();
+
+ // Fires TLP, verify a PING gets sent because packet 3 is marked
+ // RTO_RETRANSMITTED.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(70), _, _));
+ EXPECT_CALL(visitor_, SendPing()).WillOnce(Invoke([this]() { SendPing(); }));
+ connection_.GetRetransmissionAlarm()->Fire();
+}
+
} // namespace
} // namespace test
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_constants.h b/chromium/net/third_party/quiche/src/quic/core/quic_constants.h
index 442fb0907aa..cdee0f991d1 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
@@ -79,11 +79,6 @@ const QuicByteCount kSessionReceiveWindowLimit = 24 * 1024 * 1024; // 24 MB
// TODO(bnc): Move this constant to quic/core/http/.
const QuicByteCount kDefaultMaxUncompressedHeaderSize = 16 * 1024; // 16 KB
-// Default maximum dynamic table capacity, communicated via
-// SETTINGS_QPACK_MAX_TABLE_CAPACITY.
-// TODO(bnc): Move this constant to quic/core/http/.
-const QuicByteCount kDefaultQpackMaxDynamicTableCapacity = 64 * 1024; // 64 KB
-
// Minimum size of the CWND, in packets, when doing bandwidth resumption.
const QuicPacketCount kMinCongestionWindowForBandwidthResumption = 10;
@@ -118,6 +113,9 @@ QUIC_EXPORT_PRIVATE extern const char* const kFinalOffsetHeaderKey;
// in low-bandwidth (< ~384 kbps), where an ack is sent per packet.
const int64_t kDefaultDelayedAckTimeMs = 25;
+// Default shift of the ACK delay in the IETF QUIC ACK frame.
+const uint32_t kDefaultAckDelayExponent = 3;
+
// Minimum tail loss probe time in ms.
static const int64_t kMinTailLossProbeTimeoutMs = 10;
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 511ef2be82b..ac4488b1446 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
@@ -14,11 +14,25 @@
namespace quic {
+namespace {
+
+// The maximum number of buffered control frames which are waiting to be ACKed
+// or sent for the first time.
+const size_t kMaxNumControlFrames = 1000;
+
+} // namespace
+
QuicControlFrameManager::QuicControlFrameManager(QuicSession* session)
: last_control_frame_id_(kInvalidControlFrameId),
least_unacked_(1),
least_unsent_(1),
- session_(session) {}
+ session_(session),
+ add_upper_limit_(GetQuicReloadableFlag(
+ quic_add_upper_limit_of_buffered_control_frames)) {
+ if (add_upper_limit_) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_add_upper_limit_of_buffered_control_frames);
+ }
+}
QuicControlFrameManager::~QuicControlFrameManager() {
while (!control_frames_.empty()) {
@@ -30,6 +44,15 @@ QuicControlFrameManager::~QuicControlFrameManager() {
void QuicControlFrameManager::WriteOrBufferQuicFrame(QuicFrame frame) {
const bool had_buffered_frames = HasBufferedFrames();
control_frames_.emplace_back(frame);
+ if (add_upper_limit_ && control_frames_.size() > kMaxNumControlFrames) {
+ session_->connection()->CloseConnection(
+ QUIC_TOO_MANY_BUFFERED_CONTROL_FRAMES,
+ QuicStrCat("More than ", kMaxNumControlFrames,
+ "buffered control frames, least_unacked: ", least_unacked_,
+ ", least_unsent_: ", least_unsent_),
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return;
+ }
if (had_buffered_frames) {
return;
}
@@ -101,6 +124,15 @@ void QuicControlFrameManager::WritePing() {
}
control_frames_.emplace_back(
QuicFrame(QuicPingFrame(++last_control_frame_id_)));
+ if (add_upper_limit_ && control_frames_.size() > kMaxNumControlFrames) {
+ session_->connection()->CloseConnection(
+ QUIC_TOO_MANY_BUFFERED_CONTROL_FRAMES,
+ QuicStrCat("More than ", kMaxNumControlFrames,
+ "buffered control frames, least_unacked: ", least_unacked_,
+ ", least_unsent_: ", least_unsent_),
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return;
+ }
WriteBufferedFrames();
}
@@ -172,6 +204,9 @@ void QuicControlFrameManager::OnControlFrameLost(const QuicFrame& frame) {
}
if (!QuicContainsKey(pending_retransmissions_, id)) {
pending_retransmissions_[id] = true;
+ QUIC_BUG_IF(pending_retransmissions_.size() > control_frames_.size())
+ << "least_unacked_: " << least_unacked_
+ << ", least_unsent_: " << least_unsent_;
}
}
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 a4c26780d40..54ca4794405 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager.h
@@ -146,6 +146,9 @@ class QUIC_EXPORT_PRIVATE QuicControlFrameManager {
// Last sent window update frame for each stream.
QuicSmallMap<QuicStreamId, QuicControlFrameId, 10> window_update_frames_;
+
+ // Latched value of quic_add_upper_limit_of_buffered_control_frames.
+ const bool add_upper_limit_;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager_test.cc
index 216ba741132..8059ff6a967 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
@@ -4,6 +4,7 @@
#include "net/third_party/quiche/src/quic/core/quic_control_frame_manager.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
@@ -288,6 +289,27 @@ TEST_F(QuicControlFrameManagerTest, RetransmitWindowUpdateOfDifferentStreams) {
EXPECT_FALSE(manager_->WillingToWrite());
}
+TEST_F(QuicControlFrameManagerTest, TooManyBufferedControlFrames) {
+ SetQuicReloadableFlag(quic_add_upper_limit_of_buffered_control_frames, true);
+ Initialize();
+ EXPECT_CALL(*connection_, SendControlFrame(_))
+ .Times(5)
+ .WillRepeatedly(Invoke(&ClearControlFrame));
+ // Flush buffered frames.
+ manager_->OnCanWrite();
+ // Write 995 control frames.
+ EXPECT_CALL(*connection_, SendControlFrame(_)).WillOnce(Return(false));
+ for (size_t i = 0; i < 995; ++i) {
+ manager_->WriteOrBufferRstStream(kTestStreamId, 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);
+}
+
} // namespace
} // namespace test
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.cc
index bf432ff4967..ac15301efe3 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.cc
@@ -141,6 +141,11 @@ CryptoMessageParser* QuicCryptoClientHandshaker::crypto_message_parser() {
return QuicCryptoHandshaker::crypto_message_parser();
}
+size_t QuicCryptoClientHandshaker::BufferSizeLimitForLevel(
+ EncryptionLevel level) const {
+ return QuicCryptoHandshaker::BufferSizeLimitForLevel(level);
+}
+
void QuicCryptoClientHandshaker::HandleServerConfigUpdateMessage(
const CryptoHandshakeMessage& server_config_update) {
DCHECK(server_config_update.tag() == kSCUP);
@@ -321,10 +326,8 @@ void QuicCryptoClientHandshaker::DoSendCHLO(
std::move(crypto_negotiated_params_->initial_crypters.encrypter));
session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
- // TODO(ianswett): Merge ENCRYPTION_REESTABLISHED and
- // ENCRYPTION_FIRST_ESTABLSIHED
encryption_established_ = true;
- session()->OnCryptoHandshakeEvent(QuicSession::ENCRYPTION_REESTABLISHED);
+ session()->OnCryptoHandshakeEvent(QuicSession::ENCRYPTION_ESTABLISHED);
}
void QuicCryptoClientHandshaker::DoReceiveREJ(
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 5b7ce35e29b..d33ebfe32fe 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
@@ -44,6 +44,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientHandshaker
const QuicCryptoNegotiatedParameters& crypto_negotiated_params()
const override;
CryptoMessageParser* crypto_message_parser() override;
+ size_t BufferSizeLimitForLevel(EncryptionLevel level) const override;
// From QuicCryptoHandshaker
void OnHandshakeMessage(const CryptoHandshakeMessage& message) override;
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 93f2a61104a..8f89e9a8bec 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
@@ -84,6 +84,11 @@ CryptoMessageParser* QuicCryptoClientStream::crypto_message_parser() {
return handshaker_->crypto_message_parser();
}
+size_t QuicCryptoClientStream::BufferSizeLimitForLevel(
+ EncryptionLevel level) const {
+ return handshaker_->BufferSizeLimitForLevel(level);
+}
+
std::string QuicCryptoClientStream::chlo_hash() const {
return handshaker_->chlo_hash();
}
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 b8dff7e9d34..89f0d2e28b7 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
@@ -99,6 +99,10 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientStream
// Used by QuicCryptoStream to parse data received on this stream.
virtual CryptoMessageParser* crypto_message_parser() = 0;
+
+ // Used by QuicCryptoStream to know how much unprocessed data can be
+ // buffered at each encryption level.
+ virtual size_t BufferSizeLimitForLevel(EncryptionLevel level) const = 0;
};
// ProofHandler is an interface that handles callbacks from the crypto
@@ -142,6 +146,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientStream
const QuicCryptoNegotiatedParameters& crypto_negotiated_params()
const override;
CryptoMessageParser* crypto_message_parser() override;
+ size_t BufferSizeLimitForLevel(EncryptionLevel level) const override;
std::string chlo_hash() const;
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_handshaker.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_handshaker.cc
index fa0f78a51c9..d608ead807c 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_handshaker.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_handshaker.cc
@@ -45,5 +45,9 @@ CryptoMessageParser* QuicCryptoHandshaker::crypto_message_parser() {
return &crypto_framer_;
}
+size_t QuicCryptoHandshaker::BufferSizeLimitForLevel(EncryptionLevel) const {
+ return GetQuicFlag(FLAGS_quic_max_buffered_crypto_bytes);
+}
+
#undef ENDPOINT // undef for jumbo builds
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_handshaker.h b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_handshaker.h
index 231acfcdb30..e5d8d51894e 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_handshaker.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_handshaker.h
@@ -27,6 +27,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoHandshaker
void OnHandshakeMessage(const CryptoHandshakeMessage& message) override;
CryptoMessageParser* crypto_message_parser();
+ size_t BufferSizeLimitForLevel(EncryptionLevel level) const;
protected:
QuicTag last_sent_handshake_message_tag() const {
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_handshaker.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_handshaker.cc
index 26134d7185b..ab381d7ea11 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_handshaker.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_handshaker.cc
@@ -373,6 +373,11 @@ CryptoMessageParser* QuicCryptoServerHandshaker::crypto_message_parser() {
return QuicCryptoHandshaker::crypto_message_parser();
}
+size_t QuicCryptoServerHandshaker::BufferSizeLimitForLevel(
+ EncryptionLevel level) const {
+ return QuicCryptoHandshaker::BufferSizeLimitForLevel(level);
+}
+
void QuicCryptoServerHandshaker::ProcessClientHello(
QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
result,
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_handshaker.h b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_handshaker.h
index f6644083768..4b7b3bac474 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_handshaker.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_handshaker.h
@@ -58,6 +58,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerHandshaker
const QuicCryptoNegotiatedParameters& crypto_negotiated_params()
const override;
CryptoMessageParser* crypto_message_parser() override;
+ size_t BufferSizeLimitForLevel(EncryptionLevel level) 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.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.cc
index 09344cde675..353de98a125 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.cc
@@ -111,6 +111,11 @@ CryptoMessageParser* QuicCryptoServerStream::crypto_message_parser() {
return handshaker()->crypto_message_parser();
}
+size_t QuicCryptoServerStream::BufferSizeLimitForLevel(
+ EncryptionLevel level) const {
+ return handshaker()->BufferSizeLimitForLevel(level);
+}
+
void QuicCryptoServerStream::OnSuccessfulVersionNegotiation(
const ParsedQuicVersion& version) {
DCHECK_EQ(version, session()->connection()->version());
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 c5e0abc0fb4..3a7d6e74b1a 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
@@ -119,18 +119,16 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerStream
// Used by QuicCryptoStream to parse data received on this stream.
virtual CryptoMessageParser* crypto_message_parser() = 0;
+
+ // Used by QuicCryptoStream to know how much unprocessed data can be
+ // buffered at each encryption level.
+ virtual size_t BufferSizeLimitForLevel(EncryptionLevel level) const = 0;
};
class Helper {
public:
virtual ~Helper() {}
- // Given the current connection_id, generates a new ConnectionId to
- // be returned with a reject.
- virtual QuicConnectionId GenerateConnectionIdForReject(
- QuicTransportVersion version,
- QuicConnectionId connection_id) const = 0;
-
// Returns true if |message|, which was received on |self_address| is
// acceptable according to the visitor's policy. Otherwise, returns false
// and populates |error_details|.
@@ -178,6 +176,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerStream
const QuicCryptoNegotiatedParameters& crypto_negotiated_params()
const override;
CryptoMessageParser* crypto_message_parser() override;
+ size_t BufferSizeLimitForLevel(EncryptionLevel level) const override;
void OnSuccessfulVersionNegotiation(
const ParsedQuicVersion& version) override;
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_test.cc
index 238162c96ef..b58d987e6ee 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_test.cc
@@ -90,8 +90,6 @@ class QuicCryptoServerStreamTest : public QuicTestWithParam<bool> {
server_session_.reset(server_session);
EXPECT_CALL(*server_session_->helper(), CanAcceptClientHello(_, _, _, _, _))
.Times(testing::AnyNumber());
- EXPECT_CALL(*server_session_->helper(), GenerateConnectionIdForReject(_, _))
- .Times(testing::AnyNumber());
crypto_test_utils::SetupCryptoServerConfigForTest(
server_connection_->clock(), server_connection_->random_generator(),
&server_crypto_config_);
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 395b4906b25..e5b13f1f034 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
@@ -78,6 +78,11 @@ void QuicCryptoStream::OnCryptoFrame(const QuicCryptoFrame& frame) {
<< "Versions less than 47 shouldn't receive CRYPTO frames";
EncryptionLevel level = session()->connection()->last_decrypted_level();
substreams_[level].sequencer.OnCryptoFrame(frame);
+ if (substreams_[level].sequencer.NumBytesBuffered() >
+ BufferSizeLimitForLevel(frame.level)) {
+ CloseConnectionWithDetails(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA,
+ "Too much crypto data received");
+ }
}
void QuicCryptoStream::OnStreamFrame(const QuicStreamFrame& frame) {
@@ -154,6 +159,7 @@ void QuicCryptoStream::WriteCryptoData(EncryptionLevel level,
QUIC_BUG << "Empty crypto data being written";
return;
}
+ const bool had_buffered_data = HasBufferedCryptoFrames();
// Append |data| to the send buffer for this encryption level.
struct iovec iov(QuicUtils::MakeIovec(data));
QuicStreamSendBuffer* send_buffer = &substreams_[level].send_buffer;
@@ -167,19 +173,23 @@ void QuicCryptoStream::WriteCryptoData(EncryptionLevel level,
CloseConnectionWithDetails(QUIC_STREAM_LENGTH_OVERFLOW,
"Writing too much crypto handshake data");
}
+ if (had_buffered_data) {
+ // Do not try to write if there is buffered data.
+ return;
+ }
EncryptionLevel current_level = session()->connection()->encryption_level();
session()->connection()->SetDefaultEncryptionLevel(level);
size_t bytes_consumed =
session()->connection()->SendCryptoData(level, data.length(), offset);
session()->connection()->SetDefaultEncryptionLevel(current_level);
- // Since CRYPTO frames aren't flow controlled, SendCryptoData should have sent
- // all data we asked it to send.
- DCHECK_EQ(bytes_consumed, data.length());
-
send_buffer->OnStreamDataConsumed(bytes_consumed);
}
+size_t QuicCryptoStream::BufferSizeLimitForLevel(EncryptionLevel) const {
+ return GetQuicFlag(FLAGS_quic_max_buffered_crypto_bytes);
+}
+
void QuicCryptoStream::OnSuccessfulVersionNegotiation(
const ParsedQuicVersion& /*version*/) {}
@@ -412,6 +422,48 @@ void QuicCryptoStream::RetransmitData(QuicCryptoFrame* crypto_frame) {
session()->connection()->SetDefaultEncryptionLevel(current_encryption_level);
}
+void QuicCryptoStream::WriteBufferedCryptoFrames() {
+ QUIC_BUG_IF(!QuicVersionUsesCryptoFrames(
+ session()->connection()->transport_version()))
+ << "Versions less than 47 don't use CRYPTO frames";
+ EncryptionLevel current_encryption_level =
+ session()->connection()->encryption_level();
+ for (EncryptionLevel level :
+ {ENCRYPTION_INITIAL, ENCRYPTION_ZERO_RTT, ENCRYPTION_FORWARD_SECURE}) {
+ QuicStreamSendBuffer* send_buffer = &substreams_[level].send_buffer;
+ const size_t data_length =
+ send_buffer->stream_offset() - send_buffer->stream_bytes_written();
+ if (data_length == 0) {
+ // No buffered data for this encryption level.
+ continue;
+ }
+ session()->connection()->SetDefaultEncryptionLevel(level);
+ size_t bytes_consumed = session()->connection()->SendCryptoData(
+ level, data_length, send_buffer->stream_bytes_written());
+ send_buffer->OnStreamDataConsumed(bytes_consumed);
+ if (bytes_consumed < data_length) {
+ // Connection is write blocked.
+ break;
+ }
+ }
+ session()->connection()->SetDefaultEncryptionLevel(current_encryption_level);
+}
+
+bool QuicCryptoStream::HasBufferedCryptoFrames() const {
+ QUIC_BUG_IF(!QuicVersionUsesCryptoFrames(
+ session()->connection()->transport_version()))
+ << "Versions less than 47 don't use CRYPTO frames";
+ for (EncryptionLevel level :
+ {ENCRYPTION_INITIAL, ENCRYPTION_ZERO_RTT, ENCRYPTION_FORWARD_SECURE}) {
+ const QuicStreamSendBuffer& send_buffer = substreams_[level].send_buffer;
+ DCHECK_GE(send_buffer.stream_offset(), send_buffer.stream_bytes_written());
+ if (send_buffer.stream_offset() > send_buffer.stream_bytes_written()) {
+ return true;
+ }
+ }
+ return false;
+}
+
bool QuicCryptoStream::IsFrameOutstanding(EncryptionLevel level,
size_t offset,
size_t length) const {
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 1b641b19cec..12a36f894b6 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.h
@@ -80,6 +80,10 @@ class QUIC_EXPORT_PRIVATE QuicCryptoStream : public QuicStream {
// Provides the message parser to use when data is received on this stream.
virtual CryptoMessageParser* crypto_message_parser() = 0;
+ // Returns the maximum number of bytes that can be buffered at a particular
+ // encryption level |level|.
+ virtual size_t BufferSizeLimitForLevel(EncryptionLevel level) const;
+
// Called when the underlying QuicConnection has agreed upon a QUIC version to
// use.
virtual void OnSuccessfulVersionNegotiation(const ParsedQuicVersion& version);
@@ -130,6 +134,12 @@ class QUIC_EXPORT_PRIVATE QuicCryptoStream : public QuicStream {
// encryption level, offset, and length in |crypto_frame|.
void RetransmitData(QuicCryptoFrame* crypto_frame);
+ // Called to write buffered crypto frames.
+ void WriteBufferedCryptoFrames();
+
+ // Returns true if there is buffered crypto frames.
+ bool HasBufferedCryptoFrames() const;
+
// Returns true if any portion of the data at encryption level |level|
// starting at |offset| for |length| bytes is outstanding.
bool IsFrameOutstanding(EncryptionLevel level,
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 dd4450eab57..af5a8ccf2f8 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
@@ -23,6 +23,7 @@ using testing::_;
using testing::InSequence;
using testing::Invoke;
using testing::InvokeWithoutArgs;
+using testing::Return;
namespace quic {
namespace test {
@@ -519,16 +520,73 @@ TEST_F(QuicCryptoStreamTest, CryptoMessageFramingOverhead) {
SCOPED_TRACE(version);
QuicByteCount expected_overhead = 48;
if (VersionHasIetfInvariantHeader(version)) {
- expected_overhead = 52;
+ expected_overhead += 4;
}
if (QuicVersionHasLongHeaderLengths(version)) {
- expected_overhead = 55;
+ expected_overhead += 3;
+ }
+ if (VersionHasLengthPrefixedConnectionIds(version)) {
+ expected_overhead += 1;
}
EXPECT_EQ(expected_overhead, QuicCryptoStream::CryptoMessageFramingOverhead(
version, TestConnectionId()));
}
}
+TEST_F(QuicCryptoStreamTest, WriteBufferedCryptoFrames) {
+ if (!QuicVersionUsesCryptoFrames(connection_->transport_version())) {
+ return;
+ }
+ EXPECT_FALSE(stream_->HasBufferedCryptoFrames());
+ InSequence s;
+ // Send [0, 1350) in ENCRYPTION_INITIAL.
+ EXPECT_EQ(ENCRYPTION_INITIAL, connection_->encryption_level());
+ std::string data(1350, 'a');
+ // Only consumed 1000 bytes.
+ EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_INITIAL, 1350, 0))
+ .WillOnce(Return(1000));
+ stream_->WriteCryptoData(ENCRYPTION_INITIAL, data);
+ EXPECT_TRUE(stream_->HasBufferedCryptoFrames());
+
+ // Send [1350, 2700) in ENCRYPTION_ZERO_RTT and verify no write is attempted
+ // because there is buffered data.
+ EXPECT_CALL(*connection_, SendCryptoData(_, _, _)).Times(0);
+ connection_->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
+ stream_->WriteCryptoData(ENCRYPTION_ZERO_RTT, data);
+ EXPECT_EQ(ENCRYPTION_ZERO_RTT, connection_->encryption_level());
+
+ EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_INITIAL, 350, 1000))
+ .WillOnce(Return(350));
+ // Partial write of ENCRYPTION_ZERO_RTT data.
+ EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_ZERO_RTT, 1350, 0))
+ .WillOnce(Return(1000));
+ stream_->WriteBufferedCryptoFrames();
+ EXPECT_TRUE(stream_->HasBufferedCryptoFrames());
+ EXPECT_EQ(ENCRYPTION_ZERO_RTT, connection_->encryption_level());
+
+ EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_ZERO_RTT, 350, 1000))
+ .WillOnce(Return(350));
+ stream_->WriteBufferedCryptoFrames();
+ EXPECT_FALSE(stream_->HasBufferedCryptoFrames());
+}
+
+TEST_F(QuicCryptoStreamTest, LimitBufferedCryptoData) {
+ if (!QuicVersionUsesCryptoFrames(connection_->transport_version())) {
+ return;
+ }
+
+ EXPECT_CALL(*connection_,
+ CloseConnection(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA, _, _));
+ std::string large_frame(2 * GetQuicFlag(FLAGS_quic_max_buffered_crypto_bytes),
+ 'a');
+
+ // Set offset to 1 so that we guarantee the data gets buffered instead of
+ // immediately processed.
+ QuicStreamOffset offset = 1;
+ stream_->OnCryptoFrame(
+ QuicCryptoFrame(ENCRYPTION_INITIAL, offset, large_frame));
+}
+
} // namespace
} // namespace test
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_data_reader.cc b/chromium/net/third_party/quiche/src/quic/core/quic_data_reader.cc
index e2871d760ba..c9a76be8f57 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_data_reader.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_data_reader.cc
@@ -136,7 +136,7 @@ bool QuicDataReader::ReadStringPiece(QuicStringPiece* result, size_t size) {
bool QuicDataReader::ReadConnectionId(QuicConnectionId* connection_id,
uint8_t length) {
- if (length > kQuicMaxConnectionIdLength) {
+ if (length > kQuicMaxConnectionIdAllVersionsLength) {
QUIC_BUG << "Attempted to read connection ID with length too high "
<< static_cast<int>(length);
return false;
@@ -146,21 +146,13 @@ bool QuicDataReader::ReadConnectionId(QuicConnectionId* connection_id,
return true;
}
- if (!GetQuicRestartFlag(quic_use_allocated_connection_ids)) {
- const bool ok = ReadBytes(connection_id->mutable_data(), length);
- if (ok) {
- connection_id->set_length(length);
- }
- return ok;
- }
- QUIC_RESTART_FLAG_COUNT_N(quic_use_allocated_connection_ids, 6, 6);
-
if (BytesRemaining() < length) {
return false;
}
connection_id->set_length(length);
- const bool ok = ReadBytes(connection_id->mutable_data(), length);
+ const bool ok =
+ ReadBytes(connection_id->mutable_data(), connection_id->length());
DCHECK(ok);
return ok;
}
@@ -171,7 +163,7 @@ bool QuicDataReader::ReadLengthPrefixedConnectionId(
if (!ReadUInt8(&connection_id_length)) {
return false;
}
- if (connection_id_length > kQuicMaxConnectionIdLength) {
+ if (connection_id_length > kQuicMaxConnectionIdAllVersionsLength) {
return false;
}
return ReadConnectionId(connection_id, connection_id_length);
@@ -191,6 +183,10 @@ QuicStringPiece QuicDataReader::PeekRemainingPayload() const {
return QuicStringPiece(data_ + pos_, len_ - pos_);
}
+QuicStringPiece QuicDataReader::FullPayload() const {
+ return QuicStringPiece(data_, len_);
+}
+
bool QuicDataReader::ReadBytes(void* result, size_t size) {
// Make sure that we have enough data to read.
if (!CanRead(size)) {
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_data_reader.h b/chromium/net/third_party/quiche/src/quic/core/quic_data_reader.h
index 72e2d132258..74ed2269d0c 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_data_reader.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_data_reader.h
@@ -110,6 +110,14 @@ class QUIC_EXPORT_PRIVATE QuicDataReader {
// DOES NOT forward the internal iterator.
QuicStringPiece PeekRemainingPayload() const;
+ // Returns the entire payload as a QuicStringPiece.
+ //
+ // NOTE: Does not copy but rather references strings in the underlying buffer.
+ // This should be kept in mind when handling memory management!
+ //
+ // DOES NOT forward the internal iterator.
+ QuicStringPiece FullPayload() const;
+
// Reads a given number of bytes into the given buffer. The buffer
// must be of adequate size.
// Forwards the internal iterator on success.
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_data_writer_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_data_writer_test.cc
index 727c8133301..64ad5dd22ae 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_data_writer_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_data_writer_test.cc
@@ -262,8 +262,8 @@ TEST_P(QuicDataWriterTest, WriteConnectionId) {
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
};
EXPECT_EQ(connection_id.length(), QUIC_ARRAYSIZE(big_endian));
- ASSERT_LE(connection_id.length(), kQuicMaxConnectionIdLength);
- char buffer[kQuicMaxConnectionIdLength];
+ ASSERT_LE(connection_id.length(), 255);
+ char buffer[255];
QuicDataWriter writer(connection_id.length(), buffer, GetParam().endianness);
EXPECT_TRUE(writer.WriteConnectionId(connection_id));
test::CompareCharArraysWithHexError("connection_id", buffer,
@@ -285,7 +285,7 @@ TEST_P(QuicDataWriterTest, LengthPrefixedConnectionId) {
};
EXPECT_EQ(QUIC_ARRAYSIZE(length_prefixed_connection_id),
kConnectionIdLengthSize + connection_id.length());
- char buffer[kConnectionIdLengthSize + kQuicMaxConnectionIdLength] = {};
+ char buffer[kConnectionIdLengthSize + 255] = {};
QuicDataWriter writer(QUIC_ARRAYSIZE(buffer), buffer);
EXPECT_TRUE(writer.WriteLengthPrefixedConnectionId(connection_id));
test::CompareCharArraysWithHexError(
@@ -1149,11 +1149,12 @@ TEST_P(QuicDataWriterTest, PeekVarInt62Length) {
}
TEST_P(QuicDataWriterTest, InvalidConnectionIdLengthRead) {
- static const uint8_t bad_connection_id_length = 19;
- static_assert(bad_connection_id_length > kQuicMaxConnectionIdLength,
- "bad lengths");
- char buffer[20] = {};
- QuicDataReader reader(buffer, 20);
+ static const uint8_t bad_connection_id_length = 200;
+ static_assert(
+ bad_connection_id_length > kQuicMaxConnectionIdAllVersionsLength,
+ "bad lengths");
+ char buffer[255] = {};
+ QuicDataReader reader(buffer, sizeof(buffer));
QuicConnectionId connection_id;
bool ok;
EXPECT_QUIC_BUG(
@@ -1231,6 +1232,37 @@ TEST_P(QuicDataWriterTest, SeekTooFarFails) {
}
}
+TEST_P(QuicDataWriterTest, PayloadReads) {
+ char buffer[16] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
+ char expected_first_read[4] = {1, 2, 3, 4};
+ char expected_remaining[12] = {5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
+ QuicDataReader reader(buffer, sizeof(buffer));
+ char first_read_buffer[4] = {};
+ EXPECT_TRUE(reader.ReadBytes(first_read_buffer, sizeof(first_read_buffer)));
+ test::CompareCharArraysWithHexError(
+ "first read", first_read_buffer, sizeof(first_read_buffer),
+ expected_first_read, sizeof(expected_first_read));
+ QuicStringPiece peeked_remaining_payload = reader.PeekRemainingPayload();
+ test::CompareCharArraysWithHexError(
+ "peeked_remaining_payload", peeked_remaining_payload.data(),
+ peeked_remaining_payload.length(), expected_remaining,
+ sizeof(expected_remaining));
+ QuicStringPiece full_payload = reader.FullPayload();
+ test::CompareCharArraysWithHexError("full_payload", full_payload.data(),
+ full_payload.length(), buffer,
+ sizeof(buffer));
+ QuicStringPiece read_remaining_payload = reader.ReadRemainingPayload();
+ test::CompareCharArraysWithHexError(
+ "read_remaining_payload", read_remaining_payload.data(),
+ read_remaining_payload.length(), expected_remaining,
+ sizeof(expected_remaining));
+ EXPECT_TRUE(reader.IsDoneReading());
+ QuicStringPiece full_payload2 = reader.FullPayload();
+ test::CompareCharArraysWithHexError("full_payload2", full_payload2.data(),
+ full_payload2.length(), buffer,
+ sizeof(buffer));
+}
+
} // namespace
} // namespace test
} // 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 c6ee81634c7..4d7b70e53d8 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
@@ -228,18 +228,34 @@ void QuicDispatcher::ProcessPacket(const QuicSocketAddress& self_address,
QuicStringPiece(packet.data(), packet.length()));
ReceivedPacketInfo packet_info(self_address, peer_address, packet);
std::string detailed_error;
- const QuicErrorCode error = QuicFramer::ProcessPacketDispatcher(
- packet, expected_server_connection_id_length_, &packet_info.form,
- &packet_info.version_flag, &packet_info.version_label,
- &packet_info.destination_connection_id, &packet_info.source_connection_id,
- &detailed_error);
+ QuicErrorCode error;
+ if (!GetQuicReloadableFlag(quic_use_parse_public_header)) {
+ error = QuicFramer::ProcessPacketDispatcher(
+ packet, expected_server_connection_id_length_, &packet_info.form,
+ &packet_info.version_flag, &packet_info.version_label,
+ &packet_info.destination_connection_id,
+ &packet_info.source_connection_id, &detailed_error);
+ } else {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_use_parse_public_header);
+ bool retry_token_present;
+ QuicStringPiece retry_token;
+ error = QuicFramer::ParsePublicHeaderDispatcher(
+ packet, expected_server_connection_id_length_, &packet_info.form,
+ &packet_info.version_flag, &packet_info.use_length_prefix,
+ &packet_info.version_label, &packet_info.version,
+ &packet_info.destination_connection_id,
+ &packet_info.source_connection_id, &retry_token_present, &retry_token,
+ &detailed_error);
+ }
if (error != QUIC_NO_ERROR) {
// Packet has framing error.
SetLastError(error);
QUIC_DLOG(ERROR) << detailed_error;
return;
}
- packet_info.version = ParseQuicVersionLabel(packet_info.version_label);
+ if (!GetQuicReloadableFlag(quic_use_parse_public_header)) {
+ packet_info.version = ParseQuicVersionLabel(packet_info.version_label);
+ }
if (packet_info.destination_connection_id.length() !=
expected_server_connection_id_length_ &&
!should_update_expected_server_connection_id_length_ &&
@@ -249,6 +265,26 @@ void QuicDispatcher::ProcessPacket(const QuicSocketAddress& self_address,
QUIC_DLOG(ERROR) << "Invalid Connection Id Length";
return;
}
+
+ if (packet_info.version_flag && IsSupportedVersion(packet_info.version)) {
+ if (!QuicUtils::IsConnectionIdValidForVersion(
+ packet_info.destination_connection_id,
+ packet_info.version.transport_version)) {
+ SetLastError(QUIC_INVALID_PACKET_HEADER);
+ QUIC_DLOG(ERROR)
+ << "Invalid destination connection ID length for version";
+ return;
+ }
+ if (packet_info.version.SupportsClientConnectionIds() &&
+ !QuicUtils::IsConnectionIdValidForVersion(
+ packet_info.source_connection_id,
+ packet_info.version.transport_version)) {
+ SetLastError(QUIC_INVALID_PACKET_HEADER);
+ QUIC_DLOG(ERROR) << "Invalid source connection ID length for version";
+ return;
+ }
+ }
+
if (should_update_expected_server_connection_id_length_) {
expected_server_connection_id_length_ =
packet_info.destination_connection_id.length();
@@ -269,24 +305,26 @@ QuicConnectionId QuicDispatcher::MaybeReplaceServerConnectionId(
}
DCHECK(QuicUtils::VariableLengthConnectionIdAllowedForVersion(
version.transport_version));
- auto it = connection_id_map_.find(server_connection_id);
- if (it != connection_id_map_.end()) {
- return it->second;
- }
+
QuicConnectionId new_connection_id =
- session_helper_->GenerateConnectionIdForReject(version.transport_version,
- server_connection_id);
+ GenerateNewServerConnectionId(version, server_connection_id);
DCHECK_EQ(expected_server_connection_id_length_, new_connection_id.length());
- // TODO(dschinazi) Prevent connection_id_map_ from growing indefinitely
- // before we ship a version that supports variable length connection IDs
- // to production.
- connection_id_map_.insert(
- std::make_pair(server_connection_id, new_connection_id));
+
+ // Verify that GenerateNewServerConnectionId is deterministic.
+ DCHECK_EQ(new_connection_id,
+ GenerateNewServerConnectionId(version, server_connection_id));
+
QUIC_DLOG(INFO) << "Replacing incoming connection ID " << server_connection_id
<< " with " << new_connection_id;
return new_connection_id;
}
+QuicConnectionId QuicDispatcher::GenerateNewServerConnectionId(
+ ParsedQuicVersion /*version*/,
+ QuicConnectionId connection_id) const {
+ return QuicUtils::CreateReplacementConnectionId(connection_id);
+}
+
bool QuicDispatcher::MaybeDispatchPacket(
const ReceivedPacketInfo& packet_info) {
// Port zero is only allowed for unidirectional UDP, so is disallowed by QUIC.
@@ -319,7 +357,8 @@ bool QuicDispatcher::MaybeDispatchPacket(
<< " to time-wait list.";
StatelesslyTerminateConnection(
server_connection_id, packet_info.form, packet_info.version_flag,
- packet_info.version, QUIC_HANDSHAKE_FAILED, "Reject connection",
+ packet_info.use_length_prefix, packet_info.version,
+ QUIC_HANDSHAKE_FAILED, "Reject connection",
quic::QuicTimeWaitListManager::SEND_STATELESS_RESET);
DCHECK(time_wait_list_manager_->IsConnectionIdInTimeWait(
@@ -394,11 +433,22 @@ bool QuicDispatcher::MaybeDispatchPacket(
// packet and stop processing the current packet.
QuicConnectionId client_connection_id =
packet_info.source_connection_id;
+ bool use_length_prefix = packet_info.use_length_prefix;
+ if (!GetQuicReloadableFlag(quic_use_length_prefix_from_packet_info)) {
+ use_length_prefix = packet_info.form != GOOGLE_QUIC_PACKET &&
+ !QuicVersionLabelUses4BitConnectionIdLength(
+ packet_info.version_label);
+ } else {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_use_length_prefix_from_packet_info);
+ // TODO(dschinazi) remove the client-side workaround in
+ // QuicFramer::ParseServerVersionNegotiationProbeResponse
+ // when quic_use_length_prefix_from_packet_info is deprecated.
+ }
time_wait_list_manager()->SendVersionNegotiationPacket(
server_connection_id, client_connection_id,
- packet_info.form != GOOGLE_QUIC_PACKET, GetSupportedVersions(),
- packet_info.self_address, packet_info.peer_address,
- GetPerPacketContext());
+ packet_info.form != GOOGLE_QUIC_PACKET, use_length_prefix,
+ GetSupportedVersions(), packet_info.self_address,
+ packet_info.peer_address, GetPerPacketContext());
}
return true;
}
@@ -454,7 +504,8 @@ void QuicDispatcher::ProcessHeader(ReceivedPacketInfo* packet_info) {
QUIC_CODE_COUNT(quic_reject_fate_time_wait);
StatelesslyTerminateConnection(
server_connection_id, packet_info->form, packet_info->version_flag,
- packet_info->version, QUIC_HANDSHAKE_FAILED, "Reject connection",
+ packet_info->use_length_prefix, packet_info->version,
+ QUIC_HANDSHAKE_FAILED, "Reject connection",
quic::QuicTimeWaitListManager::SEND_STATELESS_RESET);
DCHECK(time_wait_list_manager_->IsConnectionIdInTimeWait(
@@ -482,6 +533,37 @@ QuicDispatcher::QuicPacketFate QuicDispatcher::ValidityChecks(
// set. Since this may be a client continuing a connection we lost track of
// via server restart, send a rejection to fast-fail the connection.
if (!packet_info.version_flag) {
+ if (GetQuicReloadableFlag(quic_reply_to_old_android_conformance_test)) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_reply_to_old_android_conformance_test);
+ // The Android network conformance test contains a UDP test that sends a
+ // 12-byte packet with the following format:
+ // - 0x0c (public flags: 8-byte connection ID, 1-byte packet number)
+ // - randomized 8-byte connection ID
+ // - 0x01 (1-byte packet number)
+ // - 0x00 (private flags)
+ // - 0x07 (PING frame).
+ // That packet is invalid and we would normally drop it but in order to
+ // unblock this conformance testing we have the following workaround that
+ // will be removed once the fixed test is deployed.
+ // TODO(b/139691956) Remove this workaround once fixed test is deployed.
+ if (packet_info.packet.length() == 12 &&
+ packet_info.packet.data()[0] == 0x0c &&
+ packet_info.packet.data()[9] == 0x01 &&
+ packet_info.packet.data()[10] == 0x00 &&
+ packet_info.packet.data()[11] == 0x07) {
+ QUIC_DLOG(INFO) << "Received Android UDP network conformance test "
+ "packet with connection ID "
+ << packet_info.destination_connection_id;
+ // Respond with a public reset that the test will know how to parse
+ // then return kFateDrop to stop processing of this packet.
+ time_wait_list_manager()->SendPublicReset(
+ packet_info.self_address, packet_info.peer_address,
+ packet_info.destination_connection_id,
+ /*ietf_quic=*/false, GetPerPacketContext());
+ return kFateDrop;
+ }
+ }
+
QUIC_DLOG(INFO)
<< "Packet without version arrived for unknown connection ID "
<< packet_info.destination_connection_id;
@@ -521,7 +603,9 @@ void QuicDispatcher::CleanUpSession(SessionMap::iterator it,
VersionHasIetfInvariantHeader(connection->transport_version())
? IETF_QUIC_LONG_HEADER_PACKET
: GOOGLE_QUIC_PACKET,
- /*version_flag=*/true, connection->version(), QUIC_HANDSHAKE_FAILED,
+ /*version_flag=*/true,
+ connection->version().HasLengthPrefixedConnectionIds(),
+ connection->version(), QUIC_HANDSHAKE_FAILED,
"Connection is closed by server before handshake confirmed",
// Although it is our intention to send termination packets, the
// |action| argument is not used by this call to
@@ -665,6 +749,7 @@ void QuicDispatcher::StatelesslyTerminateConnection(
QuicConnectionId server_connection_id,
PacketHeaderFormat format,
bool version_flag,
+ bool use_length_prefix,
ParsedQuicVersion version,
QuicErrorCode error_code,
const std::string& error_details,
@@ -707,7 +792,7 @@ void QuicDispatcher::StatelesslyTerminateConnection(
std::vector<std::unique_ptr<QuicEncryptedPacket>> termination_packets;
termination_packets.push_back(QuicFramer::BuildVersionNegotiationPacket(
server_connection_id, EmptyQuicConnectionId(),
- /*ietf_quic=*/format != GOOGLE_QUIC_PACKET,
+ /*ietf_quic=*/format != GOOGLE_QUIC_PACKET, use_length_prefix,
/*versions=*/{}));
time_wait_list_manager()->AddConnectionIdToTimeWait(
server_connection_id, /*ietf_quic=*/format != GOOGLE_QUIC_PACKET,
@@ -728,8 +813,10 @@ void QuicDispatcher::OnExpiredPackets(
server_connection_id,
early_arrived_packets.ietf_quic ? IETF_QUIC_LONG_HEADER_PACKET
: GOOGLE_QUIC_PACKET,
- /*version_flag=*/true, early_arrived_packets.version,
- QUIC_HANDSHAKE_FAILED, "Packets buffered for too long",
+ /*version_flag=*/true,
+ early_arrived_packets.version.HasLengthPrefixedConnectionIds(),
+ early_arrived_packets.version, QUIC_HANDSHAKE_FAILED,
+ "Packets buffered for too long",
quic::QuicTimeWaitListManager::SEND_STATELESS_RESET);
}
@@ -820,7 +907,8 @@ void QuicDispatcher::ProcessChlo(const std::string& alpn,
QUIC_CODE_COUNT(quic_reject_stop_accepting_new_connections);
StatelesslyTerminateConnection(
packet_info->destination_connection_id, packet_info->form,
- /*version_flag=*/true, packet_info->version, QUIC_HANDSHAKE_FAILED,
+ /*version_flag=*/true, packet_info->use_length_prefix,
+ packet_info->version, QUIC_HANDSHAKE_FAILED,
"Stop accepting new connections",
quic::QuicTimeWaitListManager::SEND_STATELESS_RESET);
// Time wait list will reject the packet correspondingly.
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 cfaafa02360..abcd4f2f733 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
@@ -113,10 +113,6 @@ class QuicDispatcher : public QuicTimeWaitListManager::Visitor,
QuicConnectionId,
QuicConnectionIdHash>;
- const ConnectionIdMap& connection_id_map() const {
- return connection_id_map_;
- }
-
// The largest packet number we expect to receive with a connection
// ID for a connection that is not established yet. The current design will
// send a handshake and then up to 50 or so data packets, and then it may
@@ -152,6 +148,13 @@ class QuicDispatcher : public QuicTimeWaitListManager::Visitor,
// otherwise, returns false and the packet needs further processing.
virtual bool MaybeDispatchPacket(const ReceivedPacketInfo& packet_info);
+ // Generate a connection ID with a length that is expected by the dispatcher.
+ // Note that this MUST produce a deterministic result (calling this method
+ // with two connection IDs that are equal must produce the same result).
+ virtual QuicConnectionId GenerateNewServerConnectionId(
+ ParsedQuicVersion version,
+ QuicConnectionId connection_id) const;
+
// Values to be returned by ValidityChecks() to indicate what should be done
// with a packet. Fates with greater values are considered to be higher
// priority. ValidityChecks should return fate based on the priority order
@@ -254,6 +257,7 @@ class QuicDispatcher : public QuicTimeWaitListManager::Visitor,
QuicConnectionId server_connection_id,
PacketHeaderFormat format,
bool version_flag,
+ bool use_length_prefix,
ParsedQuicVersion version,
QuicErrorCode error_code,
const std::string& error_details,
@@ -326,9 +330,6 @@ class QuicDispatcher : public QuicTimeWaitListManager::Visitor,
SessionMap session_map_;
- // Map of connection IDs with bad lengths to their replacements.
- ConnectionIdMap connection_id_map_;
-
// Entity that manages connection_ids in time wait state.
std::unique_ptr<QuicTimeWaitListManager> time_wait_list_manager_;
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 b18bddb983f..d0e5092c9ef 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
@@ -118,9 +118,10 @@ class TestDispatcher : public QuicDispatcher {
version_manager,
QuicMakeUnique<MockQuicConnectionHelper>(),
std::unique_ptr<QuicCryptoServerStream::Helper>(
- new QuicSimpleCryptoServerStreamHelper(random)),
+ new QuicSimpleCryptoServerStreamHelper()),
QuicMakeUnique<MockAlarmFactory>(),
- kQuicDefaultConnectionIdLength) {}
+ kQuicDefaultConnectionIdLength),
+ random_(random) {}
MOCK_METHOD4(CreateQuicSession,
QuicServerSessionBase*(QuicConnectionId connection_id,
@@ -152,6 +153,8 @@ class TestDispatcher : public QuicDispatcher {
using QuicDispatcher::SetAllowShortInitialServerConnectionIds;
using QuicDispatcher::writer;
+
+ QuicRandom* random_;
};
// A Connection class which unregisters the session from the dispatcher when
@@ -187,9 +190,7 @@ class QuicDispatcherTest : public QuicTest {
: QuicDispatcherTest(crypto_test_utils::ProofSourceForTesting()) {}
explicit QuicDispatcherTest(std::unique_ptr<ProofSource> proof_source)
- :
-
- version_manager_(AllSupportedVersions()),
+ : version_manager_(AllSupportedVersions()),
crypto_config_(QuicCryptoServerConfig::TESTING,
QuicRandom::GetInstance(),
std::move(proof_source),
@@ -524,13 +525,14 @@ TEST_F(QuicDispatcherTest, DispatcherDoesNotRejectPacketNumberZero) {
}
TEST_F(QuicDispatcherTest, StatelessVersionNegotiation) {
+ SetQuicReloadableFlag(quic_use_parse_public_header, true);
CreateTimeWaitListManager();
QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _)).Times(0);
EXPECT_CALL(
*time_wait_list_manager_,
- SendVersionNegotiationPacket(TestConnectionId(1), _, _, _, _, _, _))
+ SendVersionNegotiationPacket(TestConnectionId(1), _, _, _, _, _, _, _))
.Times(1);
// Pad the CHLO message with enough data to make the packet large enough
// to trigger version negotiation.
@@ -542,14 +544,14 @@ TEST_F(QuicDispatcherTest, StatelessVersionNegotiation) {
}
TEST_F(QuicDispatcherTest, StatelessVersionNegotiationWithClientConnectionId) {
- SetQuicRestartFlag(quic_do_not_override_connection_id, true);
+ SetQuicReloadableFlag(quic_use_parse_public_header, true);
CreateTimeWaitListManager();
QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _)).Times(0);
EXPECT_CALL(*time_wait_list_manager_,
- SendVersionNegotiationPacket(TestConnectionId(1),
- TestConnectionId(2), _, _, _, _, _))
+ SendVersionNegotiationPacket(
+ TestConnectionId(1), TestConnectionId(2), _, _, _, _, _, _))
.Times(1);
// Pad the CHLO message with enough data to make the packet large enough
// to trigger version negotiation.
@@ -567,7 +569,7 @@ TEST_F(QuicDispatcherTest, NoVersionNegotiationWithSmallPacket) {
EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _)).Times(0);
EXPECT_CALL(*time_wait_list_manager_,
- SendVersionNegotiationPacket(_, _, _, _, _, _, _))
+ SendVersionNegotiationPacket(_, _, _, _, _, _, _, _))
.Times(0);
std::string chlo = SerializeCHLO() + std::string(1200, 'a');
// Truncate to 1100 bytes of payload which results in a packet just
@@ -583,6 +585,7 @@ TEST_F(QuicDispatcherTest, NoVersionNegotiationWithSmallPacket) {
// Disabling CHLO size validation allows the dispatcher to send version
// negotiation packets in response to a CHLO that is otherwise too small.
TEST_F(QuicDispatcherTest, VersionNegotiationWithoutChloSizeValidation) {
+ SetQuicReloadableFlag(quic_use_parse_public_header, true);
crypto_config_.set_validate_chlo_size(false);
CreateTimeWaitListManager();
@@ -590,7 +593,7 @@ TEST_F(QuicDispatcherTest, VersionNegotiationWithoutChloSizeValidation) {
EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _)).Times(0);
EXPECT_CALL(*time_wait_list_manager_,
- SendVersionNegotiationPacket(_, _, _, _, _, _, _))
+ SendVersionNegotiationPacket(_, _, _, _, _, _, _, _))
.Times(1);
std::string chlo = SerializeCHLO() + std::string(1200, 'a');
// Truncate to 1100 bytes of payload which results in a packet just
@@ -747,7 +750,7 @@ TEST_F(QuicDispatcherTest, LongConnectionIdLengthReplaced) {
QuicConnectionId bad_connection_id = TestConnectionIdNineBytesLong(2);
QuicConnectionId fixed_connection_id =
- QuicUtils::CreateRandomConnectionId(mock_helper_.GetRandomGenerator());
+ QuicUtils::CreateReplacementConnectionId(bad_connection_id);
EXPECT_CALL(*dispatcher_,
CreateQuicSession(fixed_connection_id, client_address,
@@ -780,7 +783,7 @@ TEST_F(QuicDispatcherTest, InvalidShortConnectionIdLengthReplaced) {
QuicConnectionId bad_connection_id = EmptyQuicConnectionId();
QuicConnectionId fixed_connection_id =
- QuicUtils::CreateRandomConnectionId(mock_helper_.GetRandomGenerator());
+ QuicUtils::CreateReplacementConnectionId(bad_connection_id);
// Disable validation of invalid short connection IDs.
dispatcher_->SetAllowShortInitialServerConnectionIds(true);
@@ -817,7 +820,7 @@ TEST_F(QuicDispatcherTest, MixGoodAndBadConnectionIdLengthPackets) {
QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
QuicConnectionId bad_connection_id = TestConnectionIdNineBytesLong(2);
QuicConnectionId fixed_connection_id =
- QuicUtils::CreateRandomConnectionId(mock_helper_.GetRandomGenerator());
+ QuicUtils::CreateReplacementConnectionId(bad_connection_id);
EXPECT_CALL(*dispatcher_,
CreateQuicSession(TestConnectionId(1), client_address,
@@ -927,12 +930,13 @@ TEST_F(QuicDispatcherTest, OKSeqNoPacketProcessed) {
}
TEST_F(QuicDispatcherTest, SupportedTransportVersionsChangeInFlight) {
- static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 7u,
+ SetQuicRestartFlag(quic_dispatcher_hands_chlo_extractor_one_version, true);
+ SetQuicReloadableFlag(quic_use_parse_public_header, true);
+ static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 6u,
"Supported versions out of sync");
SetQuicReloadableFlag(quic_disable_version_39, false);
- SetQuicReloadableFlag(quic_disable_version_44, false);
SetQuicReloadableFlag(quic_enable_version_47, true);
- SetQuicReloadableFlag(quic_enable_version_48, true);
+ SetQuicReloadableFlag(quic_enable_version_48_2, true);
SetQuicReloadableFlag(quic_enable_version_99, true);
VerifyVersionNotSupported(QuicVersionReservedForNegotiation());
@@ -942,12 +946,12 @@ TEST_F(QuicDispatcherTest, SupportedTransportVersionsChangeInFlight) {
VerifyVersionSupported(QuicVersionMax());
// Turn off version 48.
- SetQuicReloadableFlag(quic_enable_version_48, false);
+ SetQuicReloadableFlag(quic_enable_version_48_2, false);
VerifyVersionNotSupported(
ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_48));
// Turn on version 48.
- SetQuicReloadableFlag(quic_enable_version_48, true);
+ SetQuicReloadableFlag(quic_enable_version_48_2, true);
VerifyVersionSupported(
ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_48));
@@ -961,16 +965,6 @@ TEST_F(QuicDispatcherTest, SupportedTransportVersionsChangeInFlight) {
VerifyVersionSupported(
ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_47));
- // Turn off version 44.
- SetQuicReloadableFlag(quic_disable_version_44, true);
- VerifyVersionNotSupported(
- ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_44));
-
- // Turn on version 44.
- SetQuicReloadableFlag(quic_disable_version_44, false);
- VerifyVersionSupported(
- ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_44));
-
// Turn off version 39.
SetQuicReloadableFlag(quic_disable_version_39, true);
VerifyVersionNotSupported(
@@ -983,7 +977,7 @@ TEST_F(QuicDispatcherTest, SupportedTransportVersionsChangeInFlight) {
}
TEST_F(QuicDispatcherTest, RejectDeprecatedVersionsWithVersionNegotiation) {
- static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 7u,
+ static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 6u,
"Please add deprecated versions to this test");
QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
CreateTimeWaitListManager();
@@ -994,9 +988,345 @@ TEST_F(QuicDispatcherTest, RejectDeprecatedVersionsWithVersionNegotiation) {
QuicTime::Zero());
EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _)).Times(0);
EXPECT_CALL(*time_wait_list_manager_,
- SendVersionNegotiationPacket(_, _, _, _, _, _, _))
+ SendVersionNegotiationPacket(_, _, _, _, _, _, _, _))
.Times(1);
dispatcher_->ProcessPacket(server_address_, client_address, packet);
+
+ char packet44[kMinPacketSizeForVersionNegotiation] = {
+ 0xFF, 'Q', '0', '4', '4', /*connection ID length byte*/ 0x50};
+ QuicReceivedPacket packet2(packet44, kMinPacketSizeForVersionNegotiation,
+ QuicTime::Zero());
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _)).Times(0);
+ EXPECT_CALL(*time_wait_list_manager_,
+ SendVersionNegotiationPacket(_, _, _, _, _, _, _, _))
+ .Times(1);
+ dispatcher_->ProcessPacket(server_address_, client_address, packet2);
+}
+
+TEST_F(QuicDispatcherTest, VersionNegotiationProbeOld) {
+ SetQuicFlag(FLAGS_quic_prober_uses_length_prefixed_connection_ids, false);
+ SetQuicReloadableFlag(quic_use_length_prefix_from_packet_info, true);
+ QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
+ CreateTimeWaitListManager();
+ char packet[1200];
+ char destination_connection_id_bytes[] = {0x56, 0x4e, 0x20, 0x70,
+ 0x6c, 0x7a, 0x20, 0x21};
+ EXPECT_TRUE(QuicFramer::WriteClientVersionNegotiationProbePacket(
+ packet, sizeof(packet), destination_connection_id_bytes,
+ sizeof(destination_connection_id_bytes)));
+ QuicEncryptedPacket encrypted(packet, sizeof(packet), false);
+ std::unique_ptr<QuicReceivedPacket> received_packet(
+ ConstructReceivedPacket(encrypted, mock_helper_.GetClock()->Now()));
+ QuicConnectionId client_connection_id = EmptyQuicConnectionId();
+ QuicConnectionId server_connection_id(
+ destination_connection_id_bytes, sizeof(destination_connection_id_bytes));
+ bool ietf_quic = true;
+ bool use_length_prefix =
+ GetQuicFlag(FLAGS_quic_prober_uses_length_prefixed_connection_ids);
+ EXPECT_CALL(
+ *time_wait_list_manager_,
+ SendVersionNegotiationPacket(server_connection_id, client_connection_id,
+ ietf_quic, use_length_prefix, _, _, _, _))
+ .Times(1);
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _)).Times(0);
+
+ dispatcher_->ProcessPacket(server_address_, client_address, *received_packet);
+}
+
+TEST_F(QuicDispatcherTest, VersionNegotiationProbe) {
+ SetQuicFlag(FLAGS_quic_prober_uses_length_prefixed_connection_ids, true);
+ SetQuicReloadableFlag(quic_use_parse_public_header, true);
+ SetQuicReloadableFlag(quic_use_length_prefix_from_packet_info, true);
+ QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
+ CreateTimeWaitListManager();
+ char packet[1200];
+ char destination_connection_id_bytes[] = {0x56, 0x4e, 0x20, 0x70,
+ 0x6c, 0x7a, 0x20, 0x21};
+ EXPECT_TRUE(QuicFramer::WriteClientVersionNegotiationProbePacket(
+ packet, sizeof(packet), destination_connection_id_bytes,
+ sizeof(destination_connection_id_bytes)));
+ QuicEncryptedPacket encrypted(packet, sizeof(packet), false);
+ std::unique_ptr<QuicReceivedPacket> received_packet(
+ ConstructReceivedPacket(encrypted, mock_helper_.GetClock()->Now()));
+ QuicConnectionId client_connection_id = EmptyQuicConnectionId();
+ QuicConnectionId server_connection_id(
+ destination_connection_id_bytes, sizeof(destination_connection_id_bytes));
+ bool ietf_quic = true;
+ bool use_length_prefix =
+ GetQuicFlag(FLAGS_quic_prober_uses_length_prefixed_connection_ids);
+ EXPECT_CALL(
+ *time_wait_list_manager_,
+ SendVersionNegotiationPacket(server_connection_id, client_connection_id,
+ ietf_quic, use_length_prefix, _, _, _, _))
+ .Times(1);
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _)).Times(0);
+
+ dispatcher_->ProcessPacket(server_address_, client_address, *received_packet);
+}
+
+// Testing packet writer that saves all packets instead of sending them.
+// Useful for tests that need access to sent packets.
+class SavingWriter : public QuicPacketWriterWrapper {
+ public:
+ bool IsWriteBlocked() const override { return false; }
+
+ WriteResult WritePacket(const char* buffer,
+ size_t buf_len,
+ const QuicIpAddress& /*self_client_address*/,
+ const QuicSocketAddress& /*peer_client_address*/,
+ PerPacketOptions* /*options*/) override {
+ packets_.push_back(
+ QuicEncryptedPacket(buffer, buf_len, /*owns_buffer=*/false).Clone());
+ return WriteResult(WRITE_STATUS_OK, buf_len);
+ }
+
+ std::vector<std::unique_ptr<QuicEncryptedPacket>>* packets() {
+ return &packets_;
+ }
+
+ private:
+ std::vector<std::unique_ptr<QuicEncryptedPacket>> packets_;
+};
+
+TEST_F(QuicDispatcherTest, VersionNegotiationProbeEndToEndOld) {
+ SetQuicFlag(FLAGS_quic_prober_uses_length_prefixed_connection_ids, false);
+ SetQuicReloadableFlag(quic_use_length_prefix_from_packet_info, true);
+
+ SavingWriter* saving_writer = new SavingWriter();
+ // dispatcher_ takes ownership of saving_writer.
+ QuicDispatcherPeer::UseWriter(dispatcher_.get(), saving_writer);
+
+ QuicTimeWaitListManager* time_wait_list_manager = new QuicTimeWaitListManager(
+ saving_writer, dispatcher_.get(), mock_helper_.GetClock(),
+ &mock_alarm_factory_);
+ // dispatcher_ takes ownership of time_wait_list_manager.
+ QuicDispatcherPeer::SetTimeWaitListManager(dispatcher_.get(),
+ time_wait_list_manager);
+ char packet[1200] = {};
+ char destination_connection_id_bytes[] = {0x56, 0x4e, 0x20, 0x70,
+ 0x6c, 0x7a, 0x20, 0x21};
+ EXPECT_TRUE(QuicFramer::WriteClientVersionNegotiationProbePacket(
+ packet, sizeof(packet), destination_connection_id_bytes,
+ sizeof(destination_connection_id_bytes)));
+ QuicEncryptedPacket encrypted(packet, sizeof(packet), false);
+ std::unique_ptr<QuicReceivedPacket> received_packet(
+ ConstructReceivedPacket(encrypted, mock_helper_.GetClock()->Now()));
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _)).Times(0);
+
+ QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
+ dispatcher_->ProcessPacket(server_address_, client_address, *received_packet);
+ ASSERT_EQ(1u, saving_writer->packets()->size());
+
+ char source_connection_id_bytes[255] = {};
+ uint8_t source_connection_id_length = 0;
+ std::string detailed_error = "foobar";
+ EXPECT_TRUE(QuicFramer::ParseServerVersionNegotiationProbeResponse(
+ (*(saving_writer->packets()))[0]->data(),
+ (*(saving_writer->packets()))[0]->length(), source_connection_id_bytes,
+ &source_connection_id_length, &detailed_error));
+ EXPECT_EQ("", detailed_error);
+
+ // The source connection ID of the probe response should match the
+ // destination connection ID of the probe request.
+ test::CompareCharArraysWithHexError(
+ "parsed probe", source_connection_id_bytes, source_connection_id_length,
+ destination_connection_id_bytes, sizeof(destination_connection_id_bytes));
+}
+
+TEST_F(QuicDispatcherTest, VersionNegotiationProbeEndToEnd) {
+ SetQuicFlag(FLAGS_quic_prober_uses_length_prefixed_connection_ids, true);
+ SetQuicReloadableFlag(quic_use_parse_public_header, true);
+ SetQuicReloadableFlag(quic_use_length_prefix_from_packet_info, true);
+
+ SavingWriter* saving_writer = new SavingWriter();
+ // dispatcher_ takes ownership of saving_writer.
+ QuicDispatcherPeer::UseWriter(dispatcher_.get(), saving_writer);
+
+ QuicTimeWaitListManager* time_wait_list_manager = new QuicTimeWaitListManager(
+ saving_writer, dispatcher_.get(), mock_helper_.GetClock(),
+ &mock_alarm_factory_);
+ // dispatcher_ takes ownership of time_wait_list_manager.
+ QuicDispatcherPeer::SetTimeWaitListManager(dispatcher_.get(),
+ time_wait_list_manager);
+ char packet[1200] = {};
+ char destination_connection_id_bytes[] = {0x56, 0x4e, 0x20, 0x70,
+ 0x6c, 0x7a, 0x20, 0x21};
+ EXPECT_TRUE(QuicFramer::WriteClientVersionNegotiationProbePacket(
+ packet, sizeof(packet), destination_connection_id_bytes,
+ sizeof(destination_connection_id_bytes)));
+ QuicEncryptedPacket encrypted(packet, sizeof(packet), false);
+ std::unique_ptr<QuicReceivedPacket> received_packet(
+ ConstructReceivedPacket(encrypted, mock_helper_.GetClock()->Now()));
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _)).Times(0);
+
+ QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
+ dispatcher_->ProcessPacket(server_address_, client_address, *received_packet);
+ ASSERT_EQ(1u, saving_writer->packets()->size());
+
+ char source_connection_id_bytes[255] = {};
+ uint8_t source_connection_id_length = 0;
+ std::string detailed_error = "foobar";
+ EXPECT_TRUE(QuicFramer::ParseServerVersionNegotiationProbeResponse(
+ (*(saving_writer->packets()))[0]->data(),
+ (*(saving_writer->packets()))[0]->length(), source_connection_id_bytes,
+ &source_connection_id_length, &detailed_error));
+ EXPECT_EQ("", detailed_error);
+
+ // The source connection ID of the probe response should match the
+ // destination connection ID of the probe request.
+ test::CompareCharArraysWithHexError(
+ "parsed probe", source_connection_id_bytes, source_connection_id_length,
+ destination_connection_id_bytes, sizeof(destination_connection_id_bytes));
+}
+
+TEST_F(QuicDispatcherTest, AndroidConformanceTestOld) {
+ // TODO(b/139691956) Remove this test once the workaround is removed.
+ // This test requires the workaround behind this flag to pass.
+ SetQuicReloadableFlag(quic_reply_to_old_android_conformance_test, true);
+ SavingWriter* saving_writer = new SavingWriter();
+ // dispatcher_ takes ownership of saving_writer.
+ QuicDispatcherPeer::UseWriter(dispatcher_.get(), saving_writer);
+
+ QuicTimeWaitListManager* time_wait_list_manager = new QuicTimeWaitListManager(
+ saving_writer, dispatcher_.get(), mock_helper_.GetClock(),
+ &mock_alarm_factory_);
+ // dispatcher_ takes ownership of time_wait_list_manager.
+ QuicDispatcherPeer::SetTimeWaitListManager(dispatcher_.get(),
+ time_wait_list_manager);
+ // clang-format off
+ static const unsigned char packet[] = {
+ // Android UDP network conformance test packet as it was before this change:
+ // https://android-review.googlesource.com/c/platform/cts/+/1104285
+ 0x0c, // public flags: 8-byte connection ID, 1-byte packet number
+ 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, // 8-byte connection ID
+ 0x01, // 1-byte packet number
+ 0x00, // private flags
+ 0x07, // PING frame
+ };
+ // clang-format on
+
+ QuicEncryptedPacket encrypted(reinterpret_cast<const char*>(packet),
+ sizeof(packet), false);
+ std::unique_ptr<QuicReceivedPacket> received_packet(
+ ConstructReceivedPacket(encrypted, mock_helper_.GetClock()->Now()));
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _)).Times(0);
+
+ QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
+ dispatcher_->ProcessPacket(server_address_, client_address, *received_packet);
+ ASSERT_EQ(1u, saving_writer->packets()->size());
+
+ // The Android UDP network conformance test directly checks that bytes 1-9
+ // of the response match the connection ID that was sent.
+ static const char connection_id_bytes[] = {0x71, 0x72, 0x73, 0x74,
+ 0x75, 0x76, 0x77, 0x78};
+ ASSERT_GE((*(saving_writer->packets()))[0]->length(),
+ 1u + sizeof(connection_id_bytes));
+ test::CompareCharArraysWithHexError(
+ "response connection ID", &(*(saving_writer->packets()))[0]->data()[1],
+ sizeof(connection_id_bytes), connection_id_bytes,
+ sizeof(connection_id_bytes));
+}
+
+TEST_F(QuicDispatcherTest, AndroidConformanceTestNewWithWorkaround) {
+ // TODO(b/139691956) Remove this test once the workaround is removed.
+ // This test doesn't need the workaround but we make sure that it passes even
+ // when the flag is true, also see AndroidConformanceTest below.
+ SetQuicReloadableFlag(quic_reply_to_old_android_conformance_test, true);
+ SavingWriter* saving_writer = new SavingWriter();
+ // dispatcher_ takes ownership of saving_writer.
+ QuicDispatcherPeer::UseWriter(dispatcher_.get(), saving_writer);
+
+ QuicTimeWaitListManager* time_wait_list_manager = new QuicTimeWaitListManager(
+ saving_writer, dispatcher_.get(), mock_helper_.GetClock(),
+ &mock_alarm_factory_);
+ // dispatcher_ takes ownership of time_wait_list_manager.
+ QuicDispatcherPeer::SetTimeWaitListManager(dispatcher_.get(),
+ time_wait_list_manager);
+ // clang-format off
+ static const unsigned char packet[1200] = {
+ // Android UDP network conformance test packet as it was after this change:
+ // https://android-review.googlesource.com/c/platform/cts/+/1104285
+ 0x0d, // public flags: version, 8-byte connection ID, 1-byte packet number
+ 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, // 8-byte connection ID
+ 0xaa, 0xda, 0xca, 0xaa, // reserved-space version number
+ 0x01, // 1-byte packet number
+ 0x00, // private flags
+ 0x07, // PING frame
+ };
+ // clang-format on
+
+ QuicEncryptedPacket encrypted(reinterpret_cast<const char*>(packet),
+ sizeof(packet), false);
+ std::unique_ptr<QuicReceivedPacket> received_packet(
+ ConstructReceivedPacket(encrypted, mock_helper_.GetClock()->Now()));
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _)).Times(0);
+
+ QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
+ dispatcher_->ProcessPacket(server_address_, client_address, *received_packet);
+ ASSERT_EQ(1u, saving_writer->packets()->size());
+
+ // The Android UDP network conformance test directly checks that bytes 1-9
+ // of the response match the connection ID that was sent.
+ static const char connection_id_bytes[] = {0x71, 0x72, 0x73, 0x74,
+ 0x75, 0x76, 0x77, 0x78};
+ ASSERT_GE((*(saving_writer->packets()))[0]->length(),
+ 1u + sizeof(connection_id_bytes));
+ test::CompareCharArraysWithHexError(
+ "response connection ID", &(*(saving_writer->packets()))[0]->data()[1],
+ sizeof(connection_id_bytes), connection_id_bytes,
+ sizeof(connection_id_bytes));
+}
+
+TEST_F(QuicDispatcherTest, AndroidConformanceTest) {
+ // WARNING: do not remove or modify this test without making sure that we
+ // still have adequate coverage for the Android conformance test.
+
+ // Set the flag to false to make sure this test passes even when the
+ // workaround is disabled.
+ SetQuicReloadableFlag(quic_reply_to_old_android_conformance_test, false);
+ SavingWriter* saving_writer = new SavingWriter();
+ // dispatcher_ takes ownership of saving_writer.
+ QuicDispatcherPeer::UseWriter(dispatcher_.get(), saving_writer);
+
+ QuicTimeWaitListManager* time_wait_list_manager = new QuicTimeWaitListManager(
+ saving_writer, dispatcher_.get(), mock_helper_.GetClock(),
+ &mock_alarm_factory_);
+ // dispatcher_ takes ownership of time_wait_list_manager.
+ QuicDispatcherPeer::SetTimeWaitListManager(dispatcher_.get(),
+ time_wait_list_manager);
+ // clang-format off
+ static const unsigned char packet[1200] = {
+ // Android UDP network conformance test packet as it was after this change:
+ // https://android-review.googlesource.com/c/platform/cts/+/1104285
+ 0x0d, // public flags: version, 8-byte connection ID, 1-byte packet number
+ 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, // 8-byte connection ID
+ 0xaa, 0xda, 0xca, 0xaa, // reserved-space version number
+ 0x01, // 1-byte packet number
+ 0x00, // private flags
+ 0x07, // PING frame
+ };
+ // clang-format on
+
+ QuicEncryptedPacket encrypted(reinterpret_cast<const char*>(packet),
+ sizeof(packet), false);
+ std::unique_ptr<QuicReceivedPacket> received_packet(
+ ConstructReceivedPacket(encrypted, mock_helper_.GetClock()->Now()));
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _)).Times(0);
+
+ QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
+ dispatcher_->ProcessPacket(server_address_, client_address, *received_packet);
+ ASSERT_EQ(1u, saving_writer->packets()->size());
+
+ // The Android UDP network conformance test directly checks that bytes 1-9
+ // of the response match the connection ID that was sent.
+ static const char connection_id_bytes[] = {0x71, 0x72, 0x73, 0x74,
+ 0x75, 0x76, 0x77, 0x78};
+ ASSERT_GE((*(saving_writer->packets()))[0]->length(),
+ 1u + sizeof(connection_id_bytes));
+ test::CompareCharArraysWithHexError(
+ "response connection ID", &(*(saving_writer->packets()))[0]->data()[1],
+ sizeof(connection_id_bytes), connection_id_bytes,
+ sizeof(connection_id_bytes));
}
// Verify the stopgap test: Packets with truncated connection IDs should be
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 f13eec4ae3a..1be1786297f 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
@@ -157,6 +157,7 @@ const char* QuicErrorCodeToString(QuicErrorCode error) {
RETURN_STRING_LITERAL(QUIC_IETF_GQUIC_ERROR_MISSING);
RETURN_STRING_LITERAL(
QUIC_WINDOW_UPDATE_RECEIVED_ON_READ_UNIDIRECTIONAL_STREAM);
+ RETURN_STRING_LITERAL(QUIC_TOO_MANY_BUFFERED_CONTROL_FRAMES);
RETURN_STRING_LITERAL(QUIC_LAST_ERROR);
// Intentionally have no default case, so we'll break the build
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.h b/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.h
index abc666df908..534d0b5e4c3 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
@@ -334,8 +334,11 @@ enum QuicErrorCode {
// Received WindowUpdate on a READ_UNIDIRECTIONAL stream.
QUIC_WINDOW_UPDATE_RECEIVED_ON_READ_UNIDIRECTIONAL_STREAM = 123,
+ // There are too many buffered control frames in control frame manager.
+ QUIC_TOO_MANY_BUFFERED_CONTROL_FRAMES = 124,
+
// No error. Used as bound while iterating.
- QUIC_LAST_ERROR = 124,
+ QUIC_LAST_ERROR = 125,
};
// QuicErrorCodes is encoded as a single octet on-the-wire.
static_assert(static_cast<int>(QUIC_LAST_ERROR) <=
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 e9d6fa9f598..9890f3627a5 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
@@ -24,6 +24,7 @@
#include "net/third_party/quiche/src/quic/core/quic_data_reader.h"
#include "net/third_party/quiche/src/quic/core/quic_data_writer.h"
#include "net/third_party/quiche/src/quic/core/quic_error_codes.h"
+#include "net/third_party/quiche/src/quic/core/quic_packets.h"
#include "net/third_party/quiche/src/quic/core/quic_socket_address_coder.h"
#include "net/third_party/quiche/src/quic/core/quic_stream_frame_data_producer.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
@@ -50,11 +51,6 @@ namespace {
#define ENDPOINT \
(perspective_ == Perspective::IS_SERVER ? "Server: " : "Client: ")
-// How much to shift the timestamp in the IETF Ack frame.
-// TODO(fkastenholz) when we get real IETF QUIC, need to get
-// the currect shift from the transport parameters.
-const int kIetfAckTimestampShift = 3;
-
// Number of bits the packet number length bits are shifted from the right
// edge of the header.
const uint8_t kPublicHeaderSequenceNumberShift = 4;
@@ -195,66 +191,25 @@ QuicPacketNumberLength ReadAckPacketNumberLength(
}
uint8_t PacketNumberLengthToOnWireValue(
- QuicTransportVersion version,
QuicPacketNumberLength packet_number_length) {
- if (version > QUIC_VERSION_44) {
- return packet_number_length - 1;
- }
- switch (packet_number_length) {
- case PACKET_1BYTE_PACKET_NUMBER:
- return 0;
- case PACKET_2BYTE_PACKET_NUMBER:
- return 1;
- case PACKET_4BYTE_PACKET_NUMBER:
- return 2;
- default:
- QUIC_BUG << "Invalid packet number length.";
- return 0;
- }
+ return packet_number_length - 1;
}
-bool GetShortHeaderPacketNumberLength(
- QuicTransportVersion version,
- uint8_t type,
- bool infer_packet_header_type_from_version,
- QuicPacketNumberLength* packet_number_length) {
+QuicPacketNumberLength GetShortHeaderPacketNumberLength(uint8_t type) {
DCHECK(!(type & FLAGS_LONG_HEADER));
- const bool two_bits_packet_number_length =
- infer_packet_header_type_from_version ? version > QUIC_VERSION_44
- : (type & FLAGS_FIXED_BIT);
- if (two_bits_packet_number_length) {
- *packet_number_length =
- static_cast<QuicPacketNumberLength>((type & 0x03) + 1);
- return true;
- }
- switch (type & 0x07) {
- case 0:
- *packet_number_length = PACKET_1BYTE_PACKET_NUMBER;
- break;
- case 1:
- *packet_number_length = PACKET_2BYTE_PACKET_NUMBER;
- break;
- case 2:
- *packet_number_length = PACKET_4BYTE_PACKET_NUMBER;
- break;
- default:
- *packet_number_length = PACKET_6BYTE_PACKET_NUMBER;
- return false;
- }
- return true;
+ return static_cast<QuicPacketNumberLength>((type & 0x03) + 1);
}
-uint8_t LongHeaderTypeToOnWireValue(QuicTransportVersion version,
- QuicLongHeaderType type) {
+uint8_t LongHeaderTypeToOnWireValue(QuicLongHeaderType type) {
switch (type) {
case INITIAL:
- return version > QUIC_VERSION_44 ? 0 : 0x7F;
+ return 0;
case ZERO_RTT_PROTECTED:
- return version > QUIC_VERSION_44 ? 1 << 4 : 0x7C;
+ return 1 << 4;
case HANDSHAKE:
- return version > QUIC_VERSION_44 ? 2 << 4 : 0x7D;
+ return 2 << 4;
case RETRY:
- return version > QUIC_VERSION_44 ? 3 << 4 : 0x7E;
+ return 3 << 4;
case VERSION_NEGOTIATION:
return 0xF0; // Value does not matter
default:
@@ -263,61 +218,31 @@ uint8_t LongHeaderTypeToOnWireValue(QuicTransportVersion version,
}
}
-bool GetLongHeaderType(QuicTransportVersion version,
- uint8_t type,
- QuicLongHeaderType* long_header_type) {
- DCHECK((type & FLAGS_LONG_HEADER) && version != QUIC_VERSION_UNSUPPORTED);
- if (version > QUIC_VERSION_44) {
- switch ((type & 0x30) >> 4) {
- case 0:
- *long_header_type = INITIAL;
- break;
- case 1:
- *long_header_type = ZERO_RTT_PROTECTED;
- break;
- case 2:
- *long_header_type = HANDSHAKE;
- break;
- case 3:
- *long_header_type = RETRY;
- break;
- default:
- QUIC_BUG << "Unreachable statement";
- *long_header_type = INVALID_PACKET_TYPE;
- return false;
- }
- return true;
- }
-
- switch (type & 0x7F) {
- case 0x7F:
+bool GetLongHeaderType(uint8_t type, QuicLongHeaderType* long_header_type) {
+ DCHECK((type & FLAGS_LONG_HEADER));
+ switch ((type & 0x30) >> 4) {
+ case 0:
*long_header_type = INITIAL;
break;
- case 0x7C:
+ case 1:
*long_header_type = ZERO_RTT_PROTECTED;
break;
- case 0x7D:
+ case 2:
*long_header_type = HANDSHAKE;
break;
- case 0x7E:
+ case 3:
*long_header_type = RETRY;
break;
default:
- // Invalid packet header type. Whether a packet is version negotiation is
- // determined by the version field.
+ QUIC_BUG << "Unreachable statement";
*long_header_type = INVALID_PACKET_TYPE;
return false;
}
return true;
}
-QuicPacketNumberLength GetLongHeaderPacketNumberLength(
- QuicTransportVersion version,
- uint8_t type) {
- if (version > QUIC_VERSION_44) {
- return static_cast<QuicPacketNumberLength>((type & 0x03) + 1);
- }
- return PACKET_4BYTE_PACKET_NUMBER;
+QuicPacketNumberLength GetLongHeaderPacketNumberLength(uint8_t type) {
+ return static_cast<QuicPacketNumberLength>((type & 0x03) + 1);
}
// Used to get packet number space before packet gets decrypted.
@@ -408,6 +333,7 @@ bool IsValidFullPacketNumber(uint64_t full_packet_number,
}
bool AppendIetfConnectionIds(bool version_flag,
+ bool use_length_prefix,
QuicConnectionId destination_connection_id,
QuicConnectionId source_connection_id,
QuicDataWriter* writer) {
@@ -415,6 +341,11 @@ bool AppendIetfConnectionIds(bool version_flag,
return writer->WriteConnectionId(destination_connection_id);
}
+ if (use_length_prefix) {
+ return writer->WriteLengthPrefixedConnectionId(destination_connection_id) &&
+ writer->WriteLengthPrefixedConnectionId(source_connection_id);
+ }
+
// Compute connection ID length byte.
uint8_t dcil = GetConnectionIdLengthValue(
static_cast<QuicConnectionIdLength>(destination_connection_id.length()));
@@ -454,6 +385,17 @@ PacketHeaderFormat GetIetfPacketHeaderFormat(uint8_t type_byte) {
: IETF_QUIC_SHORT_HEADER_PACKET;
}
+std::string GenerateErrorString(std::string initial_error_string,
+ QuicErrorCode quic_error_code) {
+ if (quic_error_code == QUIC_IETF_GQUIC_ERROR_MISSING) {
+ // QUIC_IETF_GQUIC_ERROR_MISSING is special -- it means not to encode
+ // the error value in the string.
+ return initial_error_string;
+ }
+ return QuicStrCat(std::to_string(static_cast<unsigned>(quic_error_code)), ":",
+ initial_error_string);
+}
+
} // namespace
QuicFramer::QuicFramer(const ParsedQuicVersionVector& supported_versions,
@@ -482,7 +424,10 @@ QuicFramer::QuicFramer(const ParsedQuicVersionVector& supported_versions,
expected_server_connection_id_length),
expected_client_connection_id_length_(0),
supports_multiple_packet_number_spaces_(false),
- last_written_packet_number_length_(0) {
+ last_written_packet_number_length_(0),
+ peer_ack_delay_exponent_(kDefaultAckDelayExponent),
+ local_ack_delay_exponent_(kDefaultAckDelayExponent),
+ current_received_frame_type_(0) {
DCHECK(!supported_versions.empty());
version_ = supported_versions_[0];
decrypter_[ENCRYPTION_INITIAL] = QuicMakeUnique<NullDecrypter>(perspective);
@@ -573,18 +518,19 @@ size_t QuicFramer::GetConnectionCloseFrameSize(
kQuicErrorDetailsLengthSize +
TruncatedErrorStringSize(frame.error_details);
}
- // TODO(fkastenholz): For complete support of IETF QUIC CONNECTION_CLOSE,
- // check if the frame is a Transport close and if the frame's
- // extracted_error_code is not QUIC_IETF_GQUIC_ERROR_MISSING. If so,
- // extend the error string to include " QuicErrorCode: #"
- const size_t truncated_error_string_size =
- TruncatedErrorStringSize(frame.error_details);
+
+ // Prepend the extra error information to the string and get the result's
+ // length.
+ const size_t truncated_error_string_size = TruncatedErrorStringSize(
+ GenerateErrorString(frame.error_details, frame.extracted_error_code));
+
uint64_t close_code = 0;
if (frame.close_type == IETF_QUIC_TRANSPORT_CONNECTION_CLOSE) {
close_code = static_cast<uint64_t>(frame.transport_error_code);
} else if (frame.close_type == IETF_QUIC_APPLICATION_CONNECTION_CLOSE) {
close_code = static_cast<uint64_t>(frame.application_error_code);
}
+
const size_t frame_size =
truncated_error_string_size +
QuicDataWriter::GetVarInt62Len(truncated_error_string_size) +
@@ -592,7 +538,8 @@ size_t QuicFramer::GetConnectionCloseFrameSize(
if (frame.close_type == IETF_QUIC_APPLICATION_CONNECTION_CLOSE) {
return frame_size;
}
- // frame includes the transport_close_frame_type, so include its length.
+ // The Transport close frame has the transport_close_frame_type, so include
+ // its length.
return frame_size +
QuicDataWriter::GetVarInt62Len(frame.transport_close_frame_type);
}
@@ -1373,8 +1320,7 @@ std::unique_ptr<QuicEncryptedPacket> QuicFramer::BuildIetfStatelessResetPacket(
type |= FLAGS_FIXED_BIT;
type |= FLAGS_SHORT_HEADER_RESERVED_1;
type |= FLAGS_SHORT_HEADER_RESERVED_2;
- type |= PacketNumberLengthToOnWireValue(QUIC_VERSION_UNSUPPORTED,
- PACKET_1BYTE_PACKET_NUMBER);
+ type |= PacketNumberLengthToOnWireValue(PACKET_1BYTE_PACKET_NUMBER);
// Append type byte.
if (!writer.WriteUInt8(type)) {
@@ -1399,6 +1345,7 @@ std::unique_ptr<QuicEncryptedPacket> QuicFramer::BuildVersionNegotiationPacket(
QuicConnectionId server_connection_id,
QuicConnectionId client_connection_id,
bool ietf_quic,
+ bool use_length_prefix,
const ParsedQuicVersionVector& versions) {
ParsedQuicVersionVector wire_versions = versions;
if (!GetQuicReloadableFlag(quic_version_negotiation_grease)) {
@@ -1431,11 +1378,14 @@ std::unique_ptr<QuicEncryptedPacket> QuicFramer::BuildVersionNegotiationPacket(
}
if (ietf_quic) {
return BuildIetfVersionNegotiationPacket(
- server_connection_id, client_connection_id, wire_versions);
+ use_length_prefix, server_connection_id, client_connection_id,
+ wire_versions);
}
// The GQUIC encoding does not support encoding client connection IDs.
DCHECK(client_connection_id.IsEmpty());
+ // The GQUIC encoding does not support length-prefixed connection IDs.
+ DCHECK(!use_length_prefix);
DCHECK(!wire_versions.empty());
size_t len = kPublicFlagsSize + server_connection_id.length() +
@@ -1467,17 +1417,25 @@ std::unique_ptr<QuicEncryptedPacket> QuicFramer::BuildVersionNegotiationPacket(
// static
std::unique_ptr<QuicEncryptedPacket>
QuicFramer::BuildIetfVersionNegotiationPacket(
+ bool use_length_prefix,
QuicConnectionId server_connection_id,
QuicConnectionId client_connection_id,
const ParsedQuicVersionVector& versions) {
- QUIC_DVLOG(1) << "Building IETF version negotiation packet: "
+ QUIC_DVLOG(1) << "Building IETF version negotiation packet with"
+ << (use_length_prefix ? "" : "out")
+ << " length prefix, server_connection_id "
+ << server_connection_id << " client_connection_id "
+ << client_connection_id << " versions "
<< ParsedQuicVersionVectorToString(versions);
- DCHECK(client_connection_id.IsEmpty() ||
- GetQuicRestartFlag(quic_do_not_override_connection_id));
DCHECK(!versions.empty());
size_t len = kPacketHeaderTypeSize + kConnectionIdLengthSize +
client_connection_id.length() + server_connection_id.length() +
(versions.size() + 1) * kQuicVersionSize;
+ if (use_length_prefix) {
+ // When using length-prefixed connection IDs, packets carry two lengths
+ // instead of one.
+ len += kConnectionIdLengthSize;
+ }
std::unique_ptr<char[]> buffer(new char[len]);
QuicDataWriter writer(len, buffer.get());
@@ -1491,8 +1449,8 @@ QuicFramer::BuildIetfVersionNegotiationPacket(
return nullptr;
}
- if (!AppendIetfConnectionIds(true, client_connection_id, server_connection_id,
- &writer)) {
+ if (!AppendIetfConnectionIds(true, use_length_prefix, client_connection_id,
+ server_connection_id, &writer)) {
return nullptr;
}
@@ -1630,16 +1588,32 @@ bool QuicFramer::ProcessRetryPacket(QuicDataReader* reader,
const QuicPacketHeader& header) {
DCHECK_EQ(Perspective::IS_CLIENT, perspective_);
- // Parse Original Destination Connection ID Length.
- uint8_t odcil = header.type_byte & 0xf;
- if (odcil != 0) {
- odcil += kConnectionIdLengthAdjustment;
+ QuicConnectionId original_destination_connection_id;
+ if (version_.HasLengthPrefixedConnectionIds()) {
+ // Parse Original Destination Connection ID.
+ if (!reader->ReadLengthPrefixedConnectionId(
+ &original_destination_connection_id)) {
+ set_detailed_error("Unable to read Original Destination ConnectionId.");
+ return false;
+ }
+ } else {
+ // Parse Original Destination Connection ID Length.
+ uint8_t odcil = header.type_byte & 0xf;
+ if (odcil != 0) {
+ odcil += kConnectionIdLengthAdjustment;
+ }
+
+ // Parse Original Destination Connection ID.
+ if (!reader->ReadConnectionId(&original_destination_connection_id, odcil)) {
+ set_detailed_error("Unable to read Original Destination ConnectionId.");
+ return false;
+ }
}
- // Parse Original Destination Connection ID.
- QuicConnectionId original_destination_connection_id;
- if (!reader->ReadConnectionId(&original_destination_connection_id, odcil)) {
- set_detailed_error("Unable to read Original Destination ConnectionId.");
+ if (!QuicUtils::IsConnectionIdValidForVersion(
+ original_destination_connection_id, transport_version())) {
+ set_detailed_error(
+ "Received Original Destination ConnectionId with invalid length.");
return false;
}
@@ -1649,42 +1623,6 @@ bool QuicFramer::ProcessRetryPacket(QuicDataReader* reader,
return true;
}
-bool QuicFramer::MaybeProcessIetfInitialRetryToken(
- QuicDataReader* encrypted_reader,
- QuicPacketHeader* header) {
- if (!QuicVersionHasLongHeaderLengths(header->version.transport_version) ||
- header->form != IETF_QUIC_LONG_HEADER_PACKET ||
- header->long_packet_type != INITIAL) {
- return true;
- }
- uint64_t retry_token_length = 0;
- header->retry_token_length_length = encrypted_reader->PeekVarInt62Length();
- if (!encrypted_reader->ReadVarInt62(&retry_token_length)) {
- set_detailed_error("Unable to read INITIAL retry token length.");
- return RaiseError(QUIC_INVALID_PACKET_HEADER);
- }
- header->retry_token = encrypted_reader->PeekRemainingPayload();
- // Safety check to avoid spending ressources if malformed.
- // At this point header->retry_token contains the rest of the packet
- // so its length() is the amount of data remaining in the packet.
- if (retry_token_length > header->retry_token.length()) {
- set_detailed_error("INITIAL token length longer than packet.");
- return RaiseError(QUIC_INVALID_PACKET_HEADER);
- }
- // Resize retry_token to make it only contain the retry token.
- header->retry_token.remove_suffix(header->retry_token.length() -
- retry_token_length);
- // Advance encrypted_reader by retry_token_length.
- uint8_t wasted_byte;
- for (uint64_t i = 0; i < retry_token_length; ++i) {
- if (!encrypted_reader->ReadUInt8(&wasted_byte)) {
- set_detailed_error("Unable to read INITIAL retry token.");
- return RaiseError(QUIC_INVALID_PACKET_HEADER);
- }
- }
- return true;
-}
-
// Seeks the current packet to check for a coalesced packet at the end.
// If the IETF length field only spans part of the outer packet,
// then there is a coalesced packet after this one.
@@ -1769,8 +1707,6 @@ bool QuicFramer::ProcessIetfDataPacket(QuicDataReader* encrypted_reader,
size_t buffer_length) {
DCHECK_NE(GOOGLE_QUIC_PACKET, header->form);
DCHECK(!header->has_possible_stateless_reset_token);
- header->retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_0;
- header->retry_token = QuicStringPiece();
header->length_length = VARIABLE_LENGTH_INTEGER_LENGTH_0;
header->remaining_packet_length = 0;
if (header->form == IETF_QUIC_SHORT_HEADER_PACKET &&
@@ -1787,10 +1723,6 @@ bool QuicFramer::ProcessIetfDataPacket(QuicDataReader* encrypted_reader,
}
}
- if (!MaybeProcessIetfInitialRetryToken(encrypted_reader, header)) {
- return false;
- }
-
if (!MaybeProcessIetfLength(encrypted_reader, header)) {
return false;
}
@@ -1840,6 +1772,16 @@ bool QuicFramer::ProcessIetfDataPacket(QuicDataReader* encrypted_reader,
return true;
}
if (hp_removal_failed) {
+ if (GetQuicRestartFlag(quic_framer_uses_undecryptable_upcall)) {
+ QUIC_RESTART_FLAG_COUNT_N(quic_framer_uses_undecryptable_upcall, 5,
+ 7);
+ const EncryptionLevel decryption_level = GetEncryptionLevel(*header);
+ const bool has_decryption_key =
+ decrypter_[decryption_level] != nullptr;
+ visitor_->OnUndecryptablePacket(
+ QuicEncryptedPacket(encrypted_reader->FullPayload()),
+ decryption_level, has_decryption_key);
+ }
set_detailed_error("Unable to decrypt header protection.");
return RaiseError(QUIC_DECRYPTION_FAILURE);
}
@@ -1898,6 +1840,15 @@ bool QuicFramer::ProcessIetfDataPacket(QuicDataReader* encrypted_reader,
visitor_->OnAuthenticatedIetfStatelessResetPacket(packet);
return true;
}
+ if (GetQuicRestartFlag(quic_framer_uses_undecryptable_upcall)) {
+ QUIC_RESTART_FLAG_COUNT_N(quic_framer_uses_undecryptable_upcall, 6, 7);
+ const EncryptionLevel decryption_level = GetEncryptionLevel(*header);
+ const bool has_decryption_key = version_.KnowsWhichDecrypterToUse() &&
+ decrypter_[decryption_level] != nullptr;
+ visitor_->OnUndecryptablePacket(
+ QuicEncryptedPacket(encrypted_reader->FullPayload()),
+ decryption_level, has_decryption_key);
+ }
set_detailed_error("Unable to decrypt payload.");
RecordDroppedPacketReason(DroppedPacketReason::DECRYPTION_FAILURE);
return RaiseError(QUIC_DECRYPTION_FAILURE);
@@ -1927,13 +1878,16 @@ bool QuicFramer::ProcessIetfDataPacket(QuicDataReader* encrypted_reader,
// Handle the payload.
if (VersionHasIetfQuicFrames(version_.transport_version)) {
+ current_received_frame_type_ = 0;
if (!ProcessIetfFrameData(&reader, *header)) {
+ current_received_frame_type_ = 0;
DCHECK_NE(QUIC_NO_ERROR, error_); // ProcessIetfFrameData sets the error.
DCHECK_NE("", detailed_error_);
QUIC_DLOG(WARNING) << ENDPOINT << "Unable to process frame data. Error: "
<< detailed_error_;
return false;
}
+ current_received_frame_type_ = 0;
} else {
if (!ProcessFrameData(&reader, *header)) {
DCHECK_NE(QUIC_NO_ERROR, error_); // ProcessFrameData sets the error.
@@ -1976,6 +1930,16 @@ bool QuicFramer::ProcessDataPacket(QuicDataReader* encrypted_reader,
EncryptionLevel decrypted_level;
if (!DecryptPayload(encrypted, associated_data, *header, decrypted_buffer,
buffer_length, &decrypted_length, &decrypted_level)) {
+ if (GetQuicRestartFlag(quic_framer_uses_undecryptable_upcall)) {
+ QUIC_RESTART_FLAG_COUNT_N(quic_framer_uses_undecryptable_upcall, 7, 7);
+ const EncryptionLevel decryption_level = decrypter_level_;
+ // This version uses trial decryption so we always report to our visitor
+ // that we are not certain we have the correct decryption key.
+ const bool has_decryption_key = false;
+ visitor_->OnUndecryptablePacket(
+ QuicEncryptedPacket(encrypted_reader->FullPayload()),
+ decryption_level, has_decryption_key);
+ }
RecordDroppedPacketReason(DroppedPacketReason::DECRYPTION_FAILURE);
set_detailed_error("Unable to decrypt payload.");
return RaiseError(QUIC_DECRYPTION_FAILURE);
@@ -2161,34 +2125,15 @@ bool QuicFramer::AppendPacketHeader(const QuicPacketHeader& header,
bool QuicFramer::AppendIetfHeaderTypeByte(const QuicPacketHeader& header,
QuicDataWriter* writer) {
uint8_t type = 0;
- if (transport_version() > QUIC_VERSION_44) {
- if (header.version_flag) {
- type = static_cast<uint8_t>(
- FLAGS_LONG_HEADER | FLAGS_FIXED_BIT |
- LongHeaderTypeToOnWireValue(transport_version(),
- header.long_packet_type) |
- PacketNumberLengthToOnWireValue(transport_version(),
- header.packet_number_length));
- } else {
- type = static_cast<uint8_t>(
- FLAGS_FIXED_BIT |
- PacketNumberLengthToOnWireValue(transport_version(),
- header.packet_number_length));
- }
- return writer->WriteUInt8(type);
- }
-
if (header.version_flag) {
type = static_cast<uint8_t>(
- FLAGS_LONG_HEADER | LongHeaderTypeToOnWireValue(
- transport_version(), header.long_packet_type));
- DCHECK_EQ(PACKET_4BYTE_PACKET_NUMBER, header.packet_number_length);
+ FLAGS_LONG_HEADER | FLAGS_FIXED_BIT |
+ LongHeaderTypeToOnWireValue(header.long_packet_type) |
+ PacketNumberLengthToOnWireValue(header.packet_number_length));
} else {
- type |= FLAGS_SHORT_HEADER_RESERVED_1;
- type |= FLAGS_SHORT_HEADER_RESERVED_2;
- DCHECK_GE(PACKET_4BYTE_PACKET_NUMBER, header.packet_number_length);
- type |= PacketNumberLengthToOnWireValue(transport_version(),
- header.packet_number_length);
+ type = static_cast<uint8_t>(
+ FLAGS_FIXED_BIT |
+ PacketNumberLengthToOnWireValue(header.packet_number_length));
}
return writer->WriteUInt8(type);
}
@@ -2218,7 +2163,7 @@ bool QuicFramer::AppendIetfPacketHeader(const QuicPacketHeader& header,
// Append connection ID.
if (!AppendIetfConnectionIds(
- header.version_flag,
+ header.version_flag, version_.HasLengthPrefixedConnectionIds(),
header.destination_connection_id_included != CONNECTION_ID_ABSENT
? header.destination_connection_id
: EmptyQuicConnectionId(),
@@ -2363,8 +2308,7 @@ bool QuicFramer::ProcessPublicHeader(QuicDataReader* reader,
QuicConnectionId* header_connection_id = &header->destination_connection_id;
QuicConnectionIdIncluded* header_connection_id_included =
&header->destination_connection_id_included;
- if (perspective_ == Perspective::IS_CLIENT &&
- GetQuicRestartFlag(quic_do_not_override_connection_id)) {
+ if (perspective_ == Perspective::IS_CLIENT) {
header_connection_id = &header->source_connection_id;
header_connection_id_included = &header->source_connection_id_included;
}
@@ -2550,7 +2494,7 @@ bool QuicFramer::ProcessIetfHeaderTypeByte(QuicDataReader* reader,
QuicPacketHeader* header) {
uint8_t type;
if (!reader->ReadBytes(&type, 1)) {
- set_detailed_error("Unable to read type.");
+ set_detailed_error("Unable to read first byte.");
return false;
}
header->type_byte = type;
@@ -2583,13 +2527,11 @@ bool QuicFramer::ProcessIetfHeaderTypeByte(QuicDataReader* reader,
} else {
header->version = ParseQuicVersionLabel(version_label);
if (header->version.transport_version != QUIC_VERSION_UNSUPPORTED) {
- if (header->version.transport_version > QUIC_VERSION_44 &&
- !(type & FLAGS_FIXED_BIT)) {
+ if (!(type & FLAGS_FIXED_BIT)) {
set_detailed_error("Fixed bit is 0 in long header.");
return false;
}
- if (!GetLongHeaderType(header->version.transport_version, type,
- &header->long_packet_type)) {
+ if (!GetLongHeaderType(type, &header->long_packet_type)) {
set_detailed_error("Illegal long header type value.");
return false;
}
@@ -2603,8 +2545,7 @@ bool QuicFramer::ProcessIetfHeaderTypeByte(QuicDataReader* reader,
return false;
}
} else if (!header->version.HasHeaderProtection()) {
- header->packet_number_length = GetLongHeaderPacketNumberLength(
- header->version.transport_version, type);
+ header->packet_number_length = GetLongHeaderPacketNumberLength(type);
}
}
}
@@ -2626,17 +2567,12 @@ bool QuicFramer::ProcessIetfHeaderTypeByte(QuicDataReader* reader,
? CONNECTION_ID_PRESENT
: CONNECTION_ID_ABSENT;
header->source_connection_id_included = CONNECTION_ID_ABSENT;
- if (infer_packet_header_type_from_version_ &&
- transport_version() > QUIC_VERSION_44 && !(type & FLAGS_FIXED_BIT)) {
+ if (!(type & FLAGS_FIXED_BIT)) {
set_detailed_error("Fixed bit is 0 in short header.");
return false;
}
- if (!header->version.HasHeaderProtection() &&
- !GetShortHeaderPacketNumberLength(transport_version(), type,
- infer_packet_header_type_from_version_,
- &header->packet_number_length)) {
- set_detailed_error("Illegal short header type value.");
- return false;
+ if (!header->version.HasHeaderProtection()) {
+ header->packet_number_length = GetShortHeaderPacketNumberLength(type);
}
QUIC_DVLOG(1) << "packet_number_length = " << header->packet_number_length;
return true;
@@ -2702,8 +2638,98 @@ bool QuicFramer::ProcessAndValidateIetfConnectionIdLength(
return true;
}
+bool QuicFramer::ValidateReceivedConnectionIds(const QuicPacketHeader& header) {
+ if (!QuicUtils::IsConnectionIdValidForVersion(
+ GetServerConnectionIdAsRecipient(header, perspective_),
+ transport_version())) {
+ set_detailed_error("Received server connection ID with invalid length.");
+ return false;
+ }
+
+ if (version_.SupportsClientConnectionIds() &&
+ !QuicUtils::IsConnectionIdValidForVersion(
+ GetClientConnectionIdAsRecipient(header, perspective_),
+ transport_version())) {
+ set_detailed_error("Received client connection ID with invalid length.");
+ return false;
+ }
+ return true;
+}
+
bool QuicFramer::ProcessIetfPacketHeader(QuicDataReader* reader,
QuicPacketHeader* header) {
+ if (version_.HasLengthPrefixedConnectionIds()) {
+ uint8_t expected_destination_connection_id_length =
+ perspective_ == Perspective::IS_CLIENT
+ ? expected_client_connection_id_length_
+ : expected_server_connection_id_length_;
+ QuicVersionLabel version_label;
+ bool has_length_prefix;
+ std::string detailed_error;
+ QuicErrorCode parse_result = QuicFramer::ParsePublicHeader(
+ reader, expected_destination_connection_id_length,
+ VersionHasIetfInvariantHeader(version_.transport_version),
+ &header->type_byte, &header->form, &header->version_flag,
+ &has_length_prefix, &version_label, &header->version,
+ &header->destination_connection_id, &header->source_connection_id,
+ &header->long_packet_type, &header->retry_token_length_length,
+ &header->retry_token, &detailed_error);
+ if (parse_result != QUIC_NO_ERROR) {
+ set_detailed_error(detailed_error);
+ return false;
+ }
+ header->destination_connection_id_included = CONNECTION_ID_PRESENT;
+ header->source_connection_id_included =
+ header->version_flag ? CONNECTION_ID_PRESENT : CONNECTION_ID_ABSENT;
+ if (header->source_connection_id_included == CONNECTION_ID_ABSENT) {
+ DCHECK(header->source_connection_id.IsEmpty());
+ if (perspective_ == Perspective::IS_CLIENT) {
+ header->source_connection_id = last_serialized_server_connection_id_;
+ } else {
+ header->source_connection_id = last_serialized_client_connection_id_;
+ }
+ }
+
+ if (!ValidateReceivedConnectionIds(*header)) {
+ return false;
+ }
+
+ if (header->version_flag &&
+ header->long_packet_type != VERSION_NEGOTIATION &&
+ !(header->type_byte & FLAGS_FIXED_BIT)) {
+ set_detailed_error("Fixed bit is 0 in long header.");
+ return false;
+ }
+ if (!header->version_flag && !(header->type_byte & FLAGS_FIXED_BIT)) {
+ set_detailed_error("Fixed bit is 0 in short header.");
+ return false;
+ }
+ if (!header->version_flag) {
+ if (!version_.HasHeaderProtection()) {
+ header->packet_number_length =
+ GetShortHeaderPacketNumberLength(header->type_byte);
+ }
+ return true;
+ }
+ if (header->long_packet_type == RETRY) {
+ if (!version().SupportsRetry()) {
+ set_detailed_error("RETRY not supported in this version.");
+ return false;
+ }
+ if (perspective_ == Perspective::IS_SERVER) {
+ set_detailed_error("Client-initiated RETRY is invalid.");
+ return false;
+ }
+ return true;
+ }
+ if (!header->version.HasHeaderProtection()) {
+ header->packet_number_length =
+ GetLongHeaderPacketNumberLength(header->type_byte);
+ }
+
+ return true;
+ }
+
if (!ProcessIetfHeaderTypeByte(reader, header)) {
return false;
}
@@ -2731,54 +2757,33 @@ bool QuicFramer::ProcessIetfPacketHeader(QuicDataReader* reader,
}
}
- DCHECK_LE(destination_connection_id_length, kQuicMaxConnectionIdLength);
- DCHECK_LE(source_connection_id_length, kQuicMaxConnectionIdLength);
-
// Read connection ID.
if (!reader->ReadConnectionId(&header->destination_connection_id,
destination_connection_id_length)) {
- set_detailed_error("Unable to read Destination ConnectionId.");
+ set_detailed_error("Unable to read destination connection ID.");
return false;
}
if (!reader->ReadConnectionId(&header->source_connection_id,
source_connection_id_length)) {
- set_detailed_error("Unable to read Source ConnectionId.");
+ set_detailed_error("Unable to read source connection ID.");
return false;
}
- if (!GetQuicRestartFlag(quic_do_not_override_connection_id)) {
- if (header->source_connection_id_included == CONNECTION_ID_PRESENT) {
- DCHECK_EQ(Perspective::IS_CLIENT, perspective_);
- DCHECK_EQ(IETF_QUIC_LONG_HEADER_PACKET, header->form);
- if (!header->destination_connection_id.IsEmpty()) {
- set_detailed_error("Client connection ID not supported yet.");
- return false;
- }
- // Set destination connection ID to source connection ID.
- header->destination_connection_id = header->source_connection_id;
- } else if (header->destination_connection_id_included ==
- CONNECTION_ID_ABSENT) {
- header->destination_connection_id = last_serialized_server_connection_id_;
+ if (header->source_connection_id_included == CONNECTION_ID_ABSENT) {
+ if (!header->source_connection_id.IsEmpty()) {
+ DCHECK(!version_.SupportsClientConnectionIds());
+ set_detailed_error("Client connection ID not supported in this version.");
+ return false;
}
- } else {
- QUIC_RESTART_FLAG_COUNT_N(quic_do_not_override_connection_id, 5, 7);
- if (header->source_connection_id_included == CONNECTION_ID_ABSENT) {
- if (!header->source_connection_id.IsEmpty()) {
- DCHECK(!version_.SupportsClientConnectionIds());
- set_detailed_error(
- "Client connection ID not supported in this version.");
- return false;
- }
- if (perspective_ == Perspective::IS_CLIENT) {
- header->source_connection_id = last_serialized_server_connection_id_;
- } else {
- header->source_connection_id = last_serialized_client_connection_id_;
- }
+ if (perspective_ == Perspective::IS_CLIENT) {
+ header->source_connection_id = last_serialized_server_connection_id_;
+ } else {
+ header->source_connection_id = last_serialized_client_connection_id_;
}
}
- return true;
+ return ValidateReceivedConnectionIds(*header);
}
bool QuicFramer::ProcessAndCalculatePacketNumber(
@@ -2814,7 +2819,7 @@ bool QuicFramer::ProcessFrameData(QuicDataReader* reader,
set_detailed_error("Unable to read frame type.");
return RaiseError(QUIC_INVALID_FRAME_DATA);
}
- const uint8_t special_mask = transport_version() <= QUIC_VERSION_44
+ const uint8_t special_mask = transport_version() <= QUIC_VERSION_43
? kQuicFrameTypeBrokenMask
: kQuicFrameTypeSpecialMask;
if (frame_type & special_mask) {
@@ -2945,7 +2950,7 @@ bool QuicFramer::ProcessFrameData(QuicDataReader* reader,
case STOP_WAITING_FRAME: {
if (GetQuicReloadableFlag(quic_do_not_accept_stop_waiting) &&
- version_.transport_version >= QUIC_VERSION_44) {
+ version_.transport_version > QUIC_VERSION_43) {
QUIC_RELOADABLE_FLAG_COUNT(quic_do_not_accept_stop_waiting);
set_detailed_error("STOP WAITING not supported in version 44+.");
return RaiseError(QUIC_INVALID_STOP_WAITING_DATA);
@@ -3044,6 +3049,7 @@ bool QuicFramer::ProcessIetfFrameData(QuicDataReader* reader,
set_detailed_error("Unable to read frame type.");
return RaiseError(QUIC_INVALID_FRAME_DATA);
}
+ current_received_frame_type_ = frame_type;
// Is now the number of bytes into which the frame type was encoded.
encoded_bytes -= reader->BytesRemaining();
@@ -3753,12 +3759,10 @@ bool QuicFramer::ProcessIetfAckFrame(QuicDataReader* reader,
return false;
}
- // TODO(fkastenholz) when we get real IETF QUIC, need to get
- // the currect shift from the transport parameters.
if (ack_delay_time_in_us == kVarInt62MaxValue) {
ack_frame->ack_delay_time = QuicTime::Delta::Infinite();
} else {
- ack_delay_time_in_us = (ack_delay_time_in_us << kIetfAckTimestampShift);
+ ack_delay_time_in_us = (ack_delay_time_in_us << peer_ack_delay_exponent_);
ack_frame->ack_delay_time =
QuicTime::Delta::FromMicroseconds(ack_delay_time_in_us);
}
@@ -3958,6 +3962,11 @@ bool QuicFramer::ProcessConnectionCloseFrame(QuicDataReader* reader,
frame->quic_error_code = static_cast<QuicErrorCode>(error_code);
+ // For Google QUIC connection closes, copy the Google QUIC error code to
+ // the extracted error code field so that the Google QUIC error code is always
+ // available in extracted_error_code.
+ frame->extracted_error_code = frame->quic_error_code;
+
QuicStringPiece error_details;
if (!reader->ReadStringPiece16(&error_details)) {
set_detailed_error("Unable to read connection close error details.");
@@ -4094,6 +4103,9 @@ void QuicFramer::SetDecrypter(EncryptionLevel level,
DCHECK_EQ(alternative_decrypter_level_, NUM_ENCRYPTION_LEVELS);
DCHECK_GE(level, decrypter_level_);
DCHECK(!version_.KnowsWhichDecrypterToUse());
+ QUIC_DVLOG(1) << ENDPOINT << "Setting decrypter from level "
+ << QuicUtils::EncryptionLevelToString(decrypter_level_)
+ << " to " << QuicUtils::EncryptionLevelToString(level);
decrypter_[decrypter_level_] = nullptr;
decrypter_[level] = std::move(decrypter);
decrypter_level_ = level;
@@ -4105,6 +4117,10 @@ void QuicFramer::SetAlternativeDecrypter(
bool latch_once_used) {
DCHECK_NE(level, decrypter_level_);
DCHECK(!version_.KnowsWhichDecrypterToUse());
+ QUIC_DVLOG(1) << ENDPOINT << "Setting alternative decrypter from level "
+ << QuicUtils::EncryptionLevelToString(
+ alternative_decrypter_level_)
+ << " to " << QuicUtils::EncryptionLevelToString(level);
if (alternative_decrypter_level_ != NUM_ENCRYPTION_LEVELS) {
decrypter_[alternative_decrypter_level_] = nullptr;
}
@@ -4116,11 +4132,15 @@ void QuicFramer::SetAlternativeDecrypter(
void QuicFramer::InstallDecrypter(EncryptionLevel level,
std::unique_ptr<QuicDecrypter> decrypter) {
DCHECK(version_.KnowsWhichDecrypterToUse());
+ QUIC_DVLOG(1) << ENDPOINT << "Installing decrypter at level "
+ << QuicUtils::EncryptionLevelToString(level);
decrypter_[level] = std::move(decrypter);
}
void QuicFramer::RemoveDecrypter(EncryptionLevel level) {
DCHECK(version_.KnowsWhichDecrypterToUse());
+ QUIC_DVLOG(1) << ENDPOINT << "Removing decrypter at level "
+ << QuicUtils::EncryptionLevelToString(level);
decrypter_[level] = nullptr;
}
@@ -4144,6 +4164,8 @@ void QuicFramer::SetEncrypter(EncryptionLevel level,
std::unique_ptr<QuicEncrypter> encrypter) {
DCHECK_GE(level, 0);
DCHECK_LT(level, NUM_ENCRYPTION_LEVELS);
+ QUIC_DVLOG(1) << ENDPOINT << "Setting encrypter at level "
+ << QuicUtils::EncryptionLevelToString(level);
encrypter_[level] = std::move(encrypter);
}
@@ -4231,8 +4253,7 @@ bool QuicFramer::ApplyHeaderProtection(EncryptionLevel level,
QuicLongHeaderType header_type;
if (IsLongHeader(type_byte)) {
bitmask = 0x0f;
- if (!GetLongHeaderType(version_.transport_version, type_byte,
- &header_type)) {
+ if (!GetLongHeaderType(type_byte, &header_type)) {
return false;
}
}
@@ -4280,8 +4301,9 @@ bool QuicFramer::RemoveHeaderProtection(QuicDataReader* reader,
QuicDecrypter* decrypter = decrypter_[expected_decryption_level].get();
if (decrypter == nullptr) {
QUIC_DVLOG(1)
+ << ENDPOINT
<< "No decrypter available for removing header protection at level "
- << expected_decryption_level;
+ << QuicUtils::EncryptionLevelToString(expected_decryption_level);
return false;
}
@@ -4566,7 +4588,7 @@ size_t QuicFramer::GetIetfAckFrameSize(const QuicAckFrame& frame) {
ack_frame_size += QuicDataWriter::GetVarInt62Len(largest_acked.ToUint64());
uint64_t ack_delay_time_us;
ack_delay_time_us = frame.ack_delay_time.ToMicroseconds();
- ack_delay_time_us = ack_delay_time_us >> kIetfAckTimestampShift;
+ ack_delay_time_us = ack_delay_time_us >> local_ack_delay_exponent_;
ack_frame_size += QuicDataWriter::GetVarInt62Len(ack_delay_time_us);
// If |ecn_counters_populated| is true and any of the ecn counters is non-0
@@ -5423,8 +5445,7 @@ bool QuicFramer::AppendIetfAckFrameAndTypeByte(const QuicAckFrame& frame,
if (!frame.ack_delay_time.IsInfinite()) {
DCHECK_LE(0u, frame.ack_delay_time.ToMicroseconds());
ack_delay_time_us = frame.ack_delay_time.ToMicroseconds();
- // TODO(fkastenholz): Use the shift from TLS transport parameters.
- ack_delay_time_us = ack_delay_time_us >> kIetfAckTimestampShift;
+ ack_delay_time_us = ack_delay_time_us >> local_ack_delay_exponent_;
}
if (!writer->WriteVarInt62(ack_delay_time_us)) {
@@ -5695,12 +5716,13 @@ bool QuicFramer::AppendIetfConnectionCloseFrame(
}
}
- // TODO(fkastenholz): For full IETF CONNECTION CLOSE support,
- // if this is a Transport CONNECTION_CLOSE and the extended
- // error is not QUIC_IETF_GQUIC_ERROR_MISSING then append the extended
- // "QuicErrorCode: #" string to the phrase.
+ // There may be additional error information available in the extracted error
+ // code. Encode the error information in the reason phrase and serialize the
+ // result.
+ std::string final_error_string =
+ GenerateErrorString(frame.error_details, frame.extracted_error_code);
if (!writer->WriteStringPieceVarInt62(
- TruncateErrorString(frame.error_details))) {
+ TruncateErrorString(final_error_string))) {
set_detailed_error("Can not write connection close phrase");
return false;
}
@@ -5713,11 +5735,14 @@ bool QuicFramer::ProcessIetfConnectionCloseFrame(
QuicConnectionCloseFrame* frame) {
frame->close_type = type;
uint64_t error_code;
+
if (!reader->ReadVarInt62(&error_code)) {
set_detailed_error("Unable to read connection close error code.");
return false;
}
+ // TODO(fkastenholz): When error codes uniformly go to uint64, remove the
+ // range check.
if (frame->close_type == IETF_QUIC_TRANSPORT_CONNECTION_CLOSE) {
if (error_code > 0xffff) {
frame->transport_error_code =
@@ -5736,6 +5761,7 @@ bool QuicFramer::ProcessIetfConnectionCloseFrame(
frame->application_error_code = static_cast<uint16_t>(error_code);
}
}
+
if (type == IETF_QUIC_TRANSPORT_CONNECTION_CLOSE) {
// The frame-type of the frame causing the error is present only
// if it's a CONNECTION_CLOSE/Transport.
@@ -5750,16 +5776,18 @@ bool QuicFramer::ProcessIetfConnectionCloseFrame(
set_detailed_error("Unable to read connection close error details.");
return false;
}
+
QuicStringPiece phrase;
if (!reader->ReadStringPiece(&phrase, static_cast<size_t>(phrase_length))) {
set_detailed_error("Unable to read connection close error details.");
return false;
}
- // TODO(fkastenholz): when full support is done, add code here
- // to extract the extended error code from the reason phrase
- // and set it into frame->extracted_error_code.
frame->error_details = std::string(phrase);
+ // The frame may have an extracted error code in it. Look for it and
+ // extract it. If it's not present, MaybeExtract will return
+ // QUIC_IETF_GQUIC_ERROR_MISSING.
+ MaybeExtractQuicErrorCode(frame);
return true;
}
@@ -6090,11 +6118,6 @@ bool QuicFramer::ProcessNewConnectionIdFrame(QuicDataReader* reader,
return false;
}
- if (frame->connection_id.length() > kQuicMaxConnectionIdLength) {
- set_detailed_error("New connection ID length too high.");
- return false;
- }
-
if (!QuicUtils::IsConnectionIdValidForVersion(frame->connection_id,
transport_version())) {
set_detailed_error("Invalid new connection ID length for version.");
@@ -6208,6 +6231,7 @@ QuicErrorCode QuicFramer::ProcessPacketDispatcher(
QuicConnectionId* destination_connection_id,
QuicConnectionId* source_connection_id,
std::string* detailed_error) {
+ DCHECK(!GetQuicReloadableFlag(quic_use_parse_public_header));
QuicDataReader reader(packet.data(), packet.length());
*source_connection_id = EmptyQuicConnectionId();
@@ -6270,8 +6294,7 @@ QuicErrorCode QuicFramer::ProcessPacketDispatcher(
return QUIC_INVALID_PACKET_HEADER;
}
// Read source connection ID.
- if (GetQuicRestartFlag(quic_do_not_override_connection_id) &&
- !reader.ReadConnectionId(source_connection_id,
+ if (!reader.ReadConnectionId(source_connection_id,
source_connection_id_length)) {
*detailed_error = "Unable to read source connection ID.";
return QUIC_INVALID_PACKET_HEADER;
@@ -6280,6 +6303,271 @@ QuicErrorCode QuicFramer::ProcessPacketDispatcher(
}
// static
+QuicErrorCode QuicFramer::ParsePublicHeaderDispatcher(
+ const QuicEncryptedPacket& packet,
+ uint8_t expected_destination_connection_id_length,
+ PacketHeaderFormat* format,
+ bool* version_present,
+ bool* has_length_prefix,
+ QuicVersionLabel* version_label,
+ ParsedQuicVersion* parsed_version,
+ QuicConnectionId* destination_connection_id,
+ QuicConnectionId* source_connection_id,
+ bool* retry_token_present,
+ QuicStringPiece* retry_token,
+ std::string* detailed_error) {
+ QuicDataReader reader(packet.data(), packet.length());
+ if (reader.IsDoneReading()) {
+ *detailed_error = "Unable to read first byte.";
+ return QUIC_INVALID_PACKET_HEADER;
+ }
+ const uint8_t first_byte = reader.PeekByte();
+ const bool ietf_format = QuicUtils::IsIetfPacketHeader(first_byte);
+ uint8_t unused_first_byte;
+ QuicVariableLengthIntegerLength retry_token_length_length;
+ QuicLongHeaderType unused_log_packet_type;
+ const QuicErrorCode error_code = ParsePublicHeader(
+ &reader, expected_destination_connection_id_length, ietf_format,
+ &unused_first_byte, format, version_present, has_length_prefix,
+ version_label, parsed_version, destination_connection_id,
+ source_connection_id, &unused_log_packet_type, &retry_token_length_length,
+ retry_token, detailed_error);
+ *retry_token_present =
+ retry_token_length_length != VARIABLE_LENGTH_INTEGER_LENGTH_0;
+ return error_code;
+}
+
+// static
+QuicErrorCode QuicFramer::ParsePublicHeaderGoogleQuic(
+ QuicDataReader* reader,
+ uint8_t* first_byte,
+ PacketHeaderFormat* format,
+ bool* version_present,
+ QuicVersionLabel* version_label,
+ ParsedQuicVersion* parsed_version,
+ QuicConnectionId* destination_connection_id,
+ std::string* detailed_error) {
+ *format = GOOGLE_QUIC_PACKET;
+ *version_present = (*first_byte & PACKET_PUBLIC_FLAGS_VERSION) != 0;
+ uint8_t destination_connection_id_length = 0;
+ if ((*first_byte & PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID) != 0) {
+ destination_connection_id_length = kQuicDefaultConnectionIdLength;
+ }
+ if (!reader->ReadConnectionId(destination_connection_id,
+ destination_connection_id_length)) {
+ *detailed_error = "Unable to read ConnectionId.";
+ return QUIC_INVALID_PACKET_HEADER;
+ }
+ if (*version_present) {
+ if (!ProcessVersionLabel(reader, version_label)) {
+ *detailed_error = "Unable to read protocol version.";
+ return QUIC_INVALID_PACKET_HEADER;
+ }
+ *parsed_version = ParseQuicVersionLabel(*version_label);
+ }
+ return QUIC_NO_ERROR;
+}
+
+namespace {
+
+inline bool PacketHasLengthPrefixedConnectionIds(
+ const QuicDataReader& reader,
+ ParsedQuicVersion parsed_version,
+ QuicVersionLabel version_label,
+ uint8_t first_byte) {
+ if (parsed_version.transport_version != QUIC_VERSION_UNSUPPORTED) {
+ return parsed_version.HasLengthPrefixedConnectionIds();
+ }
+
+ // Received unsupported version, check known old unsupported versions.
+ if (QuicVersionLabelUses4BitConnectionIdLength(version_label)) {
+ return false;
+ }
+
+ // Received unknown version, check connection ID length byte.
+ if (reader.IsDoneReading()) {
+ // This check is required to safely peek the connection ID length byte.
+ return true;
+ }
+ const uint8_t connection_id_length_byte = reader.PeekByte();
+
+ // Check for packets produced by older versions of
+ // QuicFramer::WriteClientVersionNegotiationProbePacket
+ if (first_byte == 0xc0 && (connection_id_length_byte & 0x0f) == 0 &&
+ connection_id_length_byte >= 0x50 && version_label == 0xcabadaba) {
+ return false;
+ }
+
+ // Check for munged packets with version tag PROX.
+ if ((connection_id_length_byte & 0x0f) == 0 &&
+ connection_id_length_byte >= 0x20 && version_label == 0x50524F58) {
+ return false;
+ }
+
+ return true;
+}
+
+inline bool ParseLongHeaderConnectionIds(
+ QuicDataReader* reader,
+ bool has_length_prefix,
+ QuicConnectionId* destination_connection_id,
+ QuicConnectionId* source_connection_id,
+ std::string* detailed_error) {
+ if (has_length_prefix) {
+ if (!reader->ReadLengthPrefixedConnectionId(destination_connection_id)) {
+ *detailed_error = "Unable to read destination connection ID.";
+ return false;
+ }
+ if (!reader->ReadLengthPrefixedConnectionId(source_connection_id)) {
+ *detailed_error = "Unable to read source connection ID.";
+ return false;
+ }
+ } else {
+ // Parse connection ID lengths.
+ uint8_t connection_id_lengths_byte;
+ if (!reader->ReadUInt8(&connection_id_lengths_byte)) {
+ *detailed_error = "Unable to read connection ID lengths.";
+ return false;
+ }
+ uint8_t destination_connection_id_length =
+ (connection_id_lengths_byte & kDestinationConnectionIdLengthMask) >> 4;
+ if (destination_connection_id_length != 0) {
+ destination_connection_id_length += kConnectionIdLengthAdjustment;
+ }
+ uint8_t source_connection_id_length =
+ connection_id_lengths_byte & kSourceConnectionIdLengthMask;
+ if (source_connection_id_length != 0) {
+ source_connection_id_length += kConnectionIdLengthAdjustment;
+ }
+
+ // Read destination connection ID.
+ if (!reader->ReadConnectionId(destination_connection_id,
+ destination_connection_id_length)) {
+ *detailed_error = "Unable to read destination connection ID.";
+ return false;
+ }
+
+ // Read source connection ID.
+ if (!reader->ReadConnectionId(source_connection_id,
+ source_connection_id_length)) {
+ *detailed_error = "Unable to read source connection ID.";
+ return false;
+ }
+ }
+ return true;
+}
+
+} // namespace
+
+// static
+QuicErrorCode QuicFramer::ParsePublicHeader(
+ QuicDataReader* reader,
+ uint8_t expected_destination_connection_id_length,
+ bool ietf_format,
+ uint8_t* first_byte,
+ PacketHeaderFormat* format,
+ bool* version_present,
+ bool* has_length_prefix,
+ QuicVersionLabel* version_label,
+ ParsedQuicVersion* parsed_version,
+ QuicConnectionId* destination_connection_id,
+ QuicConnectionId* source_connection_id,
+ QuicLongHeaderType* long_packet_type,
+ QuicVariableLengthIntegerLength* retry_token_length_length,
+ QuicStringPiece* retry_token,
+ std::string* detailed_error) {
+ *version_present = false;
+ *has_length_prefix = false;
+ *version_label = 0;
+ *parsed_version = UnsupportedQuicVersion();
+ *source_connection_id = EmptyQuicConnectionId();
+ *long_packet_type = INVALID_PACKET_TYPE;
+ *retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_0;
+ *retry_token = QuicStringPiece();
+ *detailed_error = "";
+
+ if (!reader->ReadUInt8(first_byte)) {
+ *detailed_error = "Unable to read first byte.";
+ return QUIC_INVALID_PACKET_HEADER;
+ }
+
+ if (!ietf_format) {
+ return ParsePublicHeaderGoogleQuic(
+ reader, first_byte, format, version_present, version_label,
+ parsed_version, destination_connection_id, detailed_error);
+ }
+
+ *format = GetIetfPacketHeaderFormat(*first_byte);
+
+ if (*format == IETF_QUIC_SHORT_HEADER_PACKET) {
+ // Read destination connection ID using
+ // expected_destination_connection_id_length to determine its length.
+ if (!reader->ReadConnectionId(destination_connection_id,
+ expected_destination_connection_id_length)) {
+ *detailed_error = "Unable to read destination connection ID.";
+ return QUIC_INVALID_PACKET_HEADER;
+ }
+ return QUIC_NO_ERROR;
+ }
+
+ DCHECK_EQ(IETF_QUIC_LONG_HEADER_PACKET, *format);
+ *version_present = true;
+ if (!ProcessVersionLabel(reader, version_label)) {
+ *detailed_error = "Unable to read protocol version.";
+ return QUIC_INVALID_PACKET_HEADER;
+ }
+
+ if (*version_label == 0) {
+ *long_packet_type = VERSION_NEGOTIATION;
+ }
+
+ // Parse version.
+ *parsed_version = ParseQuicVersionLabel(*version_label);
+
+ // Figure out which IETF QUIC invariants this packet follows.
+ *has_length_prefix = PacketHasLengthPrefixedConnectionIds(
+ *reader, *parsed_version, *version_label, *first_byte);
+
+ // Parse connection IDs.
+ if (!ParseLongHeaderConnectionIds(reader, *has_length_prefix,
+ destination_connection_id,
+ source_connection_id, detailed_error)) {
+ return QUIC_INVALID_PACKET_HEADER;
+ }
+
+ if (parsed_version->transport_version == QUIC_VERSION_UNSUPPORTED) {
+ // Skip parsing of long packet type and retry token for unknown versions.
+ return QUIC_NO_ERROR;
+ }
+
+ // Parse long packet type.
+ if (!GetLongHeaderType(*first_byte, long_packet_type)) {
+ *detailed_error = "Unable to parse long packet type.";
+ return QUIC_INVALID_PACKET_HEADER;
+ }
+
+ if (!parsed_version->SupportsRetry() || *long_packet_type != INITIAL) {
+ // Retry token is only present on initial packets for some versions.
+ return QUIC_NO_ERROR;
+ }
+
+ *retry_token_length_length = reader->PeekVarInt62Length();
+ uint64_t retry_token_length;
+ if (!reader->ReadVarInt62(&retry_token_length)) {
+ *retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_0;
+ *detailed_error = "Unable to read retry token length.";
+ return QUIC_INVALID_PACKET_HEADER;
+ }
+
+ if (!reader->ReadStringPiece(retry_token, retry_token_length)) {
+ *detailed_error = "Unable to read retry token.";
+ return QUIC_INVALID_PACKET_HEADER;
+ }
+
+ return QUIC_NO_ERROR;
+}
+
+// static
bool QuicFramer::WriteClientVersionNegotiationProbePacket(
char* packet_bytes,
QuicByteCount packet_length,
@@ -6294,20 +6582,23 @@ bool QuicFramer::WriteClientVersionNegotiationProbePacket(
QUIC_BUG << "Invalid packet_length";
return false;
}
- if (destination_connection_id_length > kQuicMaxConnectionIdLength ||
+ if (destination_connection_id_length > kQuicMaxConnectionId4BitLength ||
destination_connection_id_length <
kQuicMinimumInitialConnectionIdLength) {
QUIC_BUG << "Invalid connection_id_length";
return false;
}
+ const bool use_length_prefix =
+ GetQuicFlag(FLAGS_quic_prober_uses_length_prefixed_connection_ids);
+ const uint8_t last_version_byte = use_length_prefix ? 0xda : 0xba;
// clang-format off
- static const unsigned char packet_start_bytes[] = {
+ const unsigned char packet_start_bytes[] = {
// IETF long header with fixed bit set, type initial, all-0 encrypted bits.
0xc0,
// Version, part of the IETF space reserved for negotiation.
// This intentionally differs from QuicVersionReservedForNegotiation()
// to allow differentiating them over the wire.
- 0xca, 0xba, 0xda, 0xba,
+ 0xca, 0xba, 0xda, last_version_byte,
};
// clang-format on
static_assert(sizeof(packet_start_bytes) == 5, "bad packet_start_bytes size");
@@ -6319,8 +6610,9 @@ bool QuicFramer::WriteClientVersionNegotiationProbePacket(
QuicConnectionId destination_connection_id(destination_connection_id_bytes,
destination_connection_id_length);
- if (!AppendIetfConnectionIds(/*version_flag=*/true, destination_connection_id,
- EmptyQuicConnectionId(), &writer)) {
+ if (!AppendIetfConnectionIds(
+ /*version_flag=*/true, use_length_prefix, destination_connection_id,
+ EmptyQuicConnectionId(), &writer)) {
QUIC_BUG << "Failed to write connection IDs";
return false;
}
@@ -6404,38 +6696,101 @@ bool QuicFramer::ParseServerVersionNegotiationProbeResponse(
*detailed_error = "Packet is not a version negotiation packet";
return false;
}
- uint8_t expected_server_connection_id_length = 0,
- destination_connection_id_length = 0, source_connection_id_length = 0;
- if (!ProcessAndValidateIetfConnectionIdLength(
- &reader, UnsupportedQuicVersion(), Perspective::IS_CLIENT,
- /*should_update_expected_server_connection_id_length=*/true,
- &expected_server_connection_id_length,
- &destination_connection_id_length, &source_connection_id_length,
- detailed_error)) {
- return false;
+ const bool use_length_prefix =
+ GetQuicFlag(FLAGS_quic_prober_uses_length_prefixed_connection_ids);
+ QuicConnectionId destination_connection_id, source_connection_id;
+ if (use_length_prefix) {
+ if (!reader.ReadLengthPrefixedConnectionId(&destination_connection_id)) {
+ *detailed_error = "Failed to read destination connection ID";
+ return false;
+ }
+ if (!reader.ReadLengthPrefixedConnectionId(&source_connection_id)) {
+ *detailed_error = "Failed to read source connection ID";
+ return false;
+ }
+ } else {
+ uint8_t expected_server_connection_id_length = 0,
+ destination_connection_id_length = 0,
+ source_connection_id_length = 0;
+ if (!ProcessAndValidateIetfConnectionIdLength(
+ &reader, UnsupportedQuicVersion(), Perspective::IS_CLIENT,
+ /*should_update_expected_server_connection_id_length=*/true,
+ &expected_server_connection_id_length,
+ &destination_connection_id_length, &source_connection_id_length,
+ detailed_error)) {
+ return false;
+ }
+ if (!reader.ReadConnectionId(&destination_connection_id,
+ destination_connection_id_length)) {
+ *detailed_error = "Failed to read destination connection ID";
+ return false;
+ }
+ if (!reader.ReadConnectionId(&source_connection_id,
+ source_connection_id_length)) {
+ *detailed_error = "Failed to read source connection ID";
+ return false;
+ }
}
- if (destination_connection_id_length != 0) {
+
+ if (destination_connection_id.length() != 0) {
*detailed_error = "Received unexpected destination connection ID length";
return false;
}
- QuicConnectionId destination_connection_id, source_connection_id;
- if (!reader.ReadConnectionId(&destination_connection_id,
- destination_connection_id_length)) {
- *detailed_error = "Failed to read destination connection ID";
- return false;
- }
- if (!reader.ReadConnectionId(&source_connection_id,
- source_connection_id_length)) {
- *detailed_error = "Failed to read source connection ID";
- return false;
+
+ if (!use_length_prefix && source_connection_id.length() == 0) {
+ // We received a bad response due to b/139330014.
+ // Reparse the packet assuming length prefixes.
+ // This is a temporary client-side workaround until cl/263172621 is
+ // deployed on production servers.
+ // TODO(dschinazi): remove this client-side workaround once the server-side
+ // fix is deployed.
+ QuicDataReader reader2(packet_bytes, packet_length);
+ uint8_t type_byte2 = 0;
+ uint32_t version2 = 0;
+ QuicConnectionId destination_connection_id2, source_connection_id2;
+ if (reader2.ReadUInt8(&type_byte2) && reader2.ReadUInt32(&version2) &&
+ reader2.ReadLengthPrefixedConnectionId(&destination_connection_id2) &&
+ reader2.ReadLengthPrefixedConnectionId(&source_connection_id2) &&
+ (type_byte2 & 0x80) != 0 && version2 == 0 &&
+ destination_connection_id2.length() == 0 &&
+ source_connection_id2.length() != 0) {
+ source_connection_id = source_connection_id2;
+ }
}
memcpy(source_connection_id_bytes, source_connection_id.data(),
- source_connection_id_length);
- *source_connection_id_length_out = source_connection_id_length;
+ source_connection_id.length());
+ *source_connection_id_length_out = source_connection_id.length();
return true;
}
+// Look for and parse the error code from the "<quic_error_code>:" text that
+// may be present at the start of the CONNECTION_CLOSE error details string.
+// This text, inserted by the peer if it's using Google's QUIC implementation,
+// contains additional error information that narrows down the exact error. If
+// the string is not found, or is not properly formed, it returns
+// ErrorCode::QUIC_IETF_GQUIC_ERROR_MISSING
+void MaybeExtractQuicErrorCode(QuicConnectionCloseFrame* frame) {
+ std::vector<QuicStringPiece> ed =
+ QuicTextUtils::Split(frame->error_details, ':');
+ uint64_t extracted_error_code;
+ if (ed.size() < 2 || !QuicTextUtils::IsAllDigits(ed[0]) ||
+ !QuicTextUtils::StringToUint64(ed[0], &extracted_error_code)) {
+ frame->extracted_error_code = QUIC_IETF_GQUIC_ERROR_MISSING;
+ return;
+ }
+ // Return the error code (numeric) and the error details string without the
+ // error code prefix. Note that Split returns everything up to, but not
+ // including, the split character, so the length of ed[0] is just the number
+ // of digits in the error number. In removing the prefix, 1 is added to the
+ // length to account for the :
+ QuicStringPiece x = QuicStringPiece(frame->error_details);
+ x.remove_prefix(ed[0].length() + 1);
+ frame->error_details = std::string(x);
+ frame->extracted_error_code =
+ static_cast<QuicErrorCode>(extracted_error_code);
+}
+
#undef ENDPOINT // undef for jumbo builds
} // namespace quic
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 2349a772257..f429a83d5d6 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
@@ -15,6 +15,7 @@
#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h"
#include "net/third_party/quiche/src/quic/core/quic_connection_id.h"
#include "net/third_party/quiche/src/quic/core/quic_packets.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
@@ -127,6 +128,13 @@ class QUIC_EXPORT_PRIVATE QuicFramerVisitorInterface {
// own its internal buffer, the visitor should make a copy of it.
virtual void OnCoalescedPacket(const QuicEncryptedPacket& packet) = 0;
+ // Called when the packet being processed failed to decrypt.
+ // |has_decryption_key| indicates whether the framer knew which decryption
+ // key to use for this packet and already had a suitable key.
+ virtual void OnUndecryptablePacket(const QuicEncryptedPacket& packet,
+ EncryptionLevel decryption_level,
+ bool has_decryption_key) = 0;
+
// Called when a StreamFrame has been parsed.
virtual bool OnStreamFrame(const QuicStreamFrame& frame) = 0;
@@ -387,6 +395,43 @@ class QUIC_EXPORT_PRIVATE QuicFramer {
QuicConnectionId* source_connection_id,
std::string* detailed_error);
+ // Parses the unencryoted fields in a QUIC header using |reader| as input,
+ // stores the result in the other parameters.
+ // |expected_destination_connection_id_length| is only used for short headers.
+ static QuicErrorCode ParsePublicHeader(
+ QuicDataReader* reader,
+ uint8_t expected_destination_connection_id_length,
+ bool ietf_format,
+ uint8_t* first_byte,
+ PacketHeaderFormat* format,
+ bool* version_present,
+ bool* has_length_prefix,
+ QuicVersionLabel* version_label,
+ ParsedQuicVersion* parsed_version,
+ QuicConnectionId* destination_connection_id,
+ QuicConnectionId* source_connection_id,
+ QuicLongHeaderType* long_packet_type,
+ QuicVariableLengthIntegerLength* retry_token_length_length,
+ QuicStringPiece* retry_token,
+ std::string* detailed_error);
+
+ // Parses the unencryoted fields in |packet| and stores them in the other
+ // parameters. This can only be called on the server.
+ // |expected_destination_connection_id_length| is only used for short headers.
+ static QuicErrorCode ParsePublicHeaderDispatcher(
+ const QuicEncryptedPacket& packet,
+ uint8_t expected_destination_connection_id_length,
+ PacketHeaderFormat* format,
+ bool* version_present,
+ bool* has_length_prefix,
+ QuicVersionLabel* version_label,
+ ParsedQuicVersion* parsed_version,
+ QuicConnectionId* destination_connection_id,
+ QuicConnectionId* source_connection_id,
+ bool* retry_token_present,
+ QuicStringPiece* retry_token,
+ std::string* detailed_error);
+
// Serializes a packet containing |frames| into |buffer|.
// Returns the length of the packet, which must not be longer than
// |packet_length|. Returns 0 if it fails to serialize.
@@ -437,10 +482,12 @@ class QUIC_EXPORT_PRIVATE QuicFramer {
QuicConnectionId server_connection_id,
QuicConnectionId client_connection_id,
bool ietf_quic,
+ bool use_length_prefix,
const ParsedQuicVersionVector& versions);
// Returns a new IETF version negotiation packet.
static std::unique_ptr<QuicEncryptedPacket> BuildIetfVersionNegotiationPacket(
+ bool use_length_prefix,
QuicConnectionId server_connection_id,
QuicConnectionId client_connection_id,
const ParsedQuicVersionVector& versions);
@@ -563,6 +610,10 @@ class QUIC_EXPORT_PRIVATE QuicFramer {
return first_sending_packet_number_;
}
+ uint64_t current_received_frame_type() const {
+ return current_received_frame_type_;
+ }
+
// The connection ID length the framer expects on incoming IETF short headers
// on the server.
uint8_t GetExpectedServerConnectionIdLength() {
@@ -611,6 +662,18 @@ class QUIC_EXPORT_PRIVATE QuicFramer {
uint8_t* source_connection_id_length_out,
std::string* detailed_error);
+ void set_local_ack_delay_exponent(uint32_t exponent) {
+ local_ack_delay_exponent_ = exponent;
+ }
+ uint32_t local_ack_delay_exponent() const {
+ return local_ack_delay_exponent_;
+ }
+
+ void set_peer_ack_delay_exponent(uint32_t exponent) {
+ peer_ack_delay_exponent_ = exponent;
+ }
+ uint32_t peer_ack_delay_exponent() const { return peer_ack_delay_exponent_; }
+
private:
friend class test::QuicFramerPeer;
@@ -678,9 +741,6 @@ class QUIC_EXPORT_PRIVATE QuicFramer {
bool ProcessRetryPacket(QuicDataReader* reader,
const QuicPacketHeader& header);
- bool MaybeProcessIetfInitialRetryToken(QuicDataReader* encrypted_reader,
- QuicPacketHeader* header);
-
void MaybeProcessCoalescedPacket(const QuicDataReader& encrypted_reader,
uint64_t remaining_bytes_length,
const QuicPacketHeader& header);
@@ -816,6 +876,18 @@ class QUIC_EXPORT_PRIVATE QuicFramer {
static AckFrameInfo GetAckFrameInfo(const QuicAckFrame& frame);
+ static QuicErrorCode ParsePublicHeaderGoogleQuic(
+ QuicDataReader* reader,
+ uint8_t* first_byte,
+ PacketHeaderFormat* format,
+ bool* version_present,
+ QuicVersionLabel* version_label,
+ ParsedQuicVersion* parsed_version,
+ QuicConnectionId* destination_connection_id,
+ std::string* detailed_error);
+
+ bool ValidateReceivedConnectionIds(const QuicPacketHeader& header);
+
// The Append* methods attempt to write the provided header or frame using the
// |writer|, and return true if successful.
@@ -945,6 +1017,7 @@ class QUIC_EXPORT_PRIVATE QuicFramer {
void set_error(QuicErrorCode error) { error_ = error; }
void set_detailed_error(const char* error) { detailed_error_ = error; }
+ void set_detailed_error(std::string error) { detailed_error_ = error; }
std::string detailed_error_;
QuicFramerVisitorInterface* visitor_;
@@ -1020,8 +1093,34 @@ class QUIC_EXPORT_PRIVATE QuicFramer {
// The length in bytes of the last packet number written to an IETF-framed
// packet.
size_t last_written_packet_number_length_;
+
+ // The amount to shift the ack timestamp in ACK frames. The default is 3.
+ // Local_ is the amount this node shifts timestamps in ACK frames it
+ // generates. it is sent to the peer in a transport parameter negotiation.
+ // Peer_ is the amount the peer shifts timestamps when it sends ACK frames to
+ // this node. This node "unshifts" by this amount. The value is received from
+ // the peer in the transport parameter negotiation. IETF QUIC only.
+ uint32_t peer_ack_delay_exponent_;
+ uint32_t local_ack_delay_exponent_;
+
+ // The type of received IETF frame currently being processed. 0 when not
+ // processing a frame or when processing Google QUIC frames. Used to populate
+ // the Transport Connection Close when there is an error during frame
+ // processing.
+ uint64_t current_received_frame_type_;
};
+// Look for and parse the error code from the "<quic_error_code>:" text that
+// may be present at the start of the CONNECTION_CLOSE error details string.
+// This text, inserted by the peer if it's using Google's QUIC implementation,
+// contains additional error information that narrows down the exact error. The
+// extracted error code and (possibly updated) error_details string are returned
+// in |*frame|. If an error code is not found in the error details then the
+// extracted_error_code is set to QuicErrorCode::QUIC_IETF_GQUIC_ERROR_MISSING.
+// If there is an error code in the string then it is removed from the string.
+QUIC_EXPORT_PRIVATE void MaybeExtractQuicErrorCode(
+ QuicConnectionCloseFrame* frame);
+
} // namespace quic
#endif // QUICHE_QUIC_CORE_QUIC_FRAMER_H_
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 d73c4127267..b13f7e18b2d 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
@@ -20,6 +20,7 @@
#include "net/third_party/quiche/src/quic/core/quic_packets.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/core/quic_utils.h"
+#include "net/third_party/quiche/src/quic/core/quic_versions.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
@@ -196,12 +197,14 @@ class TestQuicVisitor : public QuicFramerVisitorInterface {
void OnPublicResetPacket(const QuicPublicResetPacket& packet) override {
public_reset_packet_ = QuicMakeUnique<QuicPublicResetPacket>((packet));
+ EXPECT_EQ(0u, framer_->current_received_frame_type());
}
void OnVersionNegotiationPacket(
const QuicVersionNegotiationPacket& packet) override {
version_negotiation_packet_ =
QuicMakeUnique<QuicVersionNegotiationPacket>((packet));
+ EXPECT_EQ(0u, framer_->current_received_frame_type());
}
void OnRetryPacket(QuicConnectionId original_connection_id,
@@ -212,39 +215,49 @@ class TestQuicVisitor : public QuicFramerVisitorInterface {
retry_new_connection_id_ =
QuicMakeUnique<QuicConnectionId>(new_connection_id);
retry_token_ = QuicMakeUnique<std::string>(std::string(retry_token));
+ EXPECT_EQ(0u, framer_->current_received_frame_type());
}
bool OnProtocolVersionMismatch(ParsedQuicVersion received_version) override {
QUIC_DLOG(INFO) << "QuicFramer Version Mismatch, version: "
<< received_version;
++version_mismatch_;
- return true;
+ EXPECT_EQ(0u, framer_->current_received_frame_type());
+ return false;
}
bool OnUnauthenticatedPublicHeader(const QuicPacketHeader& header) override {
header_ = QuicMakeUnique<QuicPacketHeader>((header));
+ EXPECT_EQ(0u, framer_->current_received_frame_type());
return accept_public_header_;
}
bool OnUnauthenticatedHeader(const QuicPacketHeader& /*header*/) override {
+ EXPECT_EQ(0u, framer_->current_received_frame_type());
return true;
}
- void OnDecryptedPacket(EncryptionLevel /*level*/) override {}
+ void OnDecryptedPacket(EncryptionLevel /*level*/) override {
+ EXPECT_EQ(0u, framer_->current_received_frame_type());
+ }
bool OnPacketHeader(const QuicPacketHeader& header) override {
++packet_count_;
header_ = QuicMakeUnique<QuicPacketHeader>((header));
+ EXPECT_EQ(0u, framer_->current_received_frame_type());
return accept_packet_;
}
void OnCoalescedPacket(const QuicEncryptedPacket& packet) override {
- size_t coalesced_data_length = packet.length();
- char* coalesced_data = new char[coalesced_data_length];
- memcpy(coalesced_data, packet.data(), coalesced_data_length);
- coalesced_packets_.push_back(QuicMakeUnique<QuicEncryptedPacket>(
- coalesced_data, coalesced_data_length,
- /*owns_buffer=*/true));
+ coalesced_packets_.push_back(packet.Clone());
+ }
+
+ void OnUndecryptablePacket(const QuicEncryptedPacket& packet,
+ EncryptionLevel decryption_level,
+ bool has_decryption_key) override {
+ undecryptable_packets_.push_back(packet.Clone());
+ undecryptable_decryption_levels_.push_back(decryption_level);
+ undecryptable_has_decryption_keys_.push_back(has_decryption_key);
}
bool OnStreamFrame(const QuicStreamFrame& frame) override {
@@ -255,6 +268,12 @@ class TestQuicVisitor : public QuicFramerVisitorInterface {
stream_data_.push_back(QuicWrapUnique(string_data));
stream_frames_.push_back(QuicMakeUnique<QuicStreamFrame>(
frame.stream_id, frame.fin, frame.offset, *string_data));
+ if (VersionHasIetfQuicFrames(transport_version_)) {
+ // Low order bits of type encode flags, ignore them for this test.
+ EXPECT_TRUE(IS_IETF_STREAM_FRAME(framer_->current_received_frame_type()));
+ } else {
+ EXPECT_EQ(0u, framer_->current_received_frame_type());
+ }
return true;
}
@@ -266,6 +285,11 @@ class TestQuicVisitor : public QuicFramerVisitorInterface {
crypto_data_.push_back(QuicWrapUnique(string_data));
crypto_frames_.push_back(QuicMakeUnique<QuicCryptoFrame>(
ENCRYPTION_INITIAL, frame.offset, *string_data));
+ if (VersionHasIetfQuicFrames(transport_version_)) {
+ EXPECT_EQ(IETF_CRYPTO, framer_->current_received_frame_type());
+ } else {
+ EXPECT_EQ(0u, framer_->current_received_frame_type());
+ }
return true;
}
@@ -276,12 +300,22 @@ class TestQuicVisitor : public QuicFramerVisitorInterface {
ack_frame.largest_acked = largest_acked;
ack_frame.ack_delay_time = ack_delay_time;
ack_frames_.push_back(QuicMakeUnique<QuicAckFrame>(ack_frame));
+ if (VersionHasIetfQuicFrames(transport_version_)) {
+ EXPECT_EQ(IETF_ACK, framer_->current_received_frame_type());
+ } else {
+ EXPECT_EQ(0u, framer_->current_received_frame_type());
+ }
return true;
}
bool OnAckRange(QuicPacketNumber start, QuicPacketNumber end) override {
DCHECK(!ack_frames_.empty());
ack_frames_[ack_frames_.size() - 1]->packets.AddRange(start, end);
+ if (VersionHasIetfQuicFrames(transport_version_)) {
+ EXPECT_EQ(IETF_ACK, framer_->current_received_frame_type());
+ } else {
+ EXPECT_EQ(0u, framer_->current_received_frame_type());
+ }
return true;
}
@@ -289,6 +323,7 @@ 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());
return true;
}
@@ -297,17 +332,28 @@ class TestQuicVisitor : public QuicFramerVisitorInterface {
bool OnStopWaitingFrame(const QuicStopWaitingFrame& frame) override {
++frame_count_;
stop_waiting_frames_.push_back(QuicMakeUnique<QuicStopWaitingFrame>(frame));
+ EXPECT_EQ(0u, framer_->current_received_frame_type());
return true;
}
bool OnPaddingFrame(const QuicPaddingFrame& frame) override {
padding_frames_.push_back(QuicMakeUnique<QuicPaddingFrame>(frame));
+ if (VersionHasIetfQuicFrames(transport_version_)) {
+ EXPECT_EQ(IETF_PADDING, framer_->current_received_frame_type());
+ } else {
+ EXPECT_EQ(0u, framer_->current_received_frame_type());
+ }
return true;
}
bool OnPingFrame(const QuicPingFrame& frame) override {
++frame_count_;
ping_frames_.push_back(QuicMakeUnique<QuicPingFrame>(frame));
+ if (VersionHasIetfQuicFrames(transport_version_)) {
+ EXPECT_EQ(IETF_PING, framer_->current_received_frame_type());
+ } else {
+ EXPECT_EQ(0u, framer_->current_received_frame_type());
+ }
return true;
}
@@ -315,6 +361,14 @@ class TestQuicVisitor : public QuicFramerVisitorInterface {
++frame_count_;
message_frames_.push_back(
QuicMakeUnique<QuicMessageFrame>(frame.data, frame.message_length));
+ if (VersionHasIetfQuicFrames(transport_version_)) {
+ EXPECT_TRUE(IETF_EXTENSION_MESSAGE_NO_LENGTH ==
+ framer_->current_received_frame_type() ||
+ IETF_EXTENSION_MESSAGE ==
+ framer_->current_received_frame_type());
+ } else {
+ EXPECT_EQ(0u, framer_->current_received_frame_type());
+ }
return true;
}
@@ -322,71 +376,128 @@ class TestQuicVisitor : public QuicFramerVisitorInterface {
bool OnRstStreamFrame(const QuicRstStreamFrame& frame) override {
rst_stream_frame_ = frame;
+ if (VersionHasIetfQuicFrames(transport_version_)) {
+ EXPECT_EQ(IETF_RST_STREAM, framer_->current_received_frame_type());
+ } else {
+ EXPECT_EQ(0u, framer_->current_received_frame_type());
+ }
return true;
}
bool OnConnectionCloseFrame(const QuicConnectionCloseFrame& frame) override {
connection_close_frame_ = frame;
+ if (VersionHasIetfQuicFrames(transport_version_)) {
+ EXPECT_NE(GOOGLE_QUIC_CONNECTION_CLOSE, frame.close_type);
+ if (frame.close_type == IETF_QUIC_TRANSPORT_CONNECTION_CLOSE) {
+ EXPECT_EQ(IETF_CONNECTION_CLOSE,
+ framer_->current_received_frame_type());
+ } else {
+ EXPECT_EQ(IETF_APPLICATION_CLOSE,
+ framer_->current_received_frame_type());
+ }
+ } else {
+ EXPECT_EQ(0u, framer_->current_received_frame_type());
+ }
return true;
}
bool OnStopSendingFrame(const QuicStopSendingFrame& frame) override {
stop_sending_frame_ = frame;
+ EXPECT_EQ(IETF_STOP_SENDING, framer_->current_received_frame_type());
+ EXPECT_TRUE(VersionHasIetfQuicFrames(transport_version_));
return true;
}
bool OnPathChallengeFrame(const QuicPathChallengeFrame& frame) override {
path_challenge_frame_ = frame;
+ EXPECT_EQ(IETF_PATH_CHALLENGE, framer_->current_received_frame_type());
+ EXPECT_TRUE(VersionHasIetfQuicFrames(transport_version_));
return true;
}
bool OnPathResponseFrame(const QuicPathResponseFrame& frame) override {
path_response_frame_ = frame;
+ EXPECT_EQ(IETF_PATH_RESPONSE, framer_->current_received_frame_type());
+ EXPECT_TRUE(VersionHasIetfQuicFrames(transport_version_));
return true;
}
bool OnGoAwayFrame(const QuicGoAwayFrame& frame) override {
goaway_frame_ = frame;
+ EXPECT_FALSE(VersionHasIetfQuicFrames(transport_version_));
+ EXPECT_EQ(0u, framer_->current_received_frame_type());
return true;
}
bool OnMaxStreamsFrame(const QuicMaxStreamsFrame& frame) override {
max_streams_frame_ = frame;
+ EXPECT_TRUE(VersionHasIetfQuicFrames(transport_version_));
+ EXPECT_TRUE(IETF_MAX_STREAMS_UNIDIRECTIONAL ==
+ framer_->current_received_frame_type() ||
+ IETF_MAX_STREAMS_BIDIRECTIONAL ==
+ framer_->current_received_frame_type());
return true;
}
bool OnStreamsBlockedFrame(const QuicStreamsBlockedFrame& frame) override {
streams_blocked_frame_ = frame;
+ EXPECT_TRUE(VersionHasIetfQuicFrames(transport_version_));
+ EXPECT_TRUE(IETF_STREAMS_BLOCKED_UNIDIRECTIONAL ==
+ framer_->current_received_frame_type() ||
+ IETF_STREAMS_BLOCKED_BIDIRECTIONAL ==
+ framer_->current_received_frame_type());
return true;
}
bool OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) override {
window_update_frame_ = frame;
+ if (VersionHasIetfQuicFrames(transport_version_)) {
+ EXPECT_TRUE(IETF_MAX_DATA == framer_->current_received_frame_type() ||
+ IETF_MAX_STREAM_DATA ==
+ framer_->current_received_frame_type());
+ } else {
+ EXPECT_EQ(0u, framer_->current_received_frame_type());
+ }
return true;
}
bool OnBlockedFrame(const QuicBlockedFrame& frame) override {
blocked_frame_ = frame;
+ if (VersionHasIetfQuicFrames(transport_version_)) {
+ EXPECT_TRUE(IETF_BLOCKED == framer_->current_received_frame_type() ||
+ IETF_STREAM_BLOCKED ==
+ framer_->current_received_frame_type());
+ } else {
+ EXPECT_EQ(0u, framer_->current_received_frame_type());
+ }
return true;
}
bool OnNewConnectionIdFrame(const QuicNewConnectionIdFrame& frame) override {
new_connection_id_ = frame;
+ EXPECT_EQ(IETF_NEW_CONNECTION_ID, framer_->current_received_frame_type());
+ EXPECT_TRUE(VersionHasIetfQuicFrames(transport_version_));
return true;
}
bool OnRetireConnectionIdFrame(
const QuicRetireConnectionIdFrame& frame) override {
+ EXPECT_EQ(IETF_RETIRE_CONNECTION_ID,
+ framer_->current_received_frame_type());
+ EXPECT_TRUE(VersionHasIetfQuicFrames(transport_version_));
retire_connection_id_ = frame;
return true;
}
bool OnNewTokenFrame(const QuicNewTokenFrame& frame) override {
new_token_ = frame;
+ EXPECT_EQ(IETF_NEW_TOKEN, framer_->current_received_frame_type());
+ EXPECT_TRUE(VersionHasIetfQuicFrames(transport_version_));
return true;
}
bool IsValidStatelessResetToken(QuicUint128 token) const override {
+ EXPECT_EQ(0u, framer_->current_received_frame_type());
return token == kTestStatelessResetToken;
}
@@ -394,6 +505,12 @@ class TestQuicVisitor : public QuicFramerVisitorInterface {
const QuicIetfStatelessResetPacket& packet) override {
stateless_reset_packet_ =
QuicMakeUnique<QuicIetfStatelessResetPacket>(packet);
+ EXPECT_EQ(0u, framer_->current_received_frame_type());
+ }
+
+ void set_framer(QuicFramer* framer) {
+ framer_ = framer;
+ transport_version_ = framer->transport_version();
}
// Counters from the visitor_ callbacks.
@@ -420,6 +537,9 @@ class TestQuicVisitor : public QuicFramerVisitorInterface {
std::vector<std::unique_ptr<QuicPingFrame>> ping_frames_;
std::vector<std::unique_ptr<QuicMessageFrame>> message_frames_;
std::vector<std::unique_ptr<QuicEncryptedPacket>> coalesced_packets_;
+ std::vector<std::unique_ptr<QuicEncryptedPacket>> undecryptable_packets_;
+ std::vector<EncryptionLevel> undecryptable_decryption_levels_;
+ std::vector<bool> undecryptable_has_decryption_keys_;
QuicRstStreamFrame rst_stream_frame_;
QuicConnectionCloseFrame connection_close_frame_;
QuicStopSendingFrame stop_sending_frame_;
@@ -435,6 +555,8 @@ class TestQuicVisitor : public QuicFramerVisitorInterface {
QuicNewTokenFrame new_token_;
std::vector<std::unique_ptr<std::string>> stream_data_;
std::vector<std::unique_ptr<std::string>> crypto_data_;
+ QuicTransportVersion transport_version_;
+ QuicFramer* framer_;
};
// Simple struct for defining a packet's content, and associated
@@ -471,6 +593,7 @@ class QuicFramerTest : public QuicTestWithParam<ParsedQuicVersion> {
framer_.set_visitor(&visitor_);
framer_.InferPacketHeaderTypeFromVersion();
+ visitor_.set_framer(&framer_);
}
void SetDecrypterLevel(EncryptionLevel level) {
@@ -482,21 +605,9 @@ class QuicFramerTest : public QuicTestWithParam<ParsedQuicVersion> {
}
// Helper function to get unsigned char representation of the handshake
- // protocol byte of the current QUIC version number.
- unsigned char GetQuicVersionProtocolByte() {
- return (CreateQuicVersionLabel(version_) >> 24) & 0xff;
- }
-
- // Helper function to get unsigned char representation of digit in the
- // units place of the current QUIC version number.
- unsigned char GetQuicVersionDigitOnes() {
- return CreateQuicVersionLabel(version_) & 0xff;
- }
-
- // Helper function to get unsigned char representation of digit in the
- // tens place of the current QUIC version number.
- unsigned char GetQuicVersionDigitTens() {
- return (CreateQuicVersionLabel(version_) >> 8) & 0xff;
+ // protocol byte at position |pos| of the current QUIC version number.
+ unsigned char GetQuicVersionByte(int pos) {
+ return (CreateQuicVersionLabel(version_) >> 8 * (3 - pos)) & 0xff;
}
bool CheckEncryption(QuicPacketNumber packet_number, QuicPacket* packet) {
@@ -695,9 +806,9 @@ class QuicFramerTest : public QuicTestWithParam<ParsedQuicVersion> {
// testing, and these byte arrays contain the QUIC version. This macro explodes
// the 32-bit version into four bytes in network order. Since it uses methods of
// QuicFramerTest, it is only valid to use this in a QuicFramerTest.
-#define QUIC_VERSION_BYTES \
- GetQuicVersionProtocolByte(), '0', GetQuicVersionDigitTens(), \
- GetQuicVersionDigitOnes()
+#define QUIC_VERSION_BYTES \
+ GetQuicVersionByte(0), GetQuicVersionByte(1), GetQuicVersionByte(2), \
+ GetQuicVersionByte(3)
// Run all framer tests with all supported versions of QUIC.
INSTANTIATE_TEST_SUITE_P(QuicFramerTests,
@@ -830,14 +941,6 @@ TEST_P(QuicFramerTest, LargePacket) {
// private flags
0x00,
};
- unsigned char packet44[kMaxIncomingPacketSize + 1] = {
- // type (short header 4 byte packet number)
- 0x32,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
- 0x78, 0x56, 0x34, 0x12,
- };
unsigned char packet46[kMaxIncomingPacketSize + 1] = {
// type (short header 4 byte packet number)
0x43,
@@ -849,12 +952,9 @@ TEST_P(QuicFramerTest, LargePacket) {
// clang-format on
unsigned char* p = packet;
size_t p_size = QUIC_ARRAYSIZE(packet);
- if (framer_.transport_version() > QUIC_VERSION_44) {
+ if (framer_.transport_version() > QUIC_VERSION_43) {
p = packet46;
p_size = QUIC_ARRAYSIZE(packet46);
- } else if (framer_.transport_version() > QUIC_VERSION_43) {
- p = packet44;
- p_size = QUIC_ARRAYSIZE(packet44);
}
const size_t header_size = GetPacketHeaderSize(
@@ -917,11 +1017,25 @@ TEST_P(QuicFramerTest, PacketHeader) {
QuicConnectionId destination_connection_id, source_connection_id;
QuicVersionLabel version_label;
std::string detailed_error;
- EXPECT_EQ(QUIC_NO_ERROR,
- QuicFramer::ProcessPacketDispatcher(
- *encrypted, kQuicDefaultConnectionIdLength, &format,
- &version_flag, &version_label, &destination_connection_id,
- &source_connection_id, &detailed_error));
+ QuicErrorCode error_code;
+ if (!GetQuicReloadableFlag(quic_use_parse_public_header)) {
+ error_code = QuicFramer::ProcessPacketDispatcher(
+ *encrypted, kQuicDefaultConnectionIdLength, &format, &version_flag,
+ &version_label, &destination_connection_id, &source_connection_id,
+ &detailed_error);
+ } else {
+ bool retry_token_present, use_length_prefix;
+ QuicStringPiece retry_token;
+ ParsedQuicVersion parsed_version = UnsupportedQuicVersion();
+ error_code = QuicFramer::ParsePublicHeaderDispatcher(
+ *encrypted, kQuicDefaultConnectionIdLength, &format, &version_flag,
+ &use_length_prefix, &version_label, &parsed_version,
+ &destination_connection_id, &source_connection_id, &retry_token_present,
+ &retry_token, &detailed_error);
+ EXPECT_FALSE(retry_token_present);
+ EXPECT_FALSE(use_length_prefix);
+ }
+ EXPECT_EQ(QUIC_NO_ERROR, error_code);
EXPECT_EQ(GOOGLE_QUIC_PACKET, format);
EXPECT_FALSE(version_flag);
EXPECT_EQ(kQuicDefaultConnectionIdLength, destination_connection_id.length());
@@ -931,26 +1045,9 @@ TEST_P(QuicFramerTest, PacketHeader) {
TEST_P(QuicFramerTest, LongPacketHeader) {
// clang-format off
- PacketFragments packet44 = {
- // type (long header with packet type INITIAL)
- {"Unable to read type.",
- {0xFF}},
- // version tag
- {"Unable to read protocol version.",
- {QUIC_VERSION_BYTES}},
- // connection_id length
- {"Unable to read ConnectionId length.",
- {0x50}},
- // connection_id
- {"Unable to read Destination ConnectionId.",
- {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
- // packet number
- {"Unable to read packet number.",
- {0x12, 0x34, 0x56, 0x78}},
- };
PacketFragments packet46 = {
// type (long header with packet type INITIAL)
- {"Unable to read type.",
+ {"Unable to read first byte.",
{0xC3}},
// version tag
{"Unable to read protocol version.",
@@ -959,7 +1056,7 @@ TEST_P(QuicFramerTest, LongPacketHeader) {
{"Unable to read ConnectionId length.",
{0x50}},
// connection_id
- {"Unable to read Destination ConnectionId.",
+ {"Unable to read destination connection ID.",
{0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
// packet number
{"Unable to read packet number.",
@@ -972,10 +1069,8 @@ TEST_P(QuicFramerTest, LongPacketHeader) {
return;
}
- PacketFragments& fragments =
- framer_.transport_version() > QUIC_VERSION_44 ? packet46 : packet44;
std::unique_ptr<QuicEncryptedPacket> encrypted(
- AssemblePacketFromFragments(fragments));
+ AssemblePacketFromFragments(packet46));
EXPECT_FALSE(framer_.ProcessPacket(*encrypted));
EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
@@ -986,20 +1081,31 @@ TEST_P(QuicFramerTest, LongPacketHeader) {
EXPECT_TRUE(visitor_.header_->version_flag);
EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number);
- CheckFramingBoundaries(
- framer_.transport_version() > QUIC_VERSION_44 ? packet46 : packet44,
- QUIC_INVALID_PACKET_HEADER);
+ CheckFramingBoundaries(packet46, QUIC_INVALID_PACKET_HEADER);
PacketHeaderFormat format;
bool version_flag;
QuicConnectionId destination_connection_id, source_connection_id;
QuicVersionLabel version_label;
std::string detailed_error;
- EXPECT_EQ(QUIC_NO_ERROR,
- QuicFramer::ProcessPacketDispatcher(
- *encrypted, kQuicDefaultConnectionIdLength, &format,
- &version_flag, &version_label, &destination_connection_id,
- &source_connection_id, &detailed_error));
+ QuicErrorCode error_code;
+ if (!GetQuicReloadableFlag(quic_use_parse_public_header)) {
+ error_code = QuicFramer::ProcessPacketDispatcher(
+ *encrypted, kQuicDefaultConnectionIdLength, &format, &version_flag,
+ &version_label, &destination_connection_id, &source_connection_id,
+ &detailed_error);
+ } else {
+ bool retry_token_present, use_length_prefix;
+ QuicStringPiece retry_token;
+ ParsedQuicVersion parsed_version = UnsupportedQuicVersion();
+ error_code = QuicFramer::ParsePublicHeaderDispatcher(
+ *encrypted, kQuicDefaultConnectionIdLength, &format, &version_flag,
+ &use_length_prefix, &version_label, &parsed_version,
+ &destination_connection_id, &source_connection_id, &retry_token_present,
+ &retry_token, &detailed_error);
+ EXPECT_EQ(retry_token_present, framer_.version().SupportsRetry());
+ EXPECT_FALSE(use_length_prefix);
+ }
EXPECT_EQ(IETF_QUIC_LONG_HEADER_PACKET, format);
EXPECT_TRUE(version_flag);
EXPECT_EQ(kQuicDefaultConnectionIdLength, destination_connection_id.length());
@@ -1012,15 +1118,13 @@ TEST_P(QuicFramerTest, LongPacketHeaderWithBothConnectionIds) {
// This test requires an IETF long header.
return;
}
- SetQuicRestartFlag(quic_do_not_override_connection_id, true);
+ SetQuicReloadableFlag(quic_use_parse_public_header, false);
SetDecrypterLevel(ENCRYPTION_ZERO_RTT);
- const unsigned char type_byte =
- framer_.transport_version() == QUIC_VERSION_44 ? 0xFC : 0xD3;
// clang-format off
unsigned char packet[] = {
// public flags (long header with packet type ZERO_RTT_PROTECTED and
// 4-byte packet number)
- type_byte,
+ 0xD3,
// version
QUIC_VERSION_BYTES,
// connection ID lengths
@@ -1044,11 +1148,24 @@ TEST_P(QuicFramerTest, LongPacketHeaderWithBothConnectionIds) {
QuicConnectionId destination_connection_id, source_connection_id;
QuicVersionLabel version_label = 0;
std::string detailed_error = "";
- EXPECT_EQ(QUIC_NO_ERROR,
- QuicFramer::ProcessPacketDispatcher(
- encrypted, kQuicDefaultConnectionIdLength, &format,
- &version_flag, &version_label, &destination_connection_id,
- &source_connection_id, &detailed_error));
+ QuicErrorCode error_code;
+ if (!GetQuicReloadableFlag(quic_use_parse_public_header)) {
+ error_code = QuicFramer::ProcessPacketDispatcher(
+ encrypted, kQuicDefaultConnectionIdLength, &format, &version_flag,
+ &version_label, &destination_connection_id, &source_connection_id,
+ &detailed_error);
+ } else {
+ bool retry_token_present, use_length_prefix;
+ QuicStringPiece retry_token;
+ ParsedQuicVersion parsed_version = UnsupportedQuicVersion();
+ error_code = QuicFramer::ParsePublicHeaderDispatcher(
+ encrypted, kQuicDefaultConnectionIdLength, &format, &version_flag,
+ &use_length_prefix, &version_label, &parsed_version,
+ &destination_connection_id, &source_connection_id, &retry_token_present,
+ &retry_token, &detailed_error);
+ EXPECT_FALSE(retry_token_present);
+ EXPECT_FALSE(use_length_prefix);
+ }
EXPECT_EQ("", detailed_error);
EXPECT_EQ(IETF_QUIC_LONG_HEADER_PACKET, format);
EXPECT_TRUE(version_flag);
@@ -1056,8 +1173,111 @@ TEST_P(QuicFramerTest, LongPacketHeaderWithBothConnectionIds) {
EXPECT_EQ(FramerTestConnectionIdPlusOne(), source_connection_id);
}
+TEST_P(QuicFramerTest, ParsePublicHeader) {
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (version included, 8-byte connection ID,
+ // 4-byte packet number)
+ 0x29,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // version
+ QUIC_VERSION_BYTES,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78,
+ // padding frame
+ 0x00,
+ };
+ unsigned char packet46[] = {
+ // public flags (long header with packet type HANDSHAKE and
+ // 4-byte packet number)
+ 0xE3,
+ // version
+ QUIC_VERSION_BYTES,
+ // connection ID lengths
+ 0x50,
+ // destination connection ID
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // long header packet length
+ 0x05,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78,
+ // padding frame
+ 0x00,
+ };
+ unsigned char packet99[] = {
+ // public flags (long header with packet type HANDSHAKE and
+ // 4-byte packet number)
+ 0xE3,
+ // version
+ QUIC_VERSION_BYTES,
+ // destination connection ID length
+ 0x08,
+ // destination connection ID
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // source connection ID length
+ 0x00,
+ // long header packet length
+ 0x05,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78,
+ // padding frame
+ 0x00,
+ };
+ // clang-format on
+ unsigned char* p = packet;
+ size_t p_length = QUIC_ARRAYSIZE(packet);
+ if (framer_.transport_version() == QUIC_VERSION_99) {
+ p = packet99;
+ p_length = QUIC_ARRAYSIZE(packet99);
+ } else if (framer_.transport_version() >= QUIC_VERSION_46) {
+ p = packet46;
+ p_length = QUIC_ARRAYSIZE(packet46);
+ }
+
+ uint8_t first_byte = 0x33;
+ PacketHeaderFormat format = GOOGLE_QUIC_PACKET;
+ bool version_present = false, has_length_prefix = false;
+ QuicVersionLabel version_label = 0;
+ ParsedQuicVersion parsed_version = UnsupportedQuicVersion();
+ QuicConnectionId destination_connection_id = EmptyQuicConnectionId(),
+ source_connection_id = EmptyQuicConnectionId();
+ QuicLongHeaderType long_packet_type = INVALID_PACKET_TYPE;
+ QuicVariableLengthIntegerLength retry_token_length_length =
+ VARIABLE_LENGTH_INTEGER_LENGTH_4;
+ QuicStringPiece retry_token;
+ std::string detailed_error = "foobar";
+
+ QuicDataReader reader(AsChars(p), p_length);
+ const QuicErrorCode parse_error = QuicFramer::ParsePublicHeader(
+ &reader, kQuicDefaultConnectionIdLength,
+ /*ietf_format=*/
+ VersionHasIetfInvariantHeader(framer_.transport_version()), &first_byte,
+ &format, &version_present, &has_length_prefix, &version_label,
+ &parsed_version, &destination_connection_id, &source_connection_id,
+ &long_packet_type, &retry_token_length_length, &retry_token,
+ &detailed_error);
+ EXPECT_EQ(QUIC_NO_ERROR, parse_error);
+ EXPECT_EQ("", detailed_error);
+ EXPECT_EQ(p[0], first_byte);
+ EXPECT_TRUE(version_present);
+ EXPECT_EQ(framer_.version().HasLengthPrefixedConnectionIds(),
+ has_length_prefix);
+ EXPECT_EQ(CreateQuicVersionLabel(framer_.version()), version_label);
+ EXPECT_EQ(framer_.version(), parsed_version);
+ EXPECT_EQ(FramerTestConnectionId(), destination_connection_id);
+ EXPECT_EQ(EmptyQuicConnectionId(), source_connection_id);
+ EXPECT_EQ(VARIABLE_LENGTH_INTEGER_LENGTH_0, retry_token_length_length);
+ EXPECT_EQ(QuicStringPiece(), retry_token);
+ if (VersionHasIetfInvariantHeader(framer_.transport_version())) {
+ EXPECT_EQ(IETF_QUIC_LONG_HEADER_PACKET, format);
+ EXPECT_EQ(HANDSHAKE, long_packet_type);
+ } else {
+ EXPECT_EQ(GOOGLE_QUIC_PACKET, format);
+ }
+}
+
TEST_P(QuicFramerTest, ClientConnectionIdFromShortHeaderToClient) {
- SetQuicRestartFlag(quic_do_not_override_connection_id, true);
if (!framer_.version().SupportsClientConnectionIds()) {
return;
}
@@ -1093,7 +1313,6 @@ TEST_P(QuicFramerTest, ClientConnectionIdFromShortHeaderToClient) {
// last serialized client connection ID. This test ensures that this
// mechanism behaves as expected.
TEST_P(QuicFramerTest, ClientConnectionIdFromShortHeaderToServer) {
- SetQuicRestartFlag(quic_do_not_override_connection_id, true);
if (!framer_.version().SupportsClientConnectionIds()) {
return;
}
@@ -1140,19 +1359,9 @@ TEST_P(QuicFramerTest, PacketHeaderWith0ByteConnectionId) {
{0x12, 0x34, 0x56, 0x78}},
};
- PacketFragments packet44 = {
- // type (short header, 4 byte packet number)
- {"Unable to read type.",
- {0x32}},
- // connection_id
- // packet number
- {"Unable to read packet number.",
- {0x12, 0x34, 0x56, 0x78}},
- };
-
PacketFragments packet46 = {
// type (short header, 4 byte packet number)
- {"Unable to read type.",
+ {"Unable to read first byte.",
{0x43}},
// connection_id
// packet number
@@ -1162,7 +1371,7 @@ TEST_P(QuicFramerTest, PacketHeaderWith0ByteConnectionId) {
PacketFragments packet_hp = {
// type (short header, 4 byte packet number)
- {"Unable to read type.",
+ {"Unable to read first byte.",
{0x43}},
// connection_id
// packet number
@@ -1174,21 +1383,14 @@ TEST_P(QuicFramerTest, PacketHeaderWith0ByteConnectionId) {
PacketFragments& fragments =
framer_.version().HasHeaderProtection()
? packet_hp
- : framer_.transport_version() > QUIC_VERSION_44
- ? packet46
- : (framer_.transport_version() > QUIC_VERSION_43 ? packet44
- : packet);
+ : (framer_.transport_version() >= QUIC_VERSION_46 ? packet46
+ : packet);
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
EXPECT_FALSE(framer_.ProcessPacket(*encrypted));
EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
- if (!GetQuicRestartFlag(quic_do_not_override_connection_id)) {
- EXPECT_EQ(FramerTestConnectionId(),
- visitor_.header_->destination_connection_id);
- } else {
- EXPECT_EQ(FramerTestConnectionId(), visitor_.header_->source_connection_id);
- }
+ EXPECT_EQ(FramerTestConnectionId(), visitor_.header_->source_connection_id);
EXPECT_FALSE(visitor_.header_->reset_flag);
EXPECT_FALSE(visitor_.header_->version_flag);
EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number);
@@ -1214,28 +1416,10 @@ TEST_P(QuicFramerTest, PacketHeaderWithVersionFlag) {
{0x12, 0x34, 0x56, 0x78}},
};
- PacketFragments packet44 = {
- // type (long header with packet type ZERO_RTT_PROTECTED)
- {"Unable to read type.",
- {0xFC}},
- // version tag
- {"Unable to read protocol version.",
- {QUIC_VERSION_BYTES}},
- // connection_id length
- {"Unable to read ConnectionId length.",
- {0x50}},
- // connection_id
- {"Unable to read Destination ConnectionId.",
- {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
- // packet number
- {"Unable to read packet number.",
- {0x12, 0x34, 0x56, 0x78}},
- };
-
PacketFragments packet46 = {
// type (long header with packet type ZERO_RTT_PROTECTED and 4 bytes
// packet number)
- {"Unable to read type.",
+ {"Unable to read first byte.",
{0xD3}},
// version tag
{"Unable to read protocol version.",
@@ -1244,7 +1428,7 @@ TEST_P(QuicFramerTest, PacketHeaderWithVersionFlag) {
{"Unable to read ConnectionId length.",
{0x50}},
// connection_id
- {"Unable to read Destination ConnectionId.",
+ {"Unable to read destination connection ID.",
{0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
// packet number
{"Unable to read packet number.",
@@ -1254,17 +1438,20 @@ TEST_P(QuicFramerTest, PacketHeaderWithVersionFlag) {
PacketFragments packet99 = {
// type (long header with packet type ZERO_RTT_PROTECTED and 4 bytes
// packet number)
- {"Unable to read type.",
+ {"Unable to read first byte.",
{0xD3}},
// version tag
{"Unable to read protocol version.",
{QUIC_VERSION_BYTES}},
- // connection_id length
- {"Unable to read ConnectionId length.",
- {0x50}},
- // connection_id
- {"Unable to read Destination ConnectionId.",
+ // destination connection ID length
+ {"Unable to read destination connection ID.",
+ {0x08}},
+ // destination connection ID
+ {"Unable to read destination connection ID.",
{0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
+ // source connection ID length
+ {"Unable to read source connection ID.",
+ {0x00}},
// long header packet length
{"Unable to read long header payload length.",
{0x04}},
@@ -1277,10 +1464,8 @@ TEST_P(QuicFramerTest, PacketHeaderWithVersionFlag) {
PacketFragments& fragments =
framer_.transport_version() == QUIC_VERSION_99
? packet99
- : framer_.transport_version() > QUIC_VERSION_44
- ? packet46
- : (framer_.transport_version() > QUIC_VERSION_43 ? packet44
- : packet);
+ : (framer_.transport_version() >= QUIC_VERSION_46 ? packet46
+ : packet);
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
EXPECT_FALSE(framer_.ProcessPacket(*encrypted));
@@ -1313,24 +1498,12 @@ TEST_P(QuicFramerTest, PacketHeaderWith4BytePacketNumber) {
{0x12, 0x34, 0x56, 0x78}},
};
- PacketFragments packet44 = {
- // type (short header, 4 byte packet number)
- {"Unable to read type.",
- {0x32}},
- // connection_id
- {"Unable to read Destination ConnectionId.",
- {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
- // packet number
- {"Unable to read packet number.",
- {0x12, 0x34, 0x56, 0x78}},
- };
-
PacketFragments packet46 = {
// type (short header, 4 byte packet number)
- {"Unable to read type.",
+ {"Unable to read first byte.",
{0x43}},
// connection_id
- {"Unable to read Destination ConnectionId.",
+ {"Unable to read destination connection ID.",
{0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
// packet number
{"Unable to read packet number.",
@@ -1339,10 +1512,10 @@ TEST_P(QuicFramerTest, PacketHeaderWith4BytePacketNumber) {
PacketFragments packet_hp = {
// type (short header, 4 byte packet number)
- {"Unable to read type.",
+ {"Unable to read first byte.",
{0x43}},
// connection_id
- {"Unable to read Destination ConnectionId.",
+ {"Unable to read destination connection ID.",
{0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
// packet number
{"",
@@ -1353,10 +1526,8 @@ TEST_P(QuicFramerTest, PacketHeaderWith4BytePacketNumber) {
PacketFragments& fragments =
framer_.version().HasHeaderProtection()
? packet_hp
- : framer_.transport_version() > QUIC_VERSION_44
- ? packet46
- : (framer_.transport_version() > QUIC_VERSION_43 ? packet44
- : packet);
+ : (framer_.transport_version() >= QUIC_VERSION_46 ? packet46
+ : packet);
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
EXPECT_FALSE(framer_.ProcessPacket(*encrypted));
@@ -1388,24 +1559,12 @@ TEST_P(QuicFramerTest, PacketHeaderWith2BytePacketNumber) {
{0x56, 0x78}},
};
- PacketFragments packet44 = {
- // type (short header, 2 byte packet number)
- {"Unable to read type.",
- {0x31}},
- // connection_id
- {"Unable to read Destination ConnectionId.",
- {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
- // packet number
- {"Unable to read packet number.",
- {0x56, 0x78}},
- };
-
PacketFragments packet46 = {
// type (short header, 2 byte packet number)
- {"Unable to read type.",
+ {"Unable to read first byte.",
{0x41}},
// connection_id
- {"Unable to read Destination ConnectionId.",
+ {"Unable to read destination connection ID.",
{0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
// packet number
{"Unable to read packet number.",
@@ -1414,10 +1573,10 @@ TEST_P(QuicFramerTest, PacketHeaderWith2BytePacketNumber) {
PacketFragments packet_hp = {
// type (short header, 2 byte packet number)
- {"Unable to read type.",
+ {"Unable to read first byte.",
{0x41}},
// connection_id
- {"Unable to read Destination ConnectionId.",
+ {"Unable to read destination connection ID.",
{0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
// packet number
{"",
@@ -1430,10 +1589,8 @@ TEST_P(QuicFramerTest, PacketHeaderWith2BytePacketNumber) {
PacketFragments& fragments =
framer_.version().HasHeaderProtection()
? packet_hp
- : (framer_.transport_version() > QUIC_VERSION_44
- ? packet46
- : (framer_.transport_version() > QUIC_VERSION_43 ? packet44
- : packet));
+ : (framer_.transport_version() >= QUIC_VERSION_46 ? packet46
+ : packet);
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
if (framer_.version().HasHeaderProtection()) {
@@ -1471,24 +1628,12 @@ TEST_P(QuicFramerTest, PacketHeaderWith1BytePacketNumber) {
{0x78}},
};
- PacketFragments packet44 = {
- // type (8 byte connection_id and 1 byte packet number)
- {"Unable to read type.",
- {0x30}},
- // connection_id
- {"Unable to read Destination ConnectionId.",
- {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
- // packet number
- {"Unable to read packet number.",
- {0x78}},
- };
-
PacketFragments packet46 = {
// type (8 byte connection_id and 1 byte packet number)
- {"Unable to read type.",
+ {"Unable to read first byte.",
{0x40}},
// connection_id
- {"Unable to read Destination ConnectionId.",
+ {"Unable to read destination connection ID.",
{0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
// packet number
{"Unable to read packet number.",
@@ -1497,10 +1642,10 @@ TEST_P(QuicFramerTest, PacketHeaderWith1BytePacketNumber) {
PacketFragments packet_hp = {
// type (8 byte connection_id and 1 byte packet number)
- {"Unable to read type.",
+ {"Unable to read first byte.",
{0x40}},
// connection_id
- {"Unable to read Destination ConnectionId.",
+ {"Unable to read destination connection ID.",
{0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
// packet number
{"",
@@ -1514,10 +1659,8 @@ TEST_P(QuicFramerTest, PacketHeaderWith1BytePacketNumber) {
PacketFragments& fragments =
framer_.version().HasHeaderProtection()
? packet_hp
- : (framer_.transport_version() > QUIC_VERSION_44
- ? packet46
- : (framer_.transport_version() > QUIC_VERSION_43 ? packet44
- : packet));
+ : (framer_.transport_version() >= QUIC_VERSION_46 ? packet46
+ : packet);
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
if (framer_.version().HasHeaderProtection()) {
@@ -1626,28 +1769,6 @@ TEST_P(QuicFramerTest, PacketWithDiversificationNonce) {
0x00, 0x00, 0x00, 0x00
};
- unsigned char packet44[] = {
- // type: Long header with packet type ZERO_RTT_PROTECTED
- 0xFC,
- // version tag
- QUIC_VERSION_BYTES,
- // connection_id length
- 0x05,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
- 0x12, 0x34, 0x56, 0x78,
- // nonce
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
-
- // frame type (padding)
- 0x00,
- 0x00, 0x00, 0x00, 0x00
- };
-
unsigned char packet46[] = {
// type: Long header with packet type ZERO_RTT_PROTECTED and 1 byte packet
// number.
@@ -1677,9 +1798,11 @@ TEST_P(QuicFramerTest, PacketWithDiversificationNonce) {
0xD0,
// version tag
QUIC_VERSION_BYTES,
- // connection_id length
- 0x05,
- // connection_id
+ // destination connection ID length
+ 0x00,
+ // source connection ID length
+ 0x08,
+ // source connection ID
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
// long header packet length
0x26,
@@ -1706,12 +1829,9 @@ TEST_P(QuicFramerTest, PacketWithDiversificationNonce) {
if (framer_.transport_version() == QUIC_VERSION_99) {
p = packet99;
p_size = QUIC_ARRAYSIZE(packet99);
- } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ } else if (framer_.transport_version() >= QUIC_VERSION_46) {
p = packet46;
p_size = QUIC_ARRAYSIZE(packet46);
- } else if (framer_.transport_version() > QUIC_VERSION_43) {
- p = packet44;
- p_size = QUIC_ARRAYSIZE(packet44);
}
QuicEncryptedPacket encrypted(AsChars(p), p_size, false);
@@ -1742,9 +1862,9 @@ TEST_P(QuicFramerTest, LargePublicFlagWithMismatchedVersions) {
0x00, 0x00, 0x00, 0x00
};
- unsigned char packet44[] = {
- // type (long header with packet type ZERO_RTT_PROTECTED)
- 0xFC,
+ unsigned char packet46[] = {
+ // type (long header, ZERO_RTT_PROTECTED, 4-byte packet number)
+ 0xD3,
// version tag
'Q', '0', '0', '0',
// connection_id length
@@ -1759,15 +1879,17 @@ TEST_P(QuicFramerTest, LargePublicFlagWithMismatchedVersions) {
0x00, 0x00, 0x00, 0x00
};
- unsigned char packet45[] = {
+ unsigned char packet99[] = {
// type (long header, ZERO_RTT_PROTECTED, 4-byte packet number)
0xD3,
// version tag
'Q', '0', '0', '0',
- // connection_id length
- 0x50,
- // connection_id
+ // destination connection ID length
+ 0x08,
+ // destination connection ID
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // source connection ID length
+ 0x00,
// packet number
0x12, 0x34, 0x56, 0x78,
@@ -1779,12 +1901,12 @@ TEST_P(QuicFramerTest, LargePublicFlagWithMismatchedVersions) {
unsigned char* p = packet;
size_t p_size = QUIC_ARRAYSIZE(packet);
- if (framer_.transport_version() > QUIC_VERSION_44) {
- p = packet45;
- p_size = QUIC_ARRAYSIZE(packet45);
- } else if (framer_.transport_version() > QUIC_VERSION_43) {
- p = packet44;
- p_size = QUIC_ARRAYSIZE(packet44);
+ if (framer_.transport_version() >= QUIC_VERSION_99) {
+ p = packet99;
+ p_size = QUIC_ARRAYSIZE(packet99);
+ } else if (framer_.transport_version() >= QUIC_VERSION_46) {
+ p = packet46;
+ p_size = QUIC_ARRAYSIZE(packet46);
}
QuicEncryptedPacket encrypted(AsChars(p), p_size, false);
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
@@ -1792,8 +1914,6 @@ TEST_P(QuicFramerTest, LargePublicFlagWithMismatchedVersions) {
ASSERT_TRUE(visitor_.header_.get());
EXPECT_EQ(0, visitor_.frame_count_);
EXPECT_EQ(1, visitor_.version_mismatch_);
- ASSERT_EQ(1u, visitor_.padding_frames_.size());
- EXPECT_EQ(5, visitor_.padding_frames_[0]->num_padding_bytes);
}
TEST_P(QuicFramerTest, PaddingFrame) {
@@ -1826,33 +1946,6 @@ TEST_P(QuicFramerTest, PaddingFrame) {
0x00, 0x00,
};
- unsigned char packet44[] = {
- // type (short header, 4 byte packet number)
- 0x32,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
- 0x12, 0x34, 0x56, 0x78,
-
- // paddings
- 0x00, 0x00,
- // frame type (stream frame with fin)
- 0xFF,
- // stream id
- 0x01, 0x02, 0x03, 0x04,
- // offset
- 0x3A, 0x98, 0xFE, 0xDC,
- 0x32, 0x10, 0x76, 0x54,
- // data length
- 0x00, 0x0c,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!',
- // paddings
- 0x00, 0x00,
- };
-
unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
@@ -1914,12 +2007,9 @@ TEST_P(QuicFramerTest, PaddingFrame) {
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
p = packet99;
p_size = QUIC_ARRAYSIZE(packet99);
- } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ } else if (framer_.transport_version() >= QUIC_VERSION_46) {
p = packet46;
p_size = QUIC_ARRAYSIZE(packet46);
- } else if (framer_.transport_version() > QUIC_VERSION_43) {
- p = packet44;
- p_size = QUIC_ARRAYSIZE(packet44);
}
QuicEncryptedPacket encrypted(AsChars(p), p_size, false);
@@ -1974,36 +2064,6 @@ TEST_P(QuicFramerTest, StreamFrame) {
'r', 'l', 'd', '!'}},
};
- PacketFragments packet44 = {
- // type (short header, 4 byte packet number)
- {"",
- {0x32}},
- // connection_id
- {"",
- {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
- // packet number
- {"",
- {0x12, 0x34, 0x56, 0x78}},
- // frame type (stream frame with fin)
- {"",
- {0xFF}},
- // stream id
- {"Unable to read stream_id.",
- {0x01, 0x02, 0x03, 0x04}},
- // offset
- {"Unable to read offset.",
- {0x3A, 0x98, 0xFE, 0xDC,
- 0x32, 0x10, 0x76, 0x54}},
- {"Unable to read frame data.",
- {
- // data length
- 0x00, 0x0c,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!'}},
- };
-
PacketFragments packet46 = {
// type (short header, 4 byte packet number)
{"",
@@ -2068,10 +2128,8 @@ TEST_P(QuicFramerTest, StreamFrame) {
PacketFragments& fragments =
VersionHasIetfQuicFrames(framer_.transport_version())
? packet99
- : (framer_.transport_version() > QUIC_VERSION_44
- ? packet46
- : (framer_.transport_version() > QUIC_VERSION_43 ? packet44
- : packet));
+ : (framer_.transport_version() >= QUIC_VERSION_46 ? packet46
+ : packet);
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
@@ -2178,21 +2236,6 @@ TEST_P(QuicFramerTest, MissingDiversificationNonce) {
0x00,
};
- unsigned char packet44[] = {
- // type (long header, ZERO_RTT_PROTECTED, 4-byte packet number)
- 0xFC,
- // version tag
- QUIC_VERSION_BYTES,
- // connection_id length
- 0x05,
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0x12, 0x34, 0x56, 0x78,
- // padding frame
- 0x00,
- };
-
unsigned char packet46[] = {
// type (long header, ZERO_RTT_PROTECTED, 4-byte packet number)
0xD3,
@@ -2213,9 +2256,11 @@ TEST_P(QuicFramerTest, MissingDiversificationNonce) {
0xD3,
// version tag
QUIC_VERSION_BYTES,
- // connection_id length
- 0x05,
- // connection_id
+ // destination connection ID length
+ 0x00,
+ // source connection ID length
+ 0x08,
+ // source connection ID
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// IETF long header payload length
0x05,
@@ -2234,16 +2279,13 @@ TEST_P(QuicFramerTest, MissingDiversificationNonce) {
} else if (framer_.transport_version() >= QUIC_VERSION_46) {
p = packet46;
p_length = QUIC_ARRAYSIZE(packet46);
- } else if (framer_.transport_version() >= QUIC_VERSION_44) {
- p = packet44;
- p_length = QUIC_ARRAYSIZE(packet44);
}
QuicEncryptedPacket encrypted(AsChars(p), p_length, false);
EXPECT_FALSE(framer_.ProcessPacket(encrypted));
if (framer_.version().HasHeaderProtection()) {
EXPECT_EQ(QUIC_DECRYPTION_FAILURE, framer_.error());
EXPECT_EQ("Unable to decrypt header protection.", framer_.detailed_error());
- } else if (framer_.transport_version() >= QUIC_VERSION_44) {
+ } else if (framer_.transport_version() >= QUIC_VERSION_46) {
// Cannot read diversification nonce.
EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, framer_.error());
EXPECT_EQ("Unable to read nonce.", framer_.detailed_error());
@@ -2344,36 +2386,6 @@ TEST_P(QuicFramerTest, StreamFrame2ByteStreamId) {
'r', 'l', 'd', '!'}},
};
- PacketFragments packet44 = {
- // type (short header, 4 byte packet number)
- {"",
- {0x32}},
- // connection_id
- {"",
- {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
- // packet number
- {"",
- {0x12, 0x34, 0x56, 0x78}},
- // frame type (stream frame with fin)
- {"",
- {0xFD}},
- // stream id
- {"Unable to read stream_id.",
- {0x03, 0x04}},
- // offset
- {"Unable to read offset.",
- {0x3A, 0x98, 0xFE, 0xDC,
- 0x32, 0x10, 0x76, 0x54}},
- {"Unable to read frame data.",
- {
- // data length
- 0x00, 0x0c,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!'}},
- };
-
PacketFragments packet46 = {
// type (short header, 4 byte packet number)
{"",
@@ -2438,10 +2450,8 @@ TEST_P(QuicFramerTest, StreamFrame2ByteStreamId) {
PacketFragments& fragments =
VersionHasIetfQuicFrames(framer_.transport_version())
? packet99
- : (framer_.transport_version() > QUIC_VERSION_44
- ? packet46
- : (framer_.transport_version() > QUIC_VERSION_43 ? packet44
- : packet));
+ : (framer_.transport_version() >= QUIC_VERSION_46 ? packet46
+ : packet);
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
@@ -2496,36 +2506,6 @@ TEST_P(QuicFramerTest, StreamFrame1ByteStreamId) {
'r', 'l', 'd', '!'}},
};
- PacketFragments packet44 = {
- // type (short header, 4 byte packet number)
- {"",
- {0x32}},
- // connection_id
- {"",
- {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
- // packet number
- {"",
- {0x12, 0x34, 0x56, 0x78}},
- // frame type (stream frame with fin)
- {"",
- {0xFC}},
- // stream id
- {"Unable to read stream_id.",
- {0x04}},
- // offset
- {"Unable to read offset.",
- {0x3A, 0x98, 0xFE, 0xDC,
- 0x32, 0x10, 0x76, 0x54}},
- {"Unable to read frame data.",
- {
- // data length
- 0x00, 0x0c,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!'}},
- };
-
PacketFragments packet46 = {
// type (short header, 4 byte packet number)
{"",
@@ -2590,10 +2570,8 @@ TEST_P(QuicFramerTest, StreamFrame1ByteStreamId) {
PacketFragments& fragments =
VersionHasIetfQuicFrames(framer_.transport_version())
? packet99
- : (framer_.transport_version() > QUIC_VERSION_44
- ? packet46
- : (framer_.transport_version() > QUIC_VERSION_43 ? packet44
- : packet));
+ : (framer_.transport_version() >= QUIC_VERSION_46 ? packet46
+ : packet);
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
@@ -2657,42 +2635,6 @@ TEST_P(QuicFramerTest, StreamFrameWithVersion) {
'r', 'l', 'd', '!'}},
};
- PacketFragments packet44 = {
- // public flags (long header with packet type ZERO_RTT_PROTECTED)
- {"",
- {0xFC}},
- // version tag
- {"",
- {QUIC_VERSION_BYTES}},
- // connection_id length
- {"",
- {0x50}},
- // connection_id
- {"",
- {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
- // packet number
- {"",
- {0x12, 0x34, 0x56, 0x78}},
- // frame type (stream frame with fin)
- {"",
- {0xFE}},
- // stream id
- {"Unable to read stream_id.",
- {0x02, 0x03, 0x04}},
- // offset
- {"Unable to read offset.",
- {0x3A, 0x98, 0xFE, 0xDC,
- 0x32, 0x10, 0x76, 0x54}},
- {"Unable to read frame data.",
- {
- // data length
- 0x00, 0x0c,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!'}},
- };
-
PacketFragments packet46 = {
// public flags (long header with packet type ZERO_RTT_PROTECTED and
// 4-byte packet number)
@@ -2738,12 +2680,15 @@ TEST_P(QuicFramerTest, StreamFrameWithVersion) {
// version tag
{"",
{QUIC_VERSION_BYTES}},
- // connection_id length
+ // destination connection ID length
{"",
- {0x50}},
- // connection_id
+ {0x08}},
+ // destination connection ID
{"",
{0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
+ // source connection ID length
+ {"",
+ {0x00}},
// long header packet length
{"",
{0x1E}},
@@ -2782,10 +2727,8 @@ TEST_P(QuicFramerTest, StreamFrameWithVersion) {
PacketFragments& fragments =
VersionHasIetfQuicFrames(framer_.transport_version())
? packet99
- : (framer_.transport_version() > QUIC_VERSION_44
- ? packet46
- : (framer_.transport_version() > QUIC_VERSION_43 ? packet44
- : packet));
+ : (framer_.transport_version() >= QUIC_VERSION_46 ? packet46
+ : packet);
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
@@ -2839,29 +2782,6 @@ TEST_P(QuicFramerTest, RejectPacket) {
'r', 'l', 'd', '!',
};
- unsigned char packet44[] = {
- // type (short header, 4 byte packet number)
- 0x32,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
- 0x12, 0x34, 0x56, 0x78,
-
- // frame type (STREAM Frame with FIN, LEN, and OFFSET bits set)
- 0x10 | 0x01 | 0x02 | 0x04,
- // stream id
- kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04,
- // offset
- kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC,
- 0x32, 0x10, 0x76, 0x54,
- // data length
- kVarInt62OneByte + 0x0c,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!',
- };
-
unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
@@ -2887,14 +2807,12 @@ TEST_P(QuicFramerTest, RejectPacket) {
// clang-format on
unsigned char* p = packet;
- if (framer_.transport_version() > QUIC_VERSION_44) {
+ if (framer_.transport_version() >= QUIC_VERSION_46) {
p = packet46;
- } else if (framer_.transport_version() > QUIC_VERSION_43) {
- p = packet44;
}
QuicEncryptedPacket encrypted(AsChars(p),
framer_.transport_version() > QUIC_VERSION_43
- ? QUIC_ARRAYSIZE(packet44)
+ ? QUIC_ARRAYSIZE(packet46)
: QUIC_ARRAYSIZE(packet),
false);
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
@@ -2920,15 +2838,6 @@ TEST_P(QuicFramerTest, RejectPublicHeader) {
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
};
- unsigned char packet44[] = {
- // type (short header, 1 byte packet number)
- 0x30,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
- 0x01,
- };
-
unsigned char packet46[] = {
// type (short header, 1 byte packet number)
0x40,
@@ -2940,15 +2849,10 @@ TEST_P(QuicFramerTest, RejectPublicHeader) {
// clang-format on
QuicEncryptedPacket encrypted(
- framer_.transport_version() > QUIC_VERSION_44
- ? AsChars(packet46)
- : (framer_.transport_version() > QUIC_VERSION_43 ? AsChars(packet44)
- : AsChars(packet)),
- framer_.transport_version() > QUIC_VERSION_44
- ? QUIC_ARRAYSIZE(packet46)
- : (framer_.transport_version() > QUIC_VERSION_43
- ? QUIC_ARRAYSIZE(packet44)
- : QUIC_ARRAYSIZE(packet)),
+ framer_.transport_version() >= QUIC_VERSION_46 ? AsChars(packet46)
+ : AsChars(packet),
+ framer_.transport_version() >= QUIC_VERSION_46 ? QUIC_ARRAYSIZE(packet46)
+ : QUIC_ARRAYSIZE(packet),
false);
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
@@ -2988,34 +2892,6 @@ TEST_P(QuicFramerTest, AckFrameOneAckBlock) {
{0x00}}
};
- PacketFragments packet44 = {
- // type (short packet, 4 byte packet number)
- {"",
- {0x32}},
- // connection_id
- {"",
- {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
- // packet number
- {"",
- {0x12, 0x34, 0x56, 0x78}},
- // frame type (ack frame)
- // (one ack block, 2 byte largest observed, 2 byte block length)
- {"",
- {0x45}},
- // largest acked
- {"Unable to read largest acked.",
- {0x12, 0x34}},
- // Zero delta time.
- {"Unable to read ack delay time.",
- {0x00, 0x00}},
- // first ack block length.
- {"Unable to read first ack block length.",
- {0x12, 0x34}},
- // num timestamps.
- {"Unable to read num received packets.",
- {0x00}}
- };
-
PacketFragments packet46 = {
// type (short packet, 4 byte packet number)
{"",
@@ -3083,10 +2959,8 @@ TEST_P(QuicFramerTest, AckFrameOneAckBlock) {
PacketFragments& fragments =
VersionHasIetfQuicFrames(framer_.transport_version())
? packet99
- : (framer_.transport_version() > QUIC_VERSION_44
- ? packet46
- : (framer_.transport_version() > QUIC_VERSION_43 ? packet44
- : packet));
+ : (framer_.transport_version() >= QUIC_VERSION_46 ? packet46
+ : packet);
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
@@ -3140,34 +3014,6 @@ TEST_P(QuicFramerTest, FirstAckFrameUnderflow) {
{0x00}}
};
- PacketFragments packet44 = {
- // type (short header, 4 byte packet number)
- {"",
- {0x32}},
- // connection_id
- {"",
- {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
- // packet number
- {"",
- {0x12, 0x34, 0x56, 0x78}},
- // frame type (ack frame)
- // (one ack block, 2 byte largest observed, 2 byte block length)
- {"",
- {0x45}},
- // largest acked
- {"Unable to read largest acked.",
- {0x12, 0x34}},
- // Zero delta time.
- {"Unable to read ack delay time.",
- {0x00, 0x00}},
- // first ack block length.
- {"Unable to read first ack block length.",
- {0x88, 0x88}},
- // num timestamps.
- {"Underflow with first ack block length 34952 largest acked is 4660.",
- {0x00}}
- };
-
PacketFragments packet46 = {
// type (short header, 4 byte packet number)
{"",
@@ -3227,10 +3073,8 @@ TEST_P(QuicFramerTest, FirstAckFrameUnderflow) {
PacketFragments& fragments =
VersionHasIetfQuicFrames(framer_.transport_version())
? packet99
- : (framer_.transport_version() > QUIC_VERSION_44
- ? packet46
- : (framer_.transport_version() > QUIC_VERSION_43 ? packet44
- : packet));
+ : (framer_.transport_version() >= QUIC_VERSION_46 ? packet46
+ : packet);
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
EXPECT_FALSE(framer_.ProcessPacket(*encrypted));
@@ -3558,44 +3402,6 @@ TEST_P(QuicFramerTest, AckFrameFirstAckBlockLengthZero) {
{ 0x00 }},
};
- PacketFragments packet44 = {
- // type (short header, 4 byte packet number)
- {"",
- { 0x32 }},
- // connection_id
- {"",
- { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 }},
- // packet number
- {"",
- { 0x12, 0x34, 0x56, 0x78 }},
-
- // frame type (ack frame)
- // (more than one ack block, 2 byte largest observed, 2 byte block length)
- {"",
- { 0x65 }},
- // largest acked
- {"Unable to read largest acked.",
- { 0x12, 0x34 }},
- // Zero delta time.
- {"Unable to read ack delay time.",
- { 0x00, 0x00 }},
- // num ack blocks ranges.
- {"Unable to read num of ack blocks.",
- { 0x01 }},
- // first ack block length.
- {"Unable to read first ack block length.",
- { 0x00, 0x00 }},
- // gap to next block.
- { "First block length is zero.",
- { 0x01 }},
- // ack block length.
- { "First block length is zero.",
- { 0x0e, 0xaf }},
- // Number of timestamps.
- { "First block length is zero.",
- { 0x00 }},
- };
-
PacketFragments packet46 = {
// type (short header, 4 byte packet number)
{"",
@@ -3636,9 +3442,7 @@ TEST_P(QuicFramerTest, AckFrameFirstAckBlockLengthZero) {
// clang-format on
PacketFragments& fragments =
- framer_.transport_version() > QUIC_VERSION_44
- ? packet46
- : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 : packet);
+ framer_.transport_version() >= QUIC_VERSION_46 ? packet46 : packet;
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
@@ -3688,34 +3492,6 @@ TEST_P(QuicFramerTest, AckFrameOneAckBlockMaxLength) {
{0x00}}
};
- PacketFragments packet44 = {
- // type (short header, 4 byte packet number)
- {"",
- {0x32}},
- // connection_id
- {"",
- {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
- // packet number
- {"",
- {0x56, 0x78, 0x9A, 0xBC}},
- // frame type (ack frame)
- // (one ack block, 4 byte largest observed, 2 byte block length)
- {"",
- {0x49}},
- // largest acked
- {"Unable to read largest acked.",
- {0x12, 0x34, 0x56, 0x78}},
- // Zero delta time.
- {"Unable to read ack delay time.",
- {0x00, 0x00}},
- // first ack block length.
- {"Unable to read first ack block length.",
- {0x12, 0x34}},
- // num timestamps.
- {"Unable to read num received packets.",
- {0x00}}
- };
-
PacketFragments packet46 = {
// type (short header, 4 byte packet number)
{"",
@@ -3775,10 +3551,8 @@ TEST_P(QuicFramerTest, AckFrameOneAckBlockMaxLength) {
PacketFragments& fragments =
VersionHasIetfQuicFrames(framer_.transport_version())
? packet99
- : (framer_.transport_version() > QUIC_VERSION_44
- ? packet46
- : (framer_.transport_version() > QUIC_VERSION_43 ? packet44
- : packet));
+ : (framer_.transport_version() >= QUIC_VERSION_46 ? packet46
+ : packet);
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
@@ -3871,74 +3645,6 @@ TEST_P(QuicFramerTest, AckFrameTwoTimeStampsMultipleAckBlocks) {
{ 0x32, 0x10 }},
};
- PacketFragments packet44 = {
- // type (short header, 4 byte packet number)
- {"",
- { 0x32 }},
- // connection_id
- {"",
- { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 }},
- // packet number
- {"",
- { 0x12, 0x34, 0x56, 0x78 }},
-
- // frame type (ack frame)
- // (more than one ack block, 2 byte largest observed, 2 byte block length)
- {"",
- { 0x65 }},
- // largest acked
- {"Unable to read largest acked.",
- { 0x12, 0x34 }},
- // Zero delta time.
- {"Unable to read ack delay time.",
- { 0x00, 0x00 }},
- // num ack blocks ranges.
- {"Unable to read num of ack blocks.",
- { 0x04 }},
- // first ack block length.
- {"Unable to read first ack block length.",
- { 0x00, 0x01 }},
- // gap to next block.
- { "Unable to read gap to next ack block.",
- { 0x01 }},
- // ack block length.
- { "Unable to ack block length.",
- { 0x0e, 0xaf }},
- // gap to next block.
- { "Unable to read gap to next ack block.",
- { 0xff }},
- // ack block length.
- { "Unable to ack block length.",
- { 0x00, 0x00 }},
- // gap to next block.
- { "Unable to read gap to next ack block.",
- { 0x91 }},
- // ack block length.
- { "Unable to ack block length.",
- { 0x01, 0xea }},
- // gap to next block.
- { "Unable to read gap to next ack block.",
- { 0x05 }},
- // ack block length.
- { "Unable to ack block length.",
- { 0x00, 0x04 }},
- // Number of timestamps.
- { "Unable to read num received packets.",
- { 0x02 }},
- // Delta from largest observed.
- { "Unable to read sequence delta in received packets.",
- { 0x01 }},
- // Delta time.
- { "Unable to read time delta in received packets.",
- { 0x76, 0x54, 0x32, 0x10 }},
- // Delta from largest observed.
- { "Unable to read sequence delta in received packets.",
- { 0x02 }},
- // Delta time.
- { "Unable to read incremental time delta in received packets.",
- { 0x32, 0x10 }},
- };
-
PacketFragments packet46 = {
// type (short header, 4 byte packet number)
{"",
@@ -4067,10 +3773,8 @@ TEST_P(QuicFramerTest, AckFrameTwoTimeStampsMultipleAckBlocks) {
PacketFragments& fragments =
VersionHasIetfQuicFrames(framer_.transport_version())
? packet99
- : (framer_.transport_version() > QUIC_VERSION_44
- ? packet46
- : (framer_.transport_version() > QUIC_VERSION_43 ? packet44
- : packet));
+ : (framer_.transport_version() >= QUIC_VERSION_46 ? packet46
+ : packet);
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
@@ -4126,31 +3830,6 @@ TEST_P(QuicFramerTest, AckFrameTimeStampDeltaTooHigh) {
0x10, 0x32, 0x54, 0x76,
};
- unsigned char packet44[] = {
- // type (short header, 4 byte packet number)
- 0x32,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
- 0x12, 0x34, 0x56, 0x78,
-
- // frame type (ack frame)
- // (no ack blocks, 1 byte largest observed, 1 byte block length)
- 0x40,
- // largest acked
- 0x01,
- // Zero delta time.
- 0x00, 0x00,
- // first ack block length.
- 0x01,
- // num timestamps.
- 0x01,
- // Delta from largest observed.
- 0x01,
- // Delta time.
- 0x10, 0x32, 0x54, 0x76,
- };
-
unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
@@ -4180,10 +3859,8 @@ TEST_P(QuicFramerTest, AckFrameTimeStampDeltaTooHigh) {
return;
}
QuicEncryptedPacket encrypted(
- AsChars(framer_.transport_version() > QUIC_VERSION_44
- ? packet46
- : (framer_.transport_version() > QUIC_VERSION_43 ? packet44
- : packet)),
+ AsChars(framer_.transport_version() >= QUIC_VERSION_46 ? packet46
+ : packet),
QUIC_ARRAYSIZE(packet), false);
EXPECT_FALSE(framer_.ProcessPacket(encrypted));
EXPECT_TRUE(QuicTextUtils::StartsWith(
@@ -4222,35 +3899,6 @@ TEST_P(QuicFramerTest, AckFrameTimeStampSecondDeltaTooHigh) {
0x10, 0x32,
};
- unsigned char packet44[] = {
- // type (short header, 4 byte packet number)
- 0x32,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
- 0x12, 0x34, 0x56, 0x78,
-
- // frame type (ack frame)
- // (no ack blocks, 1 byte largest observed, 1 byte block length)
- 0x40,
- // largest acked
- 0x03,
- // Zero delta time.
- 0x00, 0x00,
- // first ack block length.
- 0x03,
- // num timestamps.
- 0x02,
- // Delta from largest observed.
- 0x01,
- // Delta time.
- 0x10, 0x32, 0x54, 0x76,
- // Delta from largest observed.
- 0x03,
- // Delta time.
- 0x10, 0x32,
- };
-
unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
@@ -4284,10 +3932,8 @@ TEST_P(QuicFramerTest, AckFrameTimeStampSecondDeltaTooHigh) {
return;
}
QuicEncryptedPacket encrypted(
- AsChars(framer_.transport_version() > QUIC_VERSION_44
- ? packet46
- : (framer_.transport_version() > QUIC_VERSION_43 ? packet44
- : packet)),
+ AsChars(framer_.transport_version() >= QUIC_VERSION_46 ? packet46
+ : packet),
QUIC_ARRAYSIZE(packet), false);
EXPECT_FALSE(framer_.ProcessPacket(encrypted));
EXPECT_TRUE(QuicTextUtils::StartsWith(
@@ -4318,24 +3964,6 @@ TEST_P(QuicFramerTest, NewStopWaitingFrame) {
{0x00, 0x00, 0x00, 0x08}}
};
- PacketFragments packet44 = {
- // type (short header, 4 byte packet number)
- {"",
- {0x32}},
- // connection_id
- {"",
- {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
- // packet number
- {"",
- {0x12, 0x34, 0x56, 0x78}},
- // frame type (stop waiting frame)
- {"",
- {0x06}},
- // least packet number awaiting an ack, delta from packet number.
- {"Unable to read least unacked delta.",
- {0x00, 0x00, 0x00, 0x08}}
- };
-
PacketFragments packet46 = {
// type (short header, 4 byte packet number)
{"",
@@ -4356,14 +3984,12 @@ TEST_P(QuicFramerTest, NewStopWaitingFrame) {
// clang-format on
PacketFragments& fragments =
- framer_.transport_version() > QUIC_VERSION_44
- ? packet46
- : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 : packet);
+ framer_.transport_version() >= QUIC_VERSION_46 ? packet46 : packet;
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
if (GetQuicReloadableFlag(quic_do_not_accept_stop_waiting) &&
- version_.transport_version >= QUIC_VERSION_44) {
+ version_.transport_version >= QUIC_VERSION_46) {
EXPECT_FALSE(framer_.ProcessPacket(*encrypted));
EXPECT_EQ(QUIC_INVALID_STOP_WAITING_DATA, framer_.error());
EXPECT_EQ("STOP WAITING not supported in version 44+.",
@@ -4390,7 +4016,7 @@ TEST_P(QuicFramerTest, NewStopWaitingFrame) {
TEST_P(QuicFramerTest, InvalidNewStopWaitingFrame) {
if (VersionHasIetfQuicFrames(version_.transport_version) ||
(GetQuicReloadableFlag(quic_do_not_accept_stop_waiting) &&
- version_.transport_version >= QUIC_VERSION_44)) {
+ version_.transport_version >= QUIC_VERSION_46)) {
return;
}
SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
@@ -4409,19 +4035,6 @@ TEST_P(QuicFramerTest, InvalidNewStopWaitingFrame) {
0x9A, 0xA8,
};
- unsigned char packet44[] = {
- // type (short header, 4 byte packet number)
- 0x32,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
- 0x12, 0x34, 0x56, 0x78,
- // frame type (stop waiting frame)
- 0x06,
- // least packet number awaiting an ack, delta from packet number.
- 0x57, 0x78, 0x9A, 0xA8,
- };
-
unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
@@ -4437,11 +4050,9 @@ TEST_P(QuicFramerTest, InvalidNewStopWaitingFrame) {
// clang-format on
QuicEncryptedPacket encrypted(
- AsChars(framer_.transport_version() > QUIC_VERSION_44
- ? packet46
- : (framer_.transport_version() > QUIC_VERSION_43 ? packet44
- : packet)),
- framer_.transport_version() > QUIC_VERSION_43 ? QUIC_ARRAYSIZE(packet44)
+ AsChars(framer_.transport_version() >= QUIC_VERSION_46 ? packet46
+ : packet),
+ framer_.transport_version() > QUIC_VERSION_43 ? QUIC_ARRAYSIZE(packet46)
: QUIC_ARRAYSIZE(packet),
false);
EXPECT_FALSE(framer_.ProcessPacket(encrypted));
@@ -4477,31 +4088,6 @@ TEST_P(QuicFramerTest, RstStreamFrame) {
{0x00, 0x00, 0x00, 0x01}}
};
- PacketFragments packet44 = {
- // type (short header, 4 byte packet number)
- {"",
- {0x32}},
- // connection_id
- {"",
- {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
- // packet number
- {"",
- {0x12, 0x34, 0x56, 0x78}},
- // frame type (rst stream frame)
- {"",
- {0x01}},
- // stream id
- {"Unable to read stream_id.",
- {0x01, 0x02, 0x03, 0x04}},
- // sent byte offset
- {"Unable to read rst stream sent byte offset.",
- {0x3A, 0x98, 0xFE, 0xDC,
- 0x32, 0x10, 0x76, 0x54}},
- // error code
- {"Unable to read rst stream error code.",
- {0x00, 0x00, 0x00, 0x01}}
- };
-
PacketFragments packet46 = {
// type (short header, 4 byte packet number)
{"",
@@ -4555,10 +4141,8 @@ TEST_P(QuicFramerTest, RstStreamFrame) {
PacketFragments& fragments =
VersionHasIetfQuicFrames(framer_.transport_version())
? packet99
- : (framer_.transport_version() > QUIC_VERSION_44
- ? packet46
- : (framer_.transport_version() > QUIC_VERSION_43 ? packet44
- : packet));
+ : (framer_.transport_version() >= QUIC_VERSION_46 ? packet46
+ : packet);
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
@@ -4606,34 +4190,6 @@ TEST_P(QuicFramerTest, ConnectionCloseFrame) {
}
};
- PacketFragments packet44 = {
- // type (short header, 4 byte packet number)
- {"",
- {0x32}},
- // connection_id
- {"",
- {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
- // packet number
- {"",
- {0x12, 0x34, 0x56, 0x78}},
- // frame type (connection close frame)
- {"",
- {0x02}},
- // error code
- {"Unable to read connection close error code.",
- {0x00, 0x00, 0x00, 0x11}},
- {"Unable to read connection close error details.",
- {
- // error details length
- 0x0, 0x0d,
- // error details
- 'b', 'e', 'c', 'a',
- 'u', 's', 'e', ' ',
- 'I', ' ', 'c', 'a',
- 'n'}
- }
- };
-
PacketFragments packet46 = {
// type (short header, 4 byte packet number)
{"",
@@ -4672,7 +4228,7 @@ TEST_P(QuicFramerTest, ConnectionCloseFrame) {
// packet number
{"",
{0x12, 0x34, 0x56, 0x78}},
- // frame type (IETF_CONNECTION_CLOSE frame)
+ // frame type (IETF Transport CONNECTION_CLOSE frame)
{"",
{0x1c}},
// error code
@@ -4696,10 +4252,8 @@ TEST_P(QuicFramerTest, ConnectionCloseFrame) {
PacketFragments& fragments =
VersionHasIetfQuicFrames(framer_.transport_version())
? packet99
- : (framer_.transport_version() > QUIC_VERSION_44
- ? packet46
- : (framer_.transport_version() > QUIC_VERSION_43 ? packet44
- : packet));
+ : (framer_.transport_version() >= QUIC_VERSION_46 ? packet46
+ : packet);
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
@@ -4717,6 +4271,148 @@ TEST_P(QuicFramerTest, ConnectionCloseFrame) {
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
EXPECT_EQ(0x1234u,
visitor_.connection_close_frame_.transport_close_frame_type);
+ EXPECT_EQ(QUIC_IETF_GQUIC_ERROR_MISSING,
+ visitor_.connection_close_frame_.extracted_error_code);
+ } else {
+ // For Google QUIC closes, the error code is copied into
+ // extracted_error_code.
+ EXPECT_EQ(0x11u,
+ static_cast<unsigned>(
+ visitor_.connection_close_frame_.extracted_error_code));
+ }
+
+ ASSERT_EQ(0u, visitor_.ack_frames_.size());
+
+ CheckFramingBoundaries(fragments, QUIC_INVALID_CONNECTION_CLOSE_DATA);
+}
+
+// As above, but checks that for Google-QUIC, if there happens
+// to be an ErrorCode string at the start of the details, it is
+// NOT extracted/parsed/folded/spindled/and/mutilated.
+TEST_P(QuicFramerTest, ConnectionCloseFrameWithExtractedInfoIgnoreGCuic) {
+ SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
+
+ // clang-format off
+ PacketFragments packet = {
+ // public flags (8 byte connection_id)
+ {"",
+ {0x28}},
+ // connection_id
+ {"",
+ {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
+ // packet number
+ {"",
+ {0x12, 0x34, 0x56, 0x78}},
+ // frame type (connection close frame)
+ {"",
+ {0x02}},
+ // error code
+ {"Unable to read connection close error code.",
+ {0x00, 0x00, 0x00, 0x11}},
+ {"Unable to read connection close error details.",
+ {
+ // error details length
+ 0x0, 0x13,
+ // error details
+ '1', '7', '7', '6',
+ '7', ':', 'b', 'e',
+ 'c', 'a', 'u', 's',
+ 'e', ' ', 'I', ' ',
+ 'c', 'a', 'n'}
+ }
+ };
+
+ PacketFragments packet46 = {
+ // type (short header, 4 byte packet number)
+ {"",
+ {0x43}},
+ // connection_id
+ {"",
+ {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
+ // packet number
+ {"",
+ {0x12, 0x34, 0x56, 0x78}},
+ // frame type (connection close frame)
+ {"",
+ {0x02}},
+ // error code
+ {"Unable to read connection close error code.",
+ {0x00, 0x00, 0x00, 0x11}},
+ {"Unable to read connection close error details.",
+ {
+ // error details length
+ 0x0, 0x13,
+ // error details
+ '1', '7', '7', '6',
+ '7', ':', 'b', 'e',
+ 'c', 'a', 'u', 's',
+ 'e', ' ', 'I', ' ',
+ 'c', 'a', 'n'}
+ }
+ };
+
+ PacketFragments packet99 = {
+ // type (short header, 4 byte packet number)
+ {"",
+ {0x43}},
+ // connection_id
+ {"",
+ {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
+ // packet number
+ {"",
+ {0x12, 0x34, 0x56, 0x78}},
+ // frame type (IETF Transport CONNECTION_CLOSE frame)
+ {"",
+ {0x1c}},
+ // error code
+ {"Unable to read connection close error code.",
+ {kVarInt62OneByte + 0x11}},
+ {"Unable to read connection close frame type.",
+ {kVarInt62TwoBytes + 0x12, 0x34 }},
+ {"Unable to read connection close error details.",
+ {
+ // error details length
+ kVarInt62OneByte + 0x13,
+ // error details
+ '1', '7', '7', '6',
+ '7', ':', 'b', 'e',
+ 'c', 'a', 'u', 's',
+ 'e', ' ', 'I', ' ',
+ 'c', 'a', 'n'}
+ }
+ };
+ // clang-format on
+
+ PacketFragments& fragments =
+ VersionHasIetfQuicFrames(framer_.transport_version())
+ ? packet99
+ : (framer_.transport_version() >= QUIC_VERSION_46 ? packet46
+ : packet);
+ std::unique_ptr<QuicEncryptedPacket> encrypted(
+ AssemblePacketFromFragments(fragments));
+ EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(
+ *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce,
+ PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID));
+
+ EXPECT_EQ(0u, visitor_.stream_frames_.size());
+ EXPECT_EQ(0x11u, static_cast<unsigned>(
+ visitor_.connection_close_frame_.quic_error_code));
+
+ if (VersionHasIetfQuicFrames(framer_.transport_version())) {
+ EXPECT_EQ(0x1234u,
+ visitor_.connection_close_frame_.transport_close_frame_type);
+ EXPECT_EQ(17767u, visitor_.connection_close_frame_.extracted_error_code);
+ EXPECT_EQ("because I can", visitor_.connection_close_frame_.error_details);
+ } else {
+ EXPECT_EQ(0x11u, visitor_.connection_close_frame_.extracted_error_code);
+ // Error code is not prepended in GQUIC, so it is not removed and should
+ // remain in the reason phrase.
+ EXPECT_EQ("17767:because I can",
+ visitor_.connection_close_frame_.error_details);
}
ASSERT_EQ(0u, visitor_.ack_frames_.size());
@@ -4785,49 +4481,79 @@ TEST_P(QuicFramerTest, ApplicationCloseFrame) {
CheckFramingBoundaries(packet99, QUIC_INVALID_CONNECTION_CLOSE_DATA);
}
-TEST_P(QuicFramerTest, GoAwayFrame) {
- if (VersionHasIetfQuicFrames(framer_.transport_version())) {
- // This frame is not supported in version 99.
+// Check that we can extract an error code from an application close.
+TEST_P(QuicFramerTest, ApplicationCloseFrameExtract) {
+ if (!VersionHasIetfQuicFrames(framer_.transport_version())) {
+ // This frame does not exist in versions other than 99.
return;
}
SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
+
// clang-format off
- PacketFragments packet = {
- // public flags (8 byte connection_id)
+ PacketFragments packet99 = {
+ // type (short header, 4 byte packet number)
{"",
- {0x28}},
+ {0x43}},
// connection_id
{"",
{0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
// packet number
{"",
{0x12, 0x34, 0x56, 0x78}},
- // frame type (go away frame)
+ // frame type (IETF_CONNECTION_CLOSE/Application frame)
{"",
- {0x03}},
+ {0x1d}},
// error code
- {"Unable to read go away error code.",
- {0x00, 0x00, 0x00, 0x09}},
- // stream id
- {"Unable to read last good stream id.",
- {0x01, 0x02, 0x03, 0x04}},
- // stream id
- {"Unable to read goaway reason.",
+ {"Unable to read connection close error code.",
+ {kVarInt62OneByte + 0x11}},
+ {"Unable to read connection close error details.",
{
- // error details length
- 0x0, 0x0d,
- // error details
- 'b', 'e', 'c', 'a',
- 'u', 's', 'e', ' ',
- 'I', ' ', 'c', 'a',
- 'n'}
+ // error details length
+ kVarInt62OneByte + 0x13,
+ // error details
+ '1', '7', '7', '6',
+ '7', ':', 'b', 'e',
+ 'c', 'a', 'u', 's',
+ 'e', ' ', 'I', ' ',
+ 'c', 'a', 'n'}
}
};
+ // clang-format on
- PacketFragments packet44 = {
- // type (short header, 4 byte packet number)
+ std::unique_ptr<QuicEncryptedPacket> encrypted(
+ AssemblePacketFromFragments(packet99));
+ EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(
+ *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce,
+ PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID));
+
+ EXPECT_EQ(0u, visitor_.stream_frames_.size());
+
+ EXPECT_EQ(IETF_QUIC_APPLICATION_CONNECTION_CLOSE,
+ visitor_.connection_close_frame_.close_type);
+ EXPECT_EQ(17767u, visitor_.connection_close_frame_.extracted_error_code);
+ EXPECT_EQ(0x11u, visitor_.connection_close_frame_.quic_error_code);
+ EXPECT_EQ("because I can", visitor_.connection_close_frame_.error_details);
+
+ ASSERT_EQ(0u, visitor_.ack_frames_.size());
+
+ CheckFramingBoundaries(packet99, QUIC_INVALID_CONNECTION_CLOSE_DATA);
+}
+
+TEST_P(QuicFramerTest, GoAwayFrame) {
+ if (VersionHasIetfQuicFrames(framer_.transport_version())) {
+ // This frame is not supported in version 99.
+ return;
+ }
+ SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
+ // clang-format off
+ PacketFragments packet = {
+ // public flags (8 byte connection_id)
{"",
- {0x32}},
+ {0x28}},
// connection_id
{"",
{0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
@@ -4890,9 +4616,7 @@ TEST_P(QuicFramerTest, GoAwayFrame) {
// clang-format on
PacketFragments& fragments =
- framer_.transport_version() > QUIC_VERSION_44
- ? packet46
- : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 : packet);
+ framer_.transport_version() >= QUIC_VERSION_46 ? packet46 : packet;
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
@@ -4940,28 +4664,6 @@ TEST_P(QuicFramerTest, WindowUpdateFrame) {
0x32, 0x10, 0x76, 0x54}},
};
- PacketFragments packet44 = {
- // type (short header, 4 byte packet number)
- {"",
- {0x32}},
- // connection_id
- {"",
- {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
- // packet number
- {"",
- {0x12, 0x34, 0x56, 0x78}},
- // frame type (window update frame)
- {"",
- {0x04}},
- // stream id
- {"Unable to read stream_id.",
- {0x01, 0x02, 0x03, 0x04}},
- // byte offset
- {"Unable to read window byte_offset.",
- {0x3A, 0x98, 0xFE, 0xDC,
- 0x32, 0x10, 0x76, 0x54}},
- };
-
PacketFragments packet46 = {
// type (short header, 4 byte packet number)
{"",
@@ -4987,9 +4689,7 @@ TEST_P(QuicFramerTest, WindowUpdateFrame) {
// clang-format on
PacketFragments& fragments =
- framer_.transport_version() > QUIC_VERSION_44
- ? packet46
- : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 : packet);
+ framer_.transport_version() >= QUIC_VERSION_46 ? packet46 : packet;
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
@@ -5117,24 +4817,6 @@ TEST_P(QuicFramerTest, BlockedFrame) {
{0x01, 0x02, 0x03, 0x04}},
};
- PacketFragments packet44 = {
- // type (short header, 4 byte packet number)
- {"",
- {0x32}},
- // connection_id
- {"",
- {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
- // packet number
- {"",
- {0x12, 0x34, 0x56, 0x78}},
- // frame type (blocked frame)
- {"",
- {0x05}},
- // stream id
- {"Unable to read stream_id.",
- {0x01, 0x02, 0x03, 0x04}},
- };
-
PacketFragments packet46 = {
// type (short header, 4 byte packet number)
{"",
@@ -5178,10 +4860,8 @@ TEST_P(QuicFramerTest, BlockedFrame) {
PacketFragments& fragments =
VersionHasIetfQuicFrames(framer_.transport_version())
? packet99
- : (framer_.transport_version() > QUIC_VERSION_44
- ? packet46
- : (framer_.transport_version() > QUIC_VERSION_43 ? packet44
- : packet));
+ : (framer_.transport_version() >= QUIC_VERSION_46 ? packet46
+ : packet);
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
@@ -5221,18 +4901,6 @@ TEST_P(QuicFramerTest, PingFrame) {
0x07,
};
- unsigned char packet44[] = {
- // type (short header, 4 byte packet number)
- 0x32,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
- 0x12, 0x34, 0x56, 0x78,
-
- // frame type
- 0x07,
- };
-
unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
@@ -5261,18 +4929,13 @@ TEST_P(QuicFramerTest, PingFrame) {
QuicEncryptedPacket encrypted(
AsChars(VersionHasIetfQuicFrames(framer_.transport_version())
? packet99
- : (framer_.transport_version() > QUIC_VERSION_44
- ? packet46
- : framer_.transport_version() > QUIC_VERSION_43
- ? packet44
- : packet)),
+ : (framer_.transport_version() >= QUIC_VERSION_46 ? packet46
+ : packet)),
VersionHasIetfQuicFrames(framer_.transport_version())
? QUIC_ARRAYSIZE(packet99)
- : (framer_.transport_version() > QUIC_VERSION_44
+ : (framer_.transport_version() >= QUIC_VERSION_46
? QUIC_ARRAYSIZE(packet46)
- : framer_.transport_version() > QUIC_VERSION_43
- ? QUIC_ARRAYSIZE(packet44)
- : QUIC_ARRAYSIZE(packet)),
+ : QUIC_ARRAYSIZE(packet)),
false);
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
@@ -5288,38 +4951,11 @@ TEST_P(QuicFramerTest, PingFrame) {
}
TEST_P(QuicFramerTest, MessageFrame) {
- if (framer_.transport_version() <= QUIC_VERSION_44) {
+ if (framer_.transport_version() <= QUIC_VERSION_43) {
return;
}
SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
// clang-format off
- PacketFragments packet45 = {
- // type (short header, 4 byte packet number)
- {"",
- {0x32}},
- // connection_id
- {"",
- {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
- // packet number
- {"",
- {0x12, 0x34, 0x56, 0x78}},
- // message frame type.
- {"",
- { 0x21 }},
- // message length
- {"Unable to read message length",
- {0x07}},
- // message data
- {"Unable to read message data",
- {'m', 'e', 's', 's', 'a', 'g', 'e'}},
- // message frame no length.
- {"",
- { 0x20 }},
- // message data
- {{},
- {'m', 'e', 's', 's', 'a', 'g', 'e', '2'}},
- };
-
PacketFragments packet46 = {
// type (short header, 4 byte packet number)
{"",
@@ -5348,8 +4984,8 @@ TEST_P(QuicFramerTest, MessageFrame) {
};
// clang-format on
- std::unique_ptr<QuicEncryptedPacket> encrypted(AssemblePacketFromFragments(
- framer_.transport_version() > QUIC_VERSION_44 ? packet46 : packet45));
+ std::unique_ptr<QuicEncryptedPacket> encrypted(
+ AssemblePacketFromFragments(packet46));
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
@@ -5362,9 +4998,7 @@ TEST_P(QuicFramerTest, MessageFrame) {
EXPECT_EQ(7u, visitor_.message_frames_[0]->message_length);
EXPECT_EQ(8u, visitor_.message_frames_[1]->message_length);
- CheckFramingBoundaries(
- framer_.transport_version() > QUIC_VERSION_44 ? packet46 : packet45,
- QUIC_INVALID_MESSAGE_DATA);
+ CheckFramingBoundaries(packet46, QUIC_INVALID_MESSAGE_DATA);
}
TEST_P(QuicFramerTest, PublicResetPacketV33) {
@@ -5578,8 +5212,6 @@ TEST_P(QuicFramerTest, IetfStatelessResetPacket) {
unsigned char packet[] = {
// type (short packet, 1 byte packet number)
0x50,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
// Random bytes
0x01, 0x11, 0x02, 0x22, 0x03, 0x33, 0x04, 0x44,
0x01, 0x11, 0x02, 0x22, 0x03, 0x33, 0x04, 0x44,
@@ -5594,6 +5226,8 @@ TEST_P(QuicFramerTest, IetfStatelessResetPacket) {
return;
}
QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
+ QuicFramerPeer::SetLastSerializedServerConnectionId(&framer_,
+ TestConnectionId(0x33));
decrypter_ = new test::TestDecrypter();
if (framer_.version().KnowsWhichDecrypterToUse()) {
framer_.InstallDecrypter(ENCRYPTION_INITIAL, QuicMakeUnique<NullDecrypter>(
@@ -5620,8 +5254,11 @@ TEST_P(QuicFramerTest, IetfStatelessResetPacketInvalidStatelessResetToken) {
unsigned char packet[] = {
// type (short packet, 1 byte packet number)
0x50,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // Random bytes
+ 0x01, 0x11, 0x02, 0x22, 0x03, 0x33, 0x04, 0x44,
+ 0x01, 0x11, 0x02, 0x22, 0x03, 0x33, 0x04, 0x44,
+ 0x01, 0x11, 0x02, 0x22, 0x03, 0x33, 0x04, 0x44,
+ 0x01, 0x11, 0x02, 0x22, 0x03, 0x33, 0x04, 0x44,
// stateless reset token
0xB6, 0x69, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -5630,6 +5267,8 @@ TEST_P(QuicFramerTest, IetfStatelessResetPacketInvalidStatelessResetToken) {
if (framer_.transport_version() <= QUIC_VERSION_43) {
return;
}
+ QuicFramerPeer::SetLastSerializedServerConnectionId(&framer_,
+ TestConnectionId(0x33));
QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
decrypter_ = new test::TestDecrypter();
if (framer_.version().KnowsWhichDecrypterToUse()) {
@@ -5665,7 +5304,7 @@ TEST_P(QuicFramerTest, VersionNegotiationPacketClient) {
'Q', '2', '.', '0'}},
};
- PacketFragments packet44 = {
+ PacketFragments packet46 = {
// type (long header)
{"",
{0x8F}},
@@ -5682,12 +5321,34 @@ TEST_P(QuicFramerTest, VersionNegotiationPacketClient) {
{QUIC_VERSION_BYTES,
'Q', '2', '.', '0'}},
};
+
+ PacketFragments packet99 = {
+ // type (long header)
+ {"",
+ {0x8F}},
+ // version tag
+ {"",
+ {0x00, 0x00, 0x00, 0x00}},
+ {"",
+ {0x08}},
+ // connection_id
+ {"",
+ {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
+ {"",
+ {0x00}},
+ // Supported versions
+ {"Unable to read supported version in negotiation.",
+ {QUIC_VERSION_BYTES,
+ 'Q', '2', '.', '0'}},
+ };
// clang-format on
QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
PacketFragments& fragments =
- framer_.transport_version() > QUIC_VERSION_43 ? packet44 : packet;
+ framer_.transport_version() >= QUIC_VERSION_99
+ ? packet99
+ : framer_.transport_version() > QUIC_VERSION_43 ? packet46 : packet;
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
@@ -5706,7 +5367,7 @@ TEST_P(QuicFramerTest, VersionNegotiationPacketClient) {
}
TEST_P(QuicFramerTest, VersionNegotiationPacketServer) {
- if (framer_.transport_version() < QUIC_VERSION_44) {
+ if (framer_.transport_version() <= QUIC_VERSION_43) {
return;
}
@@ -5725,9 +5386,30 @@ TEST_P(QuicFramerTest, VersionNegotiationPacketServer) {
QUIC_VERSION_BYTES,
'Q', '2', '.', '0',
};
+ unsigned char packet2[] = {
+ // public flags (long header with all ignored bits set)
+ 0xFF,
+ // version
+ 0x00, 0x00, 0x00, 0x00,
+ // destination connection ID length
+ 0x08,
+ // destination connection ID
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x11,
+ // source connection ID length
+ 0x00,
+ // supported versions
+ QUIC_VERSION_BYTES,
+ 'Q', '2', '.', '0',
+ };
// clang-format on
+ unsigned char* p = packet;
+ size_t p_length = QUIC_ARRAYSIZE(packet);
+ if (framer_.version().HasLengthPrefixedConnectionIds()) {
+ p = packet2;
+ p_length = QUIC_ARRAYSIZE(packet2);
+ }
- QuicEncryptedPacket encrypted(AsChars(packet), QUIC_ARRAYSIZE(packet), false);
+ QuicEncryptedPacket encrypted(AsChars(p), p_length, false);
EXPECT_FALSE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_INVALID_VERSION_NEGOTIATION_PACKET, framer_.error());
EXPECT_EQ("Server received version negotiation packet.",
@@ -5796,9 +5478,34 @@ TEST_P(QuicFramerTest, ParseIetfRetryPacket) {
'H', 'e', 'l', 'l', 'o', ' ', 't', 'h', 'i', 's',
' ', 'i', 's', ' ', 'R', 'E', 'T', 'R', 'Y', '!',
};
+ unsigned char packet99[] = {
+ // public flags (long header with packet type RETRY)
+ 0xF0,
+ // version
+ QUIC_VERSION_BYTES,
+ // destination connection ID length
+ 0x00,
+ // source connection ID length
+ 0x08,
+ // source connection ID
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x11,
+ // original destination connection ID length
+ 0x08,
+ // original destination connection ID
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // retry token
+ 'H', 'e', 'l', 'l', 'o', ' ', 't', 'h', 'i', 's',
+ ' ', 'i', 's', ' ', 'R', 'E', 'T', 'R', 'Y', '!',
+ };
// clang-format on
- QuicEncryptedPacket encrypted(AsChars(packet), QUIC_ARRAYSIZE(packet), false);
+ unsigned char* p = packet;
+ size_t p_length = QUIC_ARRAYSIZE(packet);
+ if (framer_.transport_version() == QUIC_VERSION_99) {
+ p = packet99;
+ p_length = QUIC_ARRAYSIZE(packet99);
+ }
+ QuicEncryptedPacket encrypted(AsChars(p), p_length, false);
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
@@ -5828,7 +5535,7 @@ TEST_P(QuicFramerTest, RejectIetfRetryPacketAsServer) {
// version
QUIC_VERSION_BYTES,
// connection ID lengths
- 0x05,
+ 0x00, 0x08,
// source connection ID
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x11,
// original destination connection ID
@@ -5870,19 +5577,6 @@ TEST_P(QuicFramerTest, BuildPaddingFramePacket) {
0x00, 0x00, 0x00, 0x00
};
- unsigned char packet44[kMaxOutgoingPacketSize] = {
- // type (short header, 4 byte packet number)
- 0x32,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
- 0x12, 0x34, 0x56, 0x78,
-
- // frame type (padding frame)
- 0x00,
- 0x00, 0x00, 0x00, 0x00
- };
-
unsigned char packet46[kMaxOutgoingPacketSize] = {
// type (short header, 4 byte packet number)
0x43,
@@ -5913,10 +5607,8 @@ TEST_P(QuicFramerTest, BuildPaddingFramePacket) {
unsigned char* p = packet;
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
p = packet99;
- } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ } else if (framer_.transport_version() >= QUIC_VERSION_46) {
p = packet46;
- } else if (framer_.transport_version() > QUIC_VERSION_43) {
- p = packet44;
}
uint64_t header_size = GetPacketHeaderSize(
@@ -5931,7 +5623,7 @@ TEST_P(QuicFramerTest, BuildPaddingFramePacket) {
test::CompareCharArraysWithHexError(
"constructed packet", data->data(), data->length(), AsChars(p),
- framer_.transport_version() > QUIC_VERSION_43 ? QUIC_ARRAYSIZE(packet44)
+ framer_.transport_version() > QUIC_VERSION_43 ? QUIC_ARRAYSIZE(packet46)
: QUIC_ARRAYSIZE(packet));
}
@@ -5976,33 +5668,6 @@ TEST_P(QuicFramerTest, BuildStreamFramePacketWithNewPaddingFrame) {
0x00, 0x00,
};
- unsigned char packet44[] = {
- // type (short header, 4 byte packet number)
- 0x32,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
- 0x12, 0x34, 0x56, 0x78,
-
- // paddings
- 0x00, 0x00,
- // frame type (stream frame with fin)
- 0xFF,
- // stream id
- 0x01, 0x02, 0x03, 0x04,
- // offset
- 0x3A, 0x98, 0xFE, 0xDC,
- 0x32, 0x10, 0x76, 0x54,
- // data length
- 0x00, 0x0c,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!',
- // paddings
- 0x00, 0x00,
- };
-
unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
@@ -6066,12 +5731,9 @@ TEST_P(QuicFramerTest, BuildStreamFramePacketWithNewPaddingFrame) {
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
p = packet99;
p_size = QUIC_ARRAYSIZE(packet99);
- } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ } else if (framer_.transport_version() >= QUIC_VERSION_46) {
p = packet46;
p_size = QUIC_ARRAYSIZE(packet46);
- } else if (framer_.transport_version() > QUIC_VERSION_43) {
- p = packet44;
- p_size = QUIC_ARRAYSIZE(packet44);
}
QuicEncryptedPacket encrypted(AsChars(p), p_size, false);
@@ -6104,19 +5766,6 @@ TEST_P(QuicFramerTest, Build4ByteSequenceNumberPaddingFramePacket) {
0x00, 0x00, 0x00, 0x00
};
- unsigned char packet44[kMaxOutgoingPacketSize] = {
- // type (short header, 4 byte packet number)
- 0x32,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
- 0x12, 0x34, 0x56, 0x78,
-
- // frame type (padding frame)
- 0x00,
- 0x00, 0x00, 0x00, 0x00
- };
-
unsigned char packet46[kMaxOutgoingPacketSize] = {
// type (short header, 4 byte packet number)
0x43,
@@ -6147,10 +5796,8 @@ TEST_P(QuicFramerTest, Build4ByteSequenceNumberPaddingFramePacket) {
unsigned char* p = packet;
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
p = packet99;
- } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ } else if (framer_.transport_version() >= QUIC_VERSION_46) {
p = packet46;
- } else if (framer_.transport_version() > QUIC_VERSION_43) {
- p = packet44;
}
uint64_t header_size = GetPacketHeaderSize(
@@ -6165,7 +5812,7 @@ TEST_P(QuicFramerTest, Build4ByteSequenceNumberPaddingFramePacket) {
test::CompareCharArraysWithHexError(
"constructed packet", data->data(), data->length(), AsChars(p),
- framer_.transport_version() > QUIC_VERSION_43 ? QUIC_ARRAYSIZE(packet44)
+ framer_.transport_version() > QUIC_VERSION_43 ? QUIC_ARRAYSIZE(packet46)
: QUIC_ARRAYSIZE(packet));
}
@@ -6194,19 +5841,6 @@ TEST_P(QuicFramerTest, Build2ByteSequenceNumberPaddingFramePacket) {
0x00, 0x00, 0x00, 0x00
};
- unsigned char packet44[kMaxOutgoingPacketSize] = {
- // type (short header, 2 byte packet number)
- 0x31,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
- 0x56, 0x78,
-
- // frame type (padding frame)
- 0x00,
- 0x00, 0x00, 0x00, 0x00
- };
-
unsigned char packet46[kMaxOutgoingPacketSize] = {
// type (short header, 2 byte packet number)
0x41,
@@ -6237,10 +5871,8 @@ TEST_P(QuicFramerTest, Build2ByteSequenceNumberPaddingFramePacket) {
unsigned char* p = packet;
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
p = packet99;
- } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ } else if (framer_.transport_version() >= QUIC_VERSION_46) {
p = packet46;
- } else if (framer_.transport_version() > QUIC_VERSION_43) {
- p = packet44;
}
uint64_t header_size = GetPacketHeaderSize(
@@ -6255,7 +5887,7 @@ TEST_P(QuicFramerTest, Build2ByteSequenceNumberPaddingFramePacket) {
test::CompareCharArraysWithHexError(
"constructed packet", data->data(), data->length(), AsChars(p),
- framer_.transport_version() > QUIC_VERSION_43 ? QUIC_ARRAYSIZE(packet44)
+ framer_.transport_version() > QUIC_VERSION_43 ? QUIC_ARRAYSIZE(packet46)
: QUIC_ARRAYSIZE(packet));
}
@@ -6284,19 +5916,6 @@ TEST_P(QuicFramerTest, Build1ByteSequenceNumberPaddingFramePacket) {
0x00, 0x00, 0x00, 0x00
};
- unsigned char packet44[kMaxOutgoingPacketSize] = {
- // type (short header, 1 byte packet number)
- 0x30,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
- 0x78,
-
- // frame type (padding frame)
- 0x00,
- 0x00, 0x00, 0x00, 0x00
- };
-
unsigned char packet46[kMaxOutgoingPacketSize] = {
// type (short header, 1 byte packet number)
0x40,
@@ -6327,10 +5946,8 @@ TEST_P(QuicFramerTest, Build1ByteSequenceNumberPaddingFramePacket) {
unsigned char* p = packet;
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
p = packet99;
- } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ } else if (framer_.transport_version() >= QUIC_VERSION_46) {
p = packet46;
- } else if (framer_.transport_version() > QUIC_VERSION_43) {
- p = packet44;
}
uint64_t header_size = GetPacketHeaderSize(
@@ -6345,7 +5962,7 @@ TEST_P(QuicFramerTest, Build1ByteSequenceNumberPaddingFramePacket) {
test::CompareCharArraysWithHexError(
"constructed packet", data->data(), data->length(), AsChars(p),
- framer_.transport_version() > QUIC_VERSION_43 ? QUIC_ARRAYSIZE(packet44)
+ framer_.transport_version() > QUIC_VERSION_43 ? QUIC_ARRAYSIZE(packet46)
: QUIC_ARRAYSIZE(packet));
}
@@ -6387,27 +6004,6 @@ TEST_P(QuicFramerTest, BuildStreamFramePacket) {
'r', 'l', 'd', '!',
};
- unsigned char packet44[] = {
- // type (short header, 4 byte packet number)
- 0x32,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
- 0x12, 0x34, 0x56, 0x78,
-
- // frame type (stream frame with fin and no length)
- 0xDF,
- // stream id
- 0x01, 0x02, 0x03, 0x04,
- // offset
- 0x3A, 0x98, 0xFE, 0xDC,
- 0x32, 0x10, 0x76, 0x54,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!',
- };
-
unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
@@ -6459,12 +6055,9 @@ TEST_P(QuicFramerTest, BuildStreamFramePacket) {
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
p = packet99;
p_size = QUIC_ARRAYSIZE(packet99);
- } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ } else if (framer_.transport_version() >= QUIC_VERSION_46) {
p = packet46;
p_size = QUIC_ARRAYSIZE(packet46);
- } else if (framer_.transport_version() > QUIC_VERSION_43) {
- p = packet44;
- p_size = QUIC_ARRAYSIZE(packet44);
}
test::CompareCharArraysWithHexError("constructed packet", data->data(),
data->length(), AsChars(p), p_size);
@@ -6508,28 +6101,6 @@ TEST_P(QuicFramerTest, BuildStreamFramePacketWithVersionFlag) {
'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!',
};
- unsigned char packet44[] = {
- // type (long header with packet type ZERO_RTT_PROTECTED)
- 0xFC,
- // version tag
- QUIC_VERSION_BYTES,
- // connection_id length
- 0x50,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
- 0x12, 0x34, 0x56, 0x78,
-
- // frame type (stream frame with fin and no length)
- 0xDF,
- // stream id
- 0x01, 0x02, 0x03, 0x04,
- // offset
- 0x3A, 0x98, 0xFE, 0xDC, 0x32, 0x10, 0x76, 0x54,
- // data
- 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!',
- };
-
unsigned char packet46[] = {
// type (long header with packet type ZERO_RTT_PROTECTED)
0xD3,
@@ -6557,10 +6128,12 @@ TEST_P(QuicFramerTest, BuildStreamFramePacketWithVersionFlag) {
0xD3,
// version tag
QUIC_VERSION_BYTES,
- // connection_id length
- 0x50,
- // connection_id
+ // destination connection ID length
+ 0x08,
+ // destination connection ID
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // source connection ID length
+ 0x00,
// length
0x40, 0x1D,
// packet number
@@ -6586,12 +6159,9 @@ TEST_P(QuicFramerTest, BuildStreamFramePacketWithVersionFlag) {
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
p = packet99;
p_size = QUIC_ARRAYSIZE(packet99);
- } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ } else if (framer_.transport_version() >= QUIC_VERSION_46) {
p = packet46;
p_size = QUIC_ARRAYSIZE(packet46);
- } else if (framer_.transport_version() > QUIC_VERSION_43) {
- p = packet44;
- p_size = QUIC_ARRAYSIZE(packet44);
}
test::CompareCharArraysWithHexError("constructed packet", data->data(),
data->length(), AsChars(p), p_size);
@@ -6773,7 +6343,7 @@ TEST_P(QuicFramerTest, BuildVersionNegotiationPacket) {
0xDA, 0x5A, 0x3A, 0x3A,
QUIC_VERSION_BYTES,
};
- unsigned char packet44[] = {
+ unsigned char packet46[] = {
// type (long header)
0xC0,
// version tag
@@ -6786,12 +6356,30 @@ TEST_P(QuicFramerTest, BuildVersionNegotiationPacket) {
0xDA, 0x5A, 0x3A, 0x3A,
QUIC_VERSION_BYTES,
};
+ unsigned char packet99[] = {
+ // type (long header)
+ 0xC0,
+ // version tag
+ 0x00, 0x00, 0x00, 0x00,
+ // destination connection ID length
+ 0x00,
+ // source connection ID length
+ 0x08,
+ // source connection ID
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // supported versions
+ 0xDA, 0x5A, 0x3A, 0x3A,
+ QUIC_VERSION_BYTES,
+ };
// clang-format on
unsigned char* p = packet;
size_t p_size = QUIC_ARRAYSIZE(packet);
- if (framer_.transport_version() > QUIC_VERSION_43) {
- p = packet44;
- p_size = QUIC_ARRAYSIZE(packet44);
+ if (framer_.transport_version() >= QUIC_VERSION_99) {
+ p = packet99;
+ p_size = QUIC_ARRAYSIZE(packet99);
+ } else if (framer_.transport_version() > QUIC_VERSION_43) {
+ p = packet46;
+ p_size = QUIC_ARRAYSIZE(packet46);
}
QuicConnectionId connection_id = FramerTestConnectionId();
@@ -6799,19 +6387,17 @@ TEST_P(QuicFramerTest, BuildVersionNegotiationPacket) {
QuicFramer::BuildVersionNegotiationPacket(
connection_id, EmptyQuicConnectionId(),
framer_.transport_version() > QUIC_VERSION_43,
+ framer_.version().HasLengthPrefixedConnectionIds(),
SupportedVersions(GetParam())));
test::CompareCharArraysWithHexError("constructed packet", data->data(),
data->length(), AsChars(p), p_size);
}
TEST_P(QuicFramerTest, BuildVersionNegotiationPacketWithClientConnectionId) {
- if (framer_.transport_version() <= QUIC_VERSION_43) {
- // The GQUIC encoding does not support encoding client connection IDs.
+ if (!framer_.version().SupportsClientConnectionIds()) {
return;
}
- // Client connection IDs cannot be used unless this flag is true.
- SetQuicRestartFlag(quic_do_not_override_connection_id, true);
SetQuicReloadableFlag(quic_version_negotiation_grease, true);
SetQuicFlag(FLAGS_quic_disable_version_negotiation_grease_randomness, true);
@@ -6821,11 +6407,11 @@ TEST_P(QuicFramerTest, BuildVersionNegotiationPacketWithClientConnectionId) {
0xC0,
// version tag
0x00, 0x00, 0x00, 0x00,
- // connection ID lengths
- 0x55,
// client/destination connection ID
+ 0x08,
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x11,
// server/source connection ID
+ 0x08,
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
// supported versions
0xDA, 0x5A, 0x3A, 0x3A,
@@ -6836,9 +6422,9 @@ TEST_P(QuicFramerTest, BuildVersionNegotiationPacketWithClientConnectionId) {
QuicConnectionId server_connection_id = FramerTestConnectionId();
QuicConnectionId client_connection_id = FramerTestConnectionIdPlusOne();
std::unique_ptr<QuicEncryptedPacket> data(
- QuicFramer::BuildVersionNegotiationPacket(server_connection_id,
- client_connection_id, true,
- SupportedVersions(GetParam())));
+ QuicFramer::BuildVersionNegotiationPacket(
+ server_connection_id, client_connection_id, true, true,
+ SupportedVersions(GetParam())));
test::CompareCharArraysWithHexError("constructed packet", data->data(),
data->length(), AsChars(packet),
QUIC_ARRAYSIZE(packet));
@@ -6880,27 +6466,6 @@ TEST_P(QuicFramerTest, BuildAckFramePacketOneAckBlock) {
0x00,
};
- unsigned char packet44[] = {
- // type (short header, 4 byte packet number)
- 0x32,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
- 0x12, 0x34, 0x56, 0x78,
-
- // frame type (ack frame)
- // (no ack blocks, 2 byte largest observed, 2 byte block length)
- 0x45,
- // largest acked
- 0x12, 0x34,
- // Zero delta time.
- 0x00, 0x00,
- // first ack block length.
- 0x12, 0x34,
- // num timestamps.
- 0x00,
- };
-
unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
@@ -6947,12 +6512,9 @@ TEST_P(QuicFramerTest, BuildAckFramePacketOneAckBlock) {
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
p = packet99;
p_size = QUIC_ARRAYSIZE(packet99);
- } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ } else if (framer_.transport_version() >= QUIC_VERSION_46) {
p = packet46;
p_size = QUIC_ARRAYSIZE(packet46);
- } else if (framer_.transport_version() > QUIC_VERSION_43) {
- p = packet44;
- p_size = QUIC_ARRAYSIZE(packet44);
}
std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
@@ -6996,27 +6558,6 @@ TEST_P(QuicFramerTest, BuildAckFramePacketOneAckBlockMaxLength) {
0x00,
};
- unsigned char packet44[] = {
- // type (short header, 4 byte packet number)
- 0x32,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
- 0x12, 0x34, 0x56, 0x78,
-
- // frame type (ack frame)
- // (no ack blocks, 4 byte largest observed, 4 byte block length)
- 0x4A,
- // largest acked
- 0x12, 0x34, 0x56, 0x78,
- // Zero delta time.
- 0x00, 0x00,
- // first ack block length.
- 0x12, 0x34, 0x56, 0x78,
- // num timestamps.
- 0x00,
- };
-
unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
@@ -7064,12 +6605,9 @@ TEST_P(QuicFramerTest, BuildAckFramePacketOneAckBlockMaxLength) {
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
p = packet99;
p_size = QUIC_ARRAYSIZE(packet99);
- } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ } else if (framer_.transport_version() >= QUIC_VERSION_46) {
p = packet46;
p_size = QUIC_ARRAYSIZE(packet46);
- } else if (framer_.transport_version() > QUIC_VERSION_43) {
- p = packet44;
- p_size = QUIC_ARRAYSIZE(packet44);
}
std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
@@ -7136,45 +6674,6 @@ TEST_P(QuicFramerTest, BuildAckFramePacketMultipleAckBlocks) {
0x00,
};
- unsigned char packet44[] = {
- // type (short header, 4 byte packet number)
- 0x32,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
- 0x12, 0x34, 0x56, 0x78,
-
- // frame type (ack frame)
- // (has ack blocks, 2 byte largest observed, 2 byte block length)
- 0x65,
- // largest acked
- 0x12, 0x34,
- // Zero delta time.
- 0x00, 0x00,
- // num ack blocks ranges.
- 0x04,
- // first ack block length.
- 0x00, 0x01,
- // gap to next block.
- 0x01,
- // ack block length.
- 0x0e, 0xaf,
- // gap to next block.
- 0xff,
- // ack block length.
- 0x00, 0x00,
- // gap to next block.
- 0x91,
- // ack block length.
- 0x01, 0xea,
- // gap to next block.
- 0x05,
- // ack block length.
- 0x00, 0x04,
- // num timestamps.
- 0x00,
- };
-
unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
@@ -7254,12 +6753,9 @@ TEST_P(QuicFramerTest, BuildAckFramePacketMultipleAckBlocks) {
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
p = packet99;
p_size = QUIC_ARRAYSIZE(packet99);
- } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ } else if (framer_.transport_version() >= QUIC_VERSION_46) {
p = packet46;
p_size = QUIC_ARRAYSIZE(packet46);
- } else if (framer_.transport_version() > QUIC_VERSION_43) {
- p = packet44;
- p_size = QUIC_ARRAYSIZE(packet44);
}
std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
@@ -7383,99 +6879,6 @@ TEST_P(QuicFramerTest, BuildAckFramePacketMaxAckBlocks) {
0x00,
};
- unsigned char packet44[] = {
- // type (short header, 4 byte packet number)
- 0x32,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
- 0x12, 0x34, 0x56, 0x78,
- // frame type (ack frame)
- // (has ack blocks, 2 byte largest observed, 2 byte block length)
- 0x65,
- // largest acked
- 0x12, 0x34,
- // Zero delta time.
- 0x00, 0x00,
- // num ack blocks ranges.
- 0xff,
- // first ack block length.
- 0x0f, 0xdd,
- // 255 = 4 * 63 + 3
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
-
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
-
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
-
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
-
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
-
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
-
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
- // num timestamps.
- 0x00,
- };
-
unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
@@ -7659,12 +7062,9 @@ TEST_P(QuicFramerTest, BuildAckFramePacketMaxAckBlocks) {
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
p = packet99;
p_size = QUIC_ARRAYSIZE(packet99);
- } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ } else if (framer_.transport_version() >= QUIC_VERSION_46) {
p = packet46;
p_size = QUIC_ARRAYSIZE(packet46);
- } else if (framer_.transport_version() > QUIC_VERSION_43) {
- p = packet44;
- p_size = QUIC_ARRAYSIZE(packet44);
}
std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
@@ -7752,25 +7152,6 @@ TEST_P(QuicFramerTest, BuildRstFramePacketQuic) {
0x05, 0x06, 0x07, 0x08,
};
- unsigned char packet44[] = {
- // type (short packet, 4 byte packet number)
- 0x32,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
- 0x12, 0x34, 0x56, 0x78,
-
- // frame type (rst stream frame)
- 0x01,
- // stream id
- 0x01, 0x02, 0x03, 0x04,
- // sent byte offset
- 0x08, 0x07, 0x06, 0x05,
- 0x04, 0x03, 0x02, 0x01,
- // error code
- 0x05, 0x06, 0x07, 0x08,
- };
-
unsigned char packet46[] = {
// type (short packet, 4 byte packet number)
0x43,
@@ -7819,12 +7200,9 @@ TEST_P(QuicFramerTest, BuildRstFramePacketQuic) {
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
p = packet99;
p_size = QUIC_ARRAYSIZE(packet99);
- } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ } else if (framer_.transport_version() >= QUIC_VERSION_46) {
p = packet46;
p_size = QUIC_ARRAYSIZE(packet46);
- } else if (framer_.transport_version() > QUIC_VERSION_43) {
- p = packet44;
- p_size = QUIC_ARRAYSIZE(packet44);
}
QuicEncryptedPacket encrypted(AsChars(p), p_size, false);
@@ -7875,9 +7253,99 @@ TEST_P(QuicFramerTest, BuildCloseFramePacket) {
'n',
};
- unsigned char packet44[] = {
+ unsigned char packet46[] = {
// type (short header, 4 byte packet number)
- 0x32,
+ 0x43,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78,
+
+ // frame type (connection close frame)
+ 0x02,
+ // error code
+ 0x05, 0x06, 0x07, 0x08,
+ // error details length
+ 0x00, 0x0d,
+ // error details
+ 'b', 'e', 'c', 'a',
+ 'u', 's', 'e', ' ',
+ 'I', ' ', 'c', 'a',
+ 'n',
+ };
+
+ unsigned char packet99[] = {
+ // type (short header, 4 byte packet number)
+ 0x43,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78,
+
+ // frame type (IETF_CONNECTION_CLOSE frame)
+ 0x1c,
+ // error code
+ kVarInt62OneByte + 0x11,
+ // Frame type within the CONNECTION_CLOSE frame
+ kVarInt62OneByte + 0x05,
+ // error details length
+ kVarInt62OneByte + 0x0d,
+ // error details
+ 'b', 'e', 'c', 'a',
+ 'u', 's', 'e', ' ',
+ 'I', ' ', 'c', 'a',
+ 'n',
+ };
+ // clang-format on
+
+ unsigned char* p = packet;
+ size_t p_size = QUIC_ARRAYSIZE(packet);
+ if (VersionHasIetfQuicFrames(framer_.transport_version())) {
+ p = packet99;
+ p_size = QUIC_ARRAYSIZE(packet99);
+ } else if (framer_.transport_version() >= QUIC_VERSION_46) {
+ p = packet46;
+ p_size = QUIC_ARRAYSIZE(packet46);
+ }
+
+ std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
+ ASSERT_TRUE(data != nullptr);
+
+ test::CompareCharArraysWithHexError("constructed packet", data->data(),
+ data->length(), AsChars(p), p_size);
+}
+
+TEST_P(QuicFramerTest, BuildCloseFramePacketExtendedInfo) {
+ QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
+ QuicPacketHeader header;
+ header.destination_connection_id = FramerTestConnectionId();
+ header.reset_flag = false;
+ header.version_flag = false;
+ header.packet_number = kPacketNumber;
+
+ QuicConnectionCloseFrame close_frame;
+ if (VersionHasIetfQuicFrames(framer_.transport_version())) {
+ close_frame.transport_error_code =
+ static_cast<QuicIetfTransportErrorCodes>(0x11);
+ close_frame.transport_close_frame_type = 0x05;
+ close_frame.close_type = IETF_QUIC_TRANSPORT_CONNECTION_CLOSE;
+ } else {
+ close_frame.quic_error_code = static_cast<QuicErrorCode>(0x05060708);
+ }
+ // Set this so that it is "there" for both Google QUIC and IETF QUIC
+ // framing. It better not show up for Google QUIC!
+ close_frame.extracted_error_code = static_cast<QuicErrorCode>(0x4567);
+
+ // For IETF QUIC this will be prefaced with "17767:"
+ // (17767 == 0x4567).
+ close_frame.error_details = "because I can";
+
+ QuicFrames frames = {QuicFrame(&close_frame)};
+
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x2C,
// connection_id
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
// packet number
@@ -7932,12 +7400,13 @@ TEST_P(QuicFramerTest, BuildCloseFramePacket) {
// Frame type within the CONNECTION_CLOSE frame
kVarInt62OneByte + 0x05,
// error details length
- kVarInt62OneByte + 0x0d,
+ kVarInt62OneByte + 0x13,
// error details
- 'b', 'e', 'c', 'a',
- 'u', 's', 'e', ' ',
- 'I', ' ', 'c', 'a',
- 'n',
+ '1', '7', '7', '6',
+ '7', ':', 'b', 'e',
+ 'c', 'a', 'u', 's',
+ 'e', ' ', 'I', ' ',
+ 'c', 'a', 'n'
};
// clang-format on
@@ -7946,12 +7415,9 @@ TEST_P(QuicFramerTest, BuildCloseFramePacket) {
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
p = packet99;
p_size = QUIC_ARRAYSIZE(packet99);
- } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ } else if (framer_.transport_version() >= QUIC_VERSION_46) {
p = packet46;
p_size = QUIC_ARRAYSIZE(packet46);
- } else if (framer_.transport_version() > QUIC_VERSION_43) {
- p = packet44;
- p_size = QUIC_ARRAYSIZE(packet44);
}
std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
@@ -8030,55 +7496,6 @@ TEST_P(QuicFramerTest, BuildTruncatedCloseFramePacket) {
'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
};
- unsigned char packet44[] = {
- // type (short header, 4 byte packet number)
- 0x32,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
- 0x12, 0x34, 0x56, 0x78,
-
- // frame type (connection close frame)
- 0x02,
- // error code
- 0x05, 0x06, 0x07, 0x08,
- // error details length
- 0x01, 0x00,
- // error details (truncated to 256 bytes)
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- };
-
unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
@@ -8185,12 +7602,9 @@ TEST_P(QuicFramerTest, BuildTruncatedCloseFramePacket) {
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
p = packet99;
p_size = QUIC_ARRAYSIZE(packet99);
- } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ } else if (framer_.transport_version() >= QUIC_VERSION_46) {
p = packet46;
p_size = QUIC_ARRAYSIZE(packet46);
- } else if (framer_.transport_version() > QUIC_VERSION_43) {
- p = packet44;
- p_size = QUIC_ARRAYSIZE(packet44);
}
std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
@@ -8374,29 +7788,6 @@ TEST_P(QuicFramerTest, BuildGoAwayPacket) {
'n',
};
- unsigned char packet44[] = {
- // type (short header, 4 byte packet number)
- 0x32,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
- 0x12, 0x34, 0x56, 0x78,
-
- // frame type (go away frame)
- 0x03,
- // error code
- 0x05, 0x06, 0x07, 0x08,
- // stream id
- 0x01, 0x02, 0x03, 0x04,
- // error details length
- 0x00, 0x0d,
- // error details
- 'b', 'e', 'c', 'a',
- 'u', 's', 'e', ' ',
- 'I', ' ', 'c', 'a',
- 'n',
- };
-
unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
@@ -8424,12 +7815,9 @@ TEST_P(QuicFramerTest, BuildGoAwayPacket) {
unsigned char* p = packet;
size_t p_size = QUIC_ARRAYSIZE(packet);
- if (framer_.transport_version() > QUIC_VERSION_44) {
+ if (framer_.transport_version() > QUIC_VERSION_43) {
p = packet46;
p_size = QUIC_ARRAYSIZE(packet46);
- } else if (framer_.transport_version() > QUIC_VERSION_43) {
- p = packet44;
- p_size = QUIC_ARRAYSIZE(packet44);
}
std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
@@ -8510,57 +7898,6 @@ TEST_P(QuicFramerTest, BuildTruncatedGoAwayPacket) {
'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
};
- unsigned char packet44[] = {
- // type (short header, 4 byte packet number)
- 0x32,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
- 0x12, 0x34, 0x56, 0x78,
-
- // frame type (go away frame)
- 0x03,
- // error code
- 0x05, 0x06, 0x07, 0x08,
- // stream id
- 0x01, 0x02, 0x03, 0x04,
- // error details length
- 0x01, 0x00,
- // error details (truncated to 256 bytes)
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- };
-
unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
@@ -8615,12 +7952,9 @@ TEST_P(QuicFramerTest, BuildTruncatedGoAwayPacket) {
unsigned char* p = packet;
size_t p_size = QUIC_ARRAYSIZE(packet);
- if (framer_.transport_version() > QUIC_VERSION_44) {
+ if (framer_.transport_version() > QUIC_VERSION_43) {
p = packet46;
p_size = QUIC_ARRAYSIZE(packet46);
- } else if (framer_.transport_version() > QUIC_VERSION_43) {
- p = packet44;
- p_size = QUIC_ARRAYSIZE(packet44);
}
std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
@@ -8662,23 +7996,6 @@ TEST_P(QuicFramerTest, BuildWindowUpdatePacket) {
0x55, 0x66, 0x77, 0x88,
};
- unsigned char packet44[] = {
- // type (short header, 4 byte packet number)
- 0x32,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
- 0x12, 0x34, 0x56, 0x78,
-
- // frame type (window update frame)
- 0x04,
- // stream id
- 0x01, 0x02, 0x03, 0x04,
- // byte offset
- 0x11, 0x22, 0x33, 0x44,
- 0x55, 0x66, 0x77, 0x88,
- };
-
unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
@@ -8722,12 +8039,9 @@ TEST_P(QuicFramerTest, BuildWindowUpdatePacket) {
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
p = packet99;
p_size = QUIC_ARRAYSIZE(packet99);
- } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ } else if (framer_.transport_version() >= QUIC_VERSION_46) {
p = packet46;
p_size = QUIC_ARRAYSIZE(packet46);
- } else if (framer_.transport_version() > QUIC_VERSION_43) {
- p = packet44;
- p_size = QUIC_ARRAYSIZE(packet44);
}
test::CompareCharArraysWithHexError("constructed packet", data->data(),
@@ -8860,20 +8174,6 @@ TEST_P(QuicFramerTest, BuildBlockedPacket) {
0x01, 0x02, 0x03, 0x04,
};
- unsigned char packet44[] = {
- // type (short packet, 4 byte packet number)
- 0x32,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
- 0x12, 0x34, 0x56, 0x78,
-
- // frame type (blocked frame)
- 0x05,
- // stream id
- 0x01, 0x02, 0x03, 0x04,
- };
-
unsigned char packet46[] = {
// type (short packet, 4 byte packet number)
0x43,
@@ -8911,12 +8211,9 @@ TEST_P(QuicFramerTest, BuildBlockedPacket) {
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
p = packet99;
p_size = QUIC_ARRAYSIZE(packet99);
- } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ } else if (framer_.transport_version() >= QUIC_VERSION_46) {
p = packet46;
p_size = QUIC_ARRAYSIZE(packet46);
- } else if (framer_.transport_version() > QUIC_VERSION_43) {
- p = packet44;
- p_size = QUIC_ARRAYSIZE(packet44);
}
test::CompareCharArraysWithHexError("constructed packet", data->data(),
@@ -8946,18 +8243,6 @@ TEST_P(QuicFramerTest, BuildPingPacket) {
0x07,
};
- unsigned char packet44[] = {
- // type (short header, 4 byte packet number)
- 0x32,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
- 0x12, 0x34, 0x56, 0x78,
-
- // frame type
- 0x07,
- };
-
unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
@@ -8986,10 +8271,8 @@ TEST_P(QuicFramerTest, BuildPingPacket) {
unsigned char* p = packet;
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
p = packet99;
- } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ } else if (framer_.transport_version() >= QUIC_VERSION_46) {
p = packet46;
- } else if (framer_.transport_version() > QUIC_VERSION_43) {
- p = packet44;
}
std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
@@ -8997,12 +8280,12 @@ TEST_P(QuicFramerTest, BuildPingPacket) {
test::CompareCharArraysWithHexError(
"constructed packet", data->data(), data->length(), AsChars(p),
- framer_.transport_version() > QUIC_VERSION_43 ? QUIC_ARRAYSIZE(packet44)
+ framer_.transport_version() > QUIC_VERSION_43 ? QUIC_ARRAYSIZE(packet46)
: QUIC_ARRAYSIZE(packet));
}
TEST_P(QuicFramerTest, BuildMessagePacket) {
- if (framer_.transport_version() <= QUIC_VERSION_44) {
+ if (framer_.transport_version() <= QUIC_VERSION_43) {
return;
}
QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
@@ -9018,26 +8301,6 @@ TEST_P(QuicFramerTest, BuildMessagePacket) {
QuicFrames frames = {QuicFrame(&frame), QuicFrame(&frame2)};
// clang-format off
- unsigned char packet45[] = {
- // type (short header, 4 byte packet number)
- 0x32,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
- 0x12, 0x34, 0x56, 0x78,
-
- // frame type (message frame)
- 0x21,
- // Length
- 0x07,
- // Message Data
- 'm', 'e', 's', 's', 'a', 'g', 'e',
- // frame type (message frame no length)
- 0x20,
- // Message Data
- 'm', 'e', 's', 's', 'a', 'g', 'e', '2'
- };
-
unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
@@ -9079,11 +8342,9 @@ TEST_P(QuicFramerTest, BuildMessagePacket) {
};
// clang-format on
- unsigned char* p = packet45;
+ unsigned char* p = packet46;
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
p = packet99;
- } else if (framer_.transport_version() > QUIC_VERSION_44) {
- p = packet46;
}
std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
@@ -9091,7 +8352,7 @@ TEST_P(QuicFramerTest, BuildMessagePacket) {
test::CompareCharArraysWithHexError("constructed packet", data->data(),
data->length(), AsChars(p),
- QUIC_ARRAYSIZE(packet45));
+ QUIC_ARRAYSIZE(packet46));
}
// Test that the connectivity probing packet is serialized correctly as a
@@ -9120,21 +8381,6 @@ TEST_P(QuicFramerTest, BuildConnectivityProbingPacket) {
0x00, 0x00, 0x00, 0x00
};
- unsigned char packet44[] = {
- // type (short header, 4 byte packet number)
- 0x32,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
- 0x12, 0x34, 0x56, 0x78,
-
- // frame type
- 0x07,
- // frame type (padding frame)
- 0x00,
- 0x00, 0x00, 0x00, 0x00
- };
-
unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
@@ -9171,12 +8417,9 @@ TEST_P(QuicFramerTest, BuildConnectivityProbingPacket) {
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
p = packet99;
packet_size = QUIC_ARRAYSIZE(packet99);
- } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ } else if (framer_.transport_version() >= QUIC_VERSION_46) {
p = packet46;
packet_size = QUIC_ARRAYSIZE(packet46);
- } else if (framer_.transport_version() > QUIC_VERSION_43) {
- p = packet44;
- packet_size = QUIC_ARRAYSIZE(packet44);
}
std::unique_ptr<char[]> buffer(new char[kMaxOutgoingPacketSize]);
@@ -9467,18 +8710,6 @@ TEST_P(QuicFramerTest, BuildMtuDiscoveryPacket) {
0x07,
};
- unsigned char packet44[] = {
- // type (short header, 4 byte packet number)
- 0x32,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
- 0x12, 0x34, 0x56, 0x78,
-
- // frame type
- 0x07,
- };
-
unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
@@ -9510,15 +8741,13 @@ TEST_P(QuicFramerTest, BuildMtuDiscoveryPacket) {
unsigned char* p = packet;
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
p = packet99;
- } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ } else if (framer_.transport_version() >= QUIC_VERSION_46) {
p = packet46;
- } else if (framer_.transport_version() > QUIC_VERSION_43) {
- p = packet44;
}
test::CompareCharArraysWithHexError(
"constructed packet", data->data(), data->length(), AsChars(p),
- framer_.transport_version() > QUIC_VERSION_43 ? QUIC_ARRAYSIZE(packet44)
+ framer_.transport_version() > QUIC_VERSION_43 ? QUIC_ARRAYSIZE(packet46)
: QUIC_ARRAYSIZE(packet));
}
@@ -9689,7 +8918,7 @@ TEST_P(QuicFramerTest, BuildPublicResetPacketWithEndpointId) {
TEST_P(QuicFramerTest, BuildIetfStatelessResetPacket) {
// clang-format off
- unsigned char packet44[] = {
+ unsigned char packet[] = {
// type (short header, 1 byte packet number)
0x70,
// random packet number
@@ -9706,7 +8935,7 @@ TEST_P(QuicFramerTest, BuildIetfStatelessResetPacket) {
ASSERT_TRUE(data != nullptr);
// Skip packet number byte which is random in stateless reset packet.
test::CompareCharArraysWithHexError("constructed packet", data->data(), 1,
- AsChars(packet44), 1);
+ AsChars(packet), 1);
const size_t random_bytes_length =
data->length() - kPacketHeaderTypeSize - sizeof(kTestStatelessResetToken);
EXPECT_EQ(kMinRandomBytesLengthInStatelessReset, random_bytes_length);
@@ -9715,7 +8944,7 @@ TEST_P(QuicFramerTest, BuildIetfStatelessResetPacket) {
"constructed packet",
data->data() + data->length() - sizeof(kTestStatelessResetToken),
sizeof(kTestStatelessResetToken),
- AsChars(packet44) + QUIC_ARRAYSIZE(packet44) -
+ AsChars(packet) + QUIC_ARRAYSIZE(packet) -
sizeof(kTestStatelessResetToken),
sizeof(kTestStatelessResetToken));
}
@@ -9738,21 +8967,6 @@ TEST_P(QuicFramerTest, EncryptPacket) {
'm', 'n', 'o', 'p',
};
- unsigned char packet44[] = {
- // type (short header, 4 byte packet number)
- 0x32,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
- 0x12, 0x34, 0x56, 0x78,
-
- // redundancy
- 'a', 'b', 'c', 'd',
- 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l',
- 'm', 'n', 'o', 'p',
- };
-
unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
@@ -9790,10 +9004,8 @@ TEST_P(QuicFramerTest, EncryptPacket) {
if (framer_.transport_version() == QUIC_VERSION_99) {
p = packet99;
p_size = QUIC_ARRAYSIZE(packet99);
- } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ } else if (framer_.transport_version() >= QUIC_VERSION_46) {
p = packet46;
- } else if (framer_.transport_version() > QUIC_VERSION_43) {
- p = packet44;
}
std::unique_ptr<QuicPacket> raw(new QuicPacket(
@@ -9830,25 +9042,6 @@ TEST_P(QuicFramerTest, EncryptPacketWithVersionFlag) {
'm', 'n', 'o', 'p',
};
- unsigned char packet44[] = {
- // type (long header with packet type ZERO_RTT_PROTECTED)
- 0xFC,
- // version tag
- 'Q', '.', '1', '0',
- // connection_id length
- 0x50,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
- 0x12, 0x34, 0x56, 0x78,
-
- // redundancy
- 'a', 'b', 'c', 'd',
- 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l',
- 'm', 'n', 'o', 'p',
- };
-
unsigned char packet46[] = {
// type (long header with packet type ZERO_RTT_PROTECTED)
0xD3,
@@ -9873,10 +9066,12 @@ TEST_P(QuicFramerTest, EncryptPacketWithVersionFlag) {
0xD3,
// version tag
'Q', '.', '1', '0',
- // connection_id length
- 0x50,
- // connection_id
+ // destination connection ID length
+ 0x08,
+ // destination connection ID
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // source connection ID length
+ 0x00,
// packet number
0x12, 0x34, 0x56, 0x78,
@@ -9895,12 +9090,9 @@ TEST_P(QuicFramerTest, EncryptPacketWithVersionFlag) {
if (framer_.transport_version() == QUIC_VERSION_99) {
p = packet99;
p_size = QUIC_ARRAYSIZE(packet99);
- } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ } else if (framer_.transport_version() >= QUIC_VERSION_46) {
p = packet46;
p_size = QUIC_ARRAYSIZE(packet46);
- } else if (framer_.transport_version() > QUIC_VERSION_43) {
- p = packet44;
- p_size = QUIC_ARRAYSIZE(packet44);
}
std::unique_ptr<QuicPacket> raw(new QuicPacket(
@@ -10083,43 +9275,6 @@ TEST_P(QuicFramerTest, StopPacketProcessing) {
0x9A, 0xBE,
};
- unsigned char packet44[] = {
- // type (short header, 4 byte packet number)
- 0x32,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
- 0x12, 0x34, 0x56, 0x78,
-
- // frame type (stream frame with fin)
- 0xFF,
- // stream id
- 0x01, 0x02, 0x03, 0x04,
- // offset
- 0x3A, 0x98, 0xFE, 0xDC,
- 0x32, 0x10, 0x76, 0x54,
- // data length
- 0x00, 0x0c,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!',
-
- // frame type (ack frame)
- 0x40,
- // least packet number awaiting an ack
- 0x12, 0x34, 0x56, 0x78,
- 0x9A, 0xA0,
- // largest observed packet number
- 0x12, 0x34, 0x56, 0x78,
- 0x9A, 0xBF,
- // num missing packets
- 0x01,
- // missing packet
- 0x12, 0x34, 0x56, 0x78,
- 0x9A, 0xBE,
- };
-
unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
@@ -10211,12 +9366,9 @@ TEST_P(QuicFramerTest, StopPacketProcessing) {
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
p = packet99;
p_size = QUIC_ARRAYSIZE(packet99);
- } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ } else if (framer_.transport_version() >= QUIC_VERSION_46) {
p = packet46;
p_size = QUIC_ARRAYSIZE(packet46);
- } else if (framer_.transport_version() > QUIC_VERSION_43) {
- p = packet44;
- p_size = QUIC_ARRAYSIZE(packet44);
}
QuicEncryptedPacket encrypted(AsChars(p), p_size, false);
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
@@ -11415,11 +10567,16 @@ TEST_P(QuicFramerTest, InvalidLongNewConnectionIdFrame) {
{"Unable to read new connection ID frame retire_prior_to.",
{kVarInt62OneByte + 0x0b}},
{"Unable to read new connection ID frame connection id.",
- {0x13}}, // connection ID length
+ {0x40}}, // connection ID length
{"Unable to read new connection ID frame connection id.",
{0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
0xF0, 0xD2, 0xB4, 0x96, 0x78, 0x5A, 0x3C, 0x1E,
- 0x42, 0x33, 0x42}},
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ 0xF0, 0xD2, 0xB4, 0x96, 0x78, 0x5A, 0x3C, 0x1E,
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ 0xF0, 0xD2, 0xB4, 0x96, 0x78, 0x5A, 0x3C, 0x1E,
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ 0xF0, 0xD2, 0xB4, 0x96, 0x78, 0x5A, 0x3C, 0x1E}},
{"Can not read new connection ID frame reset token.",
{0xb5, 0x69, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}
@@ -12710,26 +11867,6 @@ TEST_P(QuicFramerTest, AckFrameWithInvalidLargestObserved) {
0x00
};
- unsigned char packet44[] = {
- // type (short header, 4 byte packet number)
- 0x32,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
- 0x12, 0x34, 0x56, 0x78,
-
- // frame type (ack frame)
- 0x45,
- // largest observed
- 0x00, 0x00,
- // Zero delta time.
- 0x00, 0x00,
- // first ack block length.
- 0x00, 0x00,
- // num timestamps.
- 0x00
- };
-
unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
@@ -12776,11 +11913,8 @@ TEST_P(QuicFramerTest, AckFrameWithInvalidLargestObserved) {
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
p = packet99;
p_size = QUIC_ARRAYSIZE(packet99);
- } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ } else if (framer_.transport_version() >= QUIC_VERSION_46) {
p = packet46;
- } else if (framer_.transport_version() > QUIC_VERSION_43) {
- p = packet44;
- p_size = QUIC_ARRAYSIZE(packet44);
}
QuicEncryptedPacket encrypted(AsChars(p), p_size, false);
@@ -12811,26 +11945,6 @@ TEST_P(QuicFramerTest, FirstAckBlockJustUnderFlow) {
0x00
};
- unsigned char packet44[] = {
- // type (short header, 4 byte packet number)
- 0x32,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
- 0x12, 0x34, 0x56, 0x78,
-
- // frame type (ack frame)
- 0x45,
- // largest observed
- 0x00, 0x02,
- // Zero delta time.
- 0x00, 0x00,
- // first ack block length.
- 0x00, 0x03,
- // num timestamps.
- 0x00
- };
-
unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
@@ -12877,12 +11991,9 @@ TEST_P(QuicFramerTest, FirstAckBlockJustUnderFlow) {
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
p = packet99;
p_size = QUIC_ARRAYSIZE(packet99);
- } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ } else if (framer_.transport_version() >= QUIC_VERSION_46) {
p = packet46;
p_size = QUIC_ARRAYSIZE(packet46);
- } else if (framer_.transport_version() > QUIC_VERSION_43) {
- p = packet44;
- p_size = QUIC_ARRAYSIZE(packet44);
}
QuicEncryptedPacket encrypted(AsChars(p), p_size, false);
@@ -12924,36 +12035,6 @@ TEST_P(QuicFramerTest, ThirdAckBlockJustUnderflow) {
0x00
};
- unsigned char packet44[] = {
- // type (short header, 4 byte packet number)
- 0x32,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
- 0x12, 0x34, 0x56, 0x78,
-
- // frame type (ack frame)
- 0x60,
- // largest observed
- 0x0A,
- // Zero delta time.
- 0x00, 0x00,
- // Num of ack blocks
- 0x02,
- // first ack block length.
- 0x02,
- // gap to next block
- 0x01,
- // ack block length
- 0x01,
- // gap to next block
- 0x01,
- // ack block length
- 0x06,
- // num timestamps.
- 0x00
- };
-
unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
@@ -13018,12 +12099,9 @@ TEST_P(QuicFramerTest, ThirdAckBlockJustUnderflow) {
if (VersionHasIetfQuicFrames(framer_.transport_version())) {
p = packet99;
p_size = QUIC_ARRAYSIZE(packet99);
- } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ } else if (framer_.transport_version() >= QUIC_VERSION_46) {
p = packet46;
p_size = QUIC_ARRAYSIZE(packet46);
- } else if (framer_.transport_version() > QUIC_VERSION_43) {
- p = packet44;
- p_size = QUIC_ARRAYSIZE(packet44);
}
QuicEncryptedPacket encrypted(AsChars(p), p_size, false);
@@ -13051,9 +12129,11 @@ TEST_P(QuicFramerTest, CoalescedPacket) {
// version
QUIC_VERSION_BYTES,
// destination connection ID length
- 0x50,
+ 0x08,
// destination connection ID
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // source connection ID length
+ 0x00,
// long header packet length
0x1E,
// packet number
@@ -13078,9 +12158,11 @@ TEST_P(QuicFramerTest, CoalescedPacket) {
// version
QUIC_VERSION_BYTES,
// destination connection ID length
- 0x50,
+ 0x08,
// destination connection ID
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // source connection ID length
+ 0x00,
// long header packet length
0x1E,
// packet number
@@ -13132,6 +12214,340 @@ TEST_P(QuicFramerTest, CoalescedPacket) {
CheckStreamFrameData("HELLO_WORLD?", visitor_.stream_frames_[1].get());
}
+TEST_P(QuicFramerTest, UndecryptablePacketWithoutDecrypter) {
+ QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
+
+ if (!framer_.version().KnowsWhichDecrypterToUse()) {
+ // We create a bad client decrypter by using initial encryption with a
+ // bogus connection ID; it should fail to decrypt everything.
+ QuicConnectionId bogus_connection_id = TestConnectionId(0xbad);
+ CrypterPair bogus_crypters;
+ CryptoUtils::CreateTlsInitialCrypters(Perspective::IS_CLIENT,
+ framer_.transport_version(),
+ bogus_connection_id, &bogus_crypters);
+ // This removes all other decrypters.
+ framer_.SetDecrypter(ENCRYPTION_FORWARD_SECURE,
+ std::move(bogus_crypters.decrypter));
+ }
+
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (version included, 8-byte connection ID,
+ // 4-byte packet number)
+ 0x28,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // packet number
+ 0x12, 0x34, 0x56, 0x00,
+ // padding frames
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+ unsigned char packet46[] = {
+ // public flags (long header with packet type HANDSHAKE and
+ // 4-byte packet number)
+ 0xE3,
+ // version
+ QUIC_VERSION_BYTES,
+ // connection ID lengths
+ 0x05,
+ // source connection ID
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // long header packet length
+ 0x05,
+ // packet number
+ 0x12, 0x34, 0x56, 0x00,
+ // padding frames
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+ unsigned char packet99[] = {
+ // public flags (long header with packet type HANDSHAKE and
+ // 4-byte packet number)
+ 0xE3,
+ // version
+ QUIC_VERSION_BYTES,
+ // destination connection ID length
+ 0x00,
+ // source connection ID length
+ 0x08,
+ // source connection ID
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // long header packet length
+ 0x24,
+ // packet number
+ 0x12, 0x34, 0x56, 0x00,
+ // padding frames
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+ // clang-format on
+ unsigned char* p = packet;
+ size_t p_length = QUIC_ARRAYSIZE(packet);
+ if (framer_.transport_version() == QUIC_VERSION_99) {
+ p = packet99;
+ p_length = QUIC_ARRAYSIZE(packet99);
+ } else if (framer_.transport_version() >= QUIC_VERSION_46) {
+ p = packet46;
+ p_length = QUIC_ARRAYSIZE(packet46);
+ }
+ // First attempt decryption without the handshake crypter.
+ EXPECT_FALSE(
+ framer_.ProcessPacket(QuicEncryptedPacket(AsChars(p), p_length, false)));
+ EXPECT_EQ(QUIC_DECRYPTION_FAILURE, framer_.error());
+ if (GetQuicRestartFlag(quic_framer_uses_undecryptable_upcall)) {
+ ASSERT_EQ(1u, visitor_.undecryptable_packets_.size());
+ ASSERT_EQ(1u, visitor_.undecryptable_decryption_levels_.size());
+ ASSERT_EQ(1u, visitor_.undecryptable_has_decryption_keys_.size());
+ CompareCharArraysWithHexError(
+ "undecryptable packet", visitor_.undecryptable_packets_[0]->data(),
+ visitor_.undecryptable_packets_[0]->length(), AsChars(p), p_length);
+ if (framer_.version().KnowsWhichDecrypterToUse()) {
+ EXPECT_EQ(ENCRYPTION_HANDSHAKE,
+ visitor_.undecryptable_decryption_levels_[0]);
+ }
+ EXPECT_FALSE(visitor_.undecryptable_has_decryption_keys_[0]);
+ } else {
+ EXPECT_EQ(0u, visitor_.undecryptable_packets_.size());
+ EXPECT_EQ(0u, visitor_.undecryptable_decryption_levels_.size());
+ EXPECT_EQ(0u, visitor_.undecryptable_has_decryption_keys_.size());
+ }
+}
+
+TEST_P(QuicFramerTest, UndecryptablePacketWithDecrypter) {
+ QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
+
+ // We create a bad client decrypter by using initial encryption with a
+ // bogus connection ID; it should fail to decrypt everything.
+ QuicConnectionId bogus_connection_id = TestConnectionId(0xbad);
+ CrypterPair bad_handshake_crypters;
+ CryptoUtils::CreateTlsInitialCrypters(
+ Perspective::IS_CLIENT, framer_.transport_version(), bogus_connection_id,
+ &bad_handshake_crypters);
+ if (framer_.version().KnowsWhichDecrypterToUse()) {
+ framer_.InstallDecrypter(ENCRYPTION_HANDSHAKE,
+ std::move(bad_handshake_crypters.decrypter));
+ } else {
+ framer_.SetDecrypter(ENCRYPTION_HANDSHAKE,
+ std::move(bad_handshake_crypters.decrypter));
+ }
+
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (version included, 8-byte connection ID,
+ // 4-byte packet number)
+ 0x28,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // packet number
+ 0x12, 0x34, 0x56, 0x00,
+ // padding frames
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+ unsigned char packet46[] = {
+ // public flags (long header with packet type HANDSHAKE and
+ // 4-byte packet number)
+ 0xE3,
+ // version
+ QUIC_VERSION_BYTES,
+ // connection ID lengths
+ 0x05,
+ // source connection ID
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // long header packet length
+ 0x05,
+ // packet number
+ 0x12, 0x34, 0x56, 0x00,
+ // padding frames
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+ unsigned char packet99[] = {
+ // public flags (long header with packet type HANDSHAKE and
+ // 4-byte packet number)
+ 0xE3,
+ // version
+ QUIC_VERSION_BYTES,
+ // destination connection ID length
+ 0x00,
+ // source connection ID length
+ 0x08,
+ // source connection ID
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // long header packet length
+ 0x24,
+ // packet number
+ 0x12, 0x34, 0x56, 0x00,
+ // padding frames
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+ // clang-format on
+ unsigned char* p = packet;
+ size_t p_length = QUIC_ARRAYSIZE(packet);
+ if (framer_.transport_version() == QUIC_VERSION_99) {
+ p = packet99;
+ p_length = QUIC_ARRAYSIZE(packet99);
+ } else if (framer_.transport_version() >= QUIC_VERSION_46) {
+ p = packet46;
+ p_length = QUIC_ARRAYSIZE(packet46);
+ }
+
+ EXPECT_FALSE(
+ framer_.ProcessPacket(QuicEncryptedPacket(AsChars(p), p_length, false)));
+ EXPECT_EQ(QUIC_DECRYPTION_FAILURE, framer_.error());
+ if (GetQuicRestartFlag(quic_framer_uses_undecryptable_upcall)) {
+ ASSERT_EQ(1u, visitor_.undecryptable_packets_.size());
+ ASSERT_EQ(1u, visitor_.undecryptable_decryption_levels_.size());
+ ASSERT_EQ(1u, visitor_.undecryptable_has_decryption_keys_.size());
+ CompareCharArraysWithHexError(
+ "undecryptable packet", visitor_.undecryptable_packets_[0]->data(),
+ visitor_.undecryptable_packets_[0]->length(), AsChars(p), p_length);
+ if (framer_.version().KnowsWhichDecrypterToUse()) {
+ EXPECT_EQ(ENCRYPTION_HANDSHAKE,
+ visitor_.undecryptable_decryption_levels_[0]);
+ }
+ EXPECT_EQ(framer_.version().KnowsWhichDecrypterToUse(),
+ visitor_.undecryptable_has_decryption_keys_[0]);
+ } else {
+ EXPECT_EQ(0u, visitor_.undecryptable_packets_.size());
+ EXPECT_EQ(0u, visitor_.undecryptable_decryption_levels_.size());
+ EXPECT_EQ(0u, visitor_.undecryptable_has_decryption_keys_.size());
+ }
+}
+
+TEST_P(QuicFramerTest, UndecryptableCoalescedPacket) {
+ if (!QuicVersionHasLongHeaderLengths(framer_.transport_version())) {
+ return;
+ }
+ ASSERT_TRUE(framer_.version().KnowsWhichDecrypterToUse());
+ SetDecrypterLevel(ENCRYPTION_ZERO_RTT);
+ // We create a bad client decrypter by using initial encryption with a
+ // bogus connection ID; it should fail to decrypt everything.
+ QuicConnectionId bogus_connection_id = TestConnectionId(0xbad);
+ CrypterPair bad_handshake_crypters;
+ CryptoUtils::CreateTlsInitialCrypters(
+ Perspective::IS_CLIENT, framer_.transport_version(), bogus_connection_id,
+ &bad_handshake_crypters);
+ framer_.InstallDecrypter(ENCRYPTION_HANDSHAKE,
+ std::move(bad_handshake_crypters.decrypter));
+ // clang-format off
+ unsigned char packet[] = {
+ // first coalesced packet
+ // public flags (long header with packet type HANDSHAKE and
+ // 4-byte packet number)
+ 0xE3,
+ // version
+ QUIC_VERSION_BYTES,
+ // destination connection ID length
+ 0x08,
+ // destination connection ID
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // source connection ID length
+ 0x00,
+ // long header packet length
+ 0x1E,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78,
+ // frame type (IETF_STREAM frame with FIN, LEN, and OFFSET bits set)
+ 0x08 | 0x01 | 0x02 | 0x04,
+ // stream id
+ kVarInt62FourBytes + 0x00, 0x02, 0x03, 0x04,
+ // offset
+ kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC,
+ 0x32, 0x10, 0x76, 0x54,
+ // data length
+ kVarInt62OneByte + 0x0c,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ // second coalesced packet
+ // public flags (long header with packet type ZERO_RTT_PROTECTED and
+ // 4-byte packet number)
+ 0xD3,
+ // version
+ QUIC_VERSION_BYTES,
+ // destination connection ID length
+ 0x08,
+ // destination connection ID
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // source connection ID length
+ 0x00,
+ // long header packet length
+ 0x1E,
+ // packet number
+ 0x12, 0x34, 0x56, 0x79,
+ // frame type (IETF_STREAM frame with FIN, LEN, and OFFSET bits set)
+ 0x08 | 0x01 | 0x02 | 0x04,
+ // stream id
+ kVarInt62FourBytes + 0x00, 0x02, 0x03, 0x04,
+ // offset
+ kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC,
+ 0x32, 0x10, 0x76, 0x54,
+ // data length
+ kVarInt62OneByte + 0x0c,
+ // data
+ 'H', 'E', 'L', 'L',
+ 'O', '_', 'W', 'O',
+ 'R', 'L', 'D', '?',
+ };
+ // clang-format on
+ const size_t length_of_first_coalesced_packet = 46;
+
+ QuicEncryptedPacket encrypted(AsChars(packet), QUIC_ARRAYSIZE(packet), false);
+ EXPECT_FALSE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_DECRYPTION_FAILURE, framer_.error());
+
+ if (GetQuicRestartFlag(quic_framer_uses_undecryptable_upcall)) {
+ ASSERT_EQ(1u, visitor_.undecryptable_packets_.size());
+ ASSERT_EQ(1u, visitor_.undecryptable_decryption_levels_.size());
+ ASSERT_EQ(1u, visitor_.undecryptable_has_decryption_keys_.size());
+ // Make sure we only receive the first undecryptable packet and not the
+ // full packet including the second coalesced packet.
+ CompareCharArraysWithHexError(
+ "undecryptable packet", visitor_.undecryptable_packets_[0]->data(),
+ visitor_.undecryptable_packets_[0]->length(), AsChars(packet),
+ length_of_first_coalesced_packet);
+ EXPECT_EQ(ENCRYPTION_HANDSHAKE,
+ visitor_.undecryptable_decryption_levels_[0]);
+ EXPECT_TRUE(visitor_.undecryptable_has_decryption_keys_[0]);
+ } else {
+ EXPECT_EQ(0u, visitor_.undecryptable_packets_.size());
+ EXPECT_EQ(0u, visitor_.undecryptable_decryption_levels_.size());
+ EXPECT_EQ(0u, visitor_.undecryptable_has_decryption_keys_.size());
+ }
+
+ // Make sure the second coalesced packet is parsed correctly.
+ ASSERT_EQ(visitor_.coalesced_packets_.size(), 1u);
+ EXPECT_TRUE(framer_.ProcessPacket(*visitor_.coalesced_packets_[0].get()));
+
+ ASSERT_TRUE(visitor_.header_.get());
+
+ ASSERT_EQ(1u, visitor_.stream_frames_.size());
+ EXPECT_EQ(0u, visitor_.ack_frames_.size());
+
+ // Stream ID should be the last 3 bytes of kStreamId.
+ EXPECT_EQ(0x00FFFFFF & kStreamId, visitor_.stream_frames_[0]->stream_id);
+ EXPECT_TRUE(visitor_.stream_frames_[0]->fin);
+ EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset);
+ CheckStreamFrameData("HELLO_WORLD?", visitor_.stream_frames_[0].get());
+}
+
TEST_P(QuicFramerTest, MismatchedCoalescedPacket) {
if (!QuicVersionHasLongHeaderLengths(framer_.transport_version())) {
return;
@@ -13146,9 +12562,11 @@ TEST_P(QuicFramerTest, MismatchedCoalescedPacket) {
// version
QUIC_VERSION_BYTES,
// destination connection ID length
- 0x50,
+ 0x08,
// destination connection ID
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // source connection ID length
+ 0x00,
// long header packet length
0x1E,
// packet number
@@ -13173,9 +12591,11 @@ TEST_P(QuicFramerTest, MismatchedCoalescedPacket) {
// version
QUIC_VERSION_BYTES,
// destination connection ID length
- 0x50,
+ 0x08,
// destination connection ID
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x11,
+ // source connection ID length
+ 0x00,
// long header packet length
0x1E,
// packet number
@@ -13229,9 +12649,11 @@ TEST_P(QuicFramerTest, InvalidCoalescedPacket) {
// version
QUIC_VERSION_BYTES,
// destination connection ID length
- 0x50,
+ 0x08,
// destination connection ID
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // source connection ID length
+ 0x00,
// long header packet length
0x1E,
// packet number
@@ -13327,11 +12749,12 @@ TEST_P(QuicFramerTest, CoalescedPacketWithZeroesRoundTrip) {
// Make sure we discard the subsequent zeroes.
EXPECT_QUIC_PEER_BUG(EXPECT_TRUE(framer_.ProcessPacket(encrypted)),
- "Server: Received mismatched coalesced header.*");
+ "Server: (Failed to parse received|Received mismatched) "
+ "coalesced header.*");
}
TEST_P(QuicFramerTest, ClientReceivesInvalidVersion) {
- if (framer_.transport_version() < QUIC_VERSION_44) {
+ if (framer_.transport_version() <= QUIC_VERSION_43) {
return;
}
QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
@@ -13339,7 +12762,7 @@ TEST_P(QuicFramerTest, ClientReceivesInvalidVersion) {
// clang-format off
unsigned char packet[] = {
// public flags (long header with packet type INITIAL)
- 0xFF,
+ 0xC3,
// version that is different from the framer's version
'Q', '0', '4', '3',
// connection ID lengths
@@ -13361,7 +12784,8 @@ TEST_P(QuicFramerTest, ClientReceivesInvalidVersion) {
}
TEST_P(QuicFramerTest, PacketHeaderWithVariableLengthConnectionId) {
- if (framer_.transport_version() < QUIC_VERSION_46) {
+ if (!QuicUtils::VariableLengthConnectionIdAllowedForVersion(
+ framer_.transport_version())) {
return;
}
SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
@@ -13376,10 +12800,10 @@ TEST_P(QuicFramerTest, PacketHeaderWithVariableLengthConnectionId) {
// clang-format off
PacketFragments packet = {
// type (8 byte connection_id and 1 byte packet number)
- {"Unable to read type.",
+ {"Unable to read first byte.",
{0x40}},
// connection_id
- {"Unable to read Destination ConnectionId.",
+ {"Unable to read destination connection ID.",
{0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, 0x42}},
// packet number
{"Unable to read packet number.",
@@ -13388,10 +12812,10 @@ TEST_P(QuicFramerTest, PacketHeaderWithVariableLengthConnectionId) {
PacketFragments packet_with_padding = {
// type (8 byte connection_id and 1 byte packet number)
- {"Unable to read type.",
+ {"Unable to read first byte.",
{0x40}},
// connection_id
- {"Unable to read Destination ConnectionId.",
+ {"Unable to read destination connection ID.",
{0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, 0x42}},
// packet number
{"",
@@ -13451,9 +12875,11 @@ TEST_P(QuicFramerTest, MultiplePacketNumberSpaces) {
// version
QUIC_VERSION_BYTES,
// destination connection ID length
- 0x50,
+ 0x08,
// destination connection ID
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // source connection ID length
+ 0x00,
// long header packet length
0x05,
// packet number
@@ -13533,23 +12959,9 @@ TEST_P(QuicFramerTest, IetfRetryPacketRejected) {
}
// clang-format off
- PacketFragments packet = {
- // public flags (IETF Retry packet, 0-length original destination CID)
- {"Unable to read type.",
- {0xf0}},
- // version tag
- {"Unable to read protocol version.",
- {QUIC_VERSION_BYTES}},
- // connection_id length
- {"Illegal long header type value.",
- {0x00}},
- };
- // clang-format on
-
- // clang-format off
- PacketFragments packet45 = {
+ PacketFragments packet46 = {
// public flags (IETF Retry packet, 0-length original destination CID)
- {"Unable to read type.",
+ {"Unable to read first byte.",
{0xf0}},
// version tag
{"Unable to read protocol version.",
@@ -13560,14 +12972,12 @@ TEST_P(QuicFramerTest, IetfRetryPacketRejected) {
};
// clang-format on
- PacketFragments& fragments =
- framer_.transport_version() > QUIC_VERSION_44 ? packet45 : packet;
std::unique_ptr<QuicEncryptedPacket> encrypted(
- AssemblePacketFromFragments(fragments));
+ AssemblePacketFromFragments(packet46));
EXPECT_FALSE(framer_.ProcessPacket(*encrypted));
EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, framer_.error());
- CheckFramingBoundaries(fragments, QUIC_INVALID_PACKET_HEADER);
+ CheckFramingBoundaries(packet46, QUIC_INVALID_PACKET_HEADER);
}
TEST_P(QuicFramerTest, RetryPacketRejectedWithMultiplePacketNumberSpaces) {
@@ -13580,7 +12990,7 @@ TEST_P(QuicFramerTest, RetryPacketRejectedWithMultiplePacketNumberSpaces) {
// clang-format off
PacketFragments packet = {
// public flags (IETF Retry packet, 0-length original destination CID)
- {"Unable to read type.",
+ {"Unable to read first byte.",
{0xf0}},
// version tag
{"Unable to read protocol version.",
@@ -13677,7 +13087,8 @@ TEST_P(QuicFramerTest, ProcessMismatchedHeaderVersion) {
CheckFramingBoundaries(packet, QUIC_INVALID_PACKET_HEADER);
}
-TEST_P(QuicFramerTest, WriteClientVersionNegotiationProbePacket) {
+TEST_P(QuicFramerTest, WriteClientVersionNegotiationProbePacketOld) {
+ SetQuicFlag(FLAGS_quic_prober_uses_length_prefixed_connection_ids, false);
// clang-format off
static const char expected_packet[1200] = {
// IETF long header with fixed bit set, type initial, all-0 encrypted bits.
@@ -13726,26 +13137,279 @@ TEST_P(QuicFramerTest, WriteClientVersionNegotiationProbePacket) {
EXPECT_TRUE(QuicFramer::WriteClientVersionNegotiationProbePacket(
packet, sizeof(packet), destination_connection_id_bytes,
sizeof(destination_connection_id_bytes)));
- test::CompareCharArraysWithHexError("constructed packet", expected_packet,
- sizeof(expected_packet), packet,
- sizeof(packet));
+ test::CompareCharArraysWithHexError("constructed packet", packet,
+ sizeof(packet), expected_packet,
+ sizeof(expected_packet));
QuicEncryptedPacket encrypted(reinterpret_cast<const char*>(packet),
sizeof(packet), false);
// Make sure we fail to parse this packet for the version under test.
- EXPECT_FALSE(framer_.ProcessPacket(encrypted));
if (framer_.transport_version() <= QUIC_VERSION_43) {
// We can only parse the connection ID with an IETF parser.
+ EXPECT_FALSE(framer_.ProcessPacket(encrypted));
return;
}
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
ASSERT_TRUE(visitor_.header_.get());
QuicConnectionId probe_payload_connection_id(
reinterpret_cast<const char*>(destination_connection_id_bytes),
sizeof(destination_connection_id_bytes));
EXPECT_EQ(probe_payload_connection_id,
visitor_.header_.get()->destination_connection_id);
+
+ PacketHeaderFormat format = GOOGLE_QUIC_PACKET;
+ bool version_present = false, has_length_prefix = false;
+ QuicVersionLabel version_label = 0;
+ ParsedQuicVersion parsed_version = QuicVersionReservedForNegotiation();
+ QuicConnectionId destination_connection_id = TestConnectionId(0x33);
+ QuicConnectionId source_connection_id = TestConnectionId(0x34);
+ bool retry_token_present = true;
+ QuicStringPiece retry_token;
+ std::string detailed_error = "foobar";
+
+ QuicErrorCode parse_result = QuicFramer::ParsePublicHeaderDispatcher(
+ encrypted, kQuicDefaultConnectionIdLength, &format, &version_present,
+ &has_length_prefix, &version_label, &parsed_version,
+ &destination_connection_id, &source_connection_id, &retry_token_present,
+ &retry_token, &detailed_error);
+ EXPECT_EQ(QUIC_NO_ERROR, parse_result);
+ EXPECT_EQ(IETF_QUIC_LONG_HEADER_PACKET, format);
+ EXPECT_TRUE(version_present);
+ EXPECT_FALSE(has_length_prefix);
+ EXPECT_EQ(0xcabadaba, version_label);
+ EXPECT_EQ(QUIC_VERSION_UNSUPPORTED, parsed_version.transport_version);
+ EXPECT_EQ(probe_payload_connection_id, destination_connection_id);
+ EXPECT_EQ(EmptyQuicConnectionId(), source_connection_id);
+ EXPECT_FALSE(retry_token_present);
+ EXPECT_EQ(QuicStringPiece(), retry_token);
+ EXPECT_EQ("", detailed_error);
}
-TEST_P(QuicFramerTest, ParseServerVersionNegotiationProbeResponse) {
+TEST_P(QuicFramerTest, WriteClientVersionNegotiationProbePacket) {
+ SetQuicFlag(FLAGS_quic_prober_uses_length_prefixed_connection_ids, true);
+ // clang-format off
+ static const char expected_packet[1200] = {
+ // IETF long header with fixed bit set, type initial, all-0 encrypted bits.
+ 0xc0,
+ // Version, part of the IETF space reserved for negotiation.
+ 0xca, 0xba, 0xda, 0xda,
+ // Destination connection ID length 8.
+ 0x08,
+ // 8-byte destination connection ID.
+ 0x56, 0x4e, 0x20, 0x70, 0x6c, 0x7a, 0x20, 0x21,
+ // Source connection ID length 0.
+ 0x00,
+ // 8 bytes of zeroes followed by 8 bytes of ones to ensure that this does
+ // not parse with any known version.
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ // zeroes to pad to 16 byte boundary.
+ 0x00,
+ // A polite greeting in case a human sees this in tcpdump.
+ 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x61, 0x63,
+ 0x6b, 0x65, 0x74, 0x20, 0x6f, 0x6e, 0x6c, 0x79,
+ 0x20, 0x65, 0x78, 0x69, 0x73, 0x74, 0x73, 0x20,
+ 0x74, 0x6f, 0x20, 0x74, 0x72, 0x69, 0x67, 0x67,
+ 0x65, 0x72, 0x20, 0x49, 0x45, 0x54, 0x46, 0x20,
+ 0x51, 0x55, 0x49, 0x43, 0x20, 0x76, 0x65, 0x72,
+ 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x6e, 0x65, 0x67,
+ 0x6f, 0x74, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+ 0x2e, 0x20, 0x50, 0x6c, 0x65, 0x61, 0x73, 0x65,
+ 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64,
+ 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x61, 0x20,
+ 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20,
+ 0x4e, 0x65, 0x67, 0x6f, 0x74, 0x69, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x20, 0x70, 0x61, 0x63, 0x6b,
+ 0x65, 0x74, 0x20, 0x69, 0x6e, 0x64, 0x69, 0x63,
+ 0x61, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x77, 0x68,
+ 0x61, 0x74, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69,
+ 0x6f, 0x6e, 0x73, 0x20, 0x79, 0x6f, 0x75, 0x20,
+ 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x2e,
+ 0x20, 0x54, 0x68, 0x61, 0x6e, 0x6b, 0x20, 0x79,
+ 0x6f, 0x75, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x68,
+ 0x61, 0x76, 0x65, 0x20, 0x61, 0x20, 0x6e, 0x69,
+ 0x63, 0x65, 0x20, 0x64, 0x61, 0x79, 0x2e, 0x00,
+ };
+ // clang-format on
+ char packet[1200];
+ char destination_connection_id_bytes[] = {0x56, 0x4e, 0x20, 0x70,
+ 0x6c, 0x7a, 0x20, 0x21};
+ EXPECT_TRUE(QuicFramer::WriteClientVersionNegotiationProbePacket(
+ packet, sizeof(packet), destination_connection_id_bytes,
+ sizeof(destination_connection_id_bytes)));
+ test::CompareCharArraysWithHexError("constructed packet", packet,
+ sizeof(packet), expected_packet,
+ sizeof(expected_packet));
+ QuicEncryptedPacket encrypted(reinterpret_cast<const char*>(packet),
+ sizeof(packet), false);
+ if (framer_.transport_version() < QUIC_VERSION_99) {
+ // We can only parse the connection ID with a v99 parser.
+ EXPECT_FALSE(framer_.ProcessPacket(encrypted));
+ return;
+ }
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+ ASSERT_TRUE(visitor_.header_.get());
+ QuicConnectionId probe_payload_connection_id(
+ reinterpret_cast<const char*>(destination_connection_id_bytes),
+ sizeof(destination_connection_id_bytes));
+ EXPECT_EQ(probe_payload_connection_id,
+ visitor_.header_.get()->destination_connection_id);
+}
+
+TEST_P(QuicFramerTest, DispatcherParseOldClientVersionNegotiationProbePacket) {
+ // clang-format off
+ static const char packet[1200] = {
+ // IETF long header with fixed bit set, type initial, all-0 encrypted bits.
+ 0xc0,
+ // Version, part of the IETF space reserved for negotiation.
+ 0xca, 0xba, 0xda, 0xba,
+ // Destination connection ID length 8, source connection ID length 0.
+ 0x50,
+ // 8-byte destination connection ID.
+ 0x56, 0x4e, 0x20, 0x70, 0x6c, 0x7a, 0x20, 0x21,
+ // 8 bytes of zeroes followed by 8 bytes of ones to ensure that this does
+ // not parse with any known version.
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ // 2 bytes of zeroes to pad to 16 byte boundary.
+ 0x00, 0x00,
+ // A polite greeting in case a human sees this in tcpdump.
+ 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x61, 0x63,
+ 0x6b, 0x65, 0x74, 0x20, 0x6f, 0x6e, 0x6c, 0x79,
+ 0x20, 0x65, 0x78, 0x69, 0x73, 0x74, 0x73, 0x20,
+ 0x74, 0x6f, 0x20, 0x74, 0x72, 0x69, 0x67, 0x67,
+ 0x65, 0x72, 0x20, 0x49, 0x45, 0x54, 0x46, 0x20,
+ 0x51, 0x55, 0x49, 0x43, 0x20, 0x76, 0x65, 0x72,
+ 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x6e, 0x65, 0x67,
+ 0x6f, 0x74, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+ 0x2e, 0x20, 0x50, 0x6c, 0x65, 0x61, 0x73, 0x65,
+ 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64,
+ 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x61, 0x20,
+ 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20,
+ 0x4e, 0x65, 0x67, 0x6f, 0x74, 0x69, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x20, 0x70, 0x61, 0x63, 0x6b,
+ 0x65, 0x74, 0x20, 0x69, 0x6e, 0x64, 0x69, 0x63,
+ 0x61, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x77, 0x68,
+ 0x61, 0x74, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69,
+ 0x6f, 0x6e, 0x73, 0x20, 0x79, 0x6f, 0x75, 0x20,
+ 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x2e,
+ 0x20, 0x54, 0x68, 0x61, 0x6e, 0x6b, 0x20, 0x79,
+ 0x6f, 0x75, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x68,
+ 0x61, 0x76, 0x65, 0x20, 0x61, 0x20, 0x6e, 0x69,
+ 0x63, 0x65, 0x20, 0x64, 0x61, 0x79, 0x2e, 0x00,
+ };
+ // clang-format on
+ char expected_destination_connection_id_bytes[] = {0x56, 0x4e, 0x20, 0x70,
+ 0x6c, 0x7a, 0x20, 0x21};
+ QuicConnectionId expected_destination_connection_id(
+ reinterpret_cast<const char*>(expected_destination_connection_id_bytes),
+ sizeof(expected_destination_connection_id_bytes));
+
+ QuicEncryptedPacket encrypted(reinterpret_cast<const char*>(packet),
+ sizeof(packet));
+ PacketHeaderFormat format = GOOGLE_QUIC_PACKET;
+ bool version_present = false, has_length_prefix = true;
+ QuicVersionLabel version_label = 33;
+ ParsedQuicVersion parsed_version = UnsupportedQuicVersion();
+ QuicConnectionId destination_connection_id = TestConnectionId(1);
+ QuicConnectionId source_connection_id = TestConnectionId(2);
+ bool retry_token_present = true;
+ QuicStringPiece retry_token;
+ std::string detailed_error = "foobar";
+ QuicErrorCode header_parse_result = QuicFramer::ParsePublicHeaderDispatcher(
+ encrypted, kQuicDefaultConnectionIdLength, &format, &version_present,
+ &has_length_prefix, &version_label, &parsed_version,
+ &destination_connection_id, &source_connection_id, &retry_token_present,
+ &retry_token, &detailed_error);
+ EXPECT_EQ(QUIC_NO_ERROR, header_parse_result);
+ EXPECT_EQ(IETF_QUIC_LONG_HEADER_PACKET, format);
+ EXPECT_TRUE(version_present);
+ EXPECT_FALSE(has_length_prefix);
+ EXPECT_EQ(0xcabadaba, version_label);
+ EXPECT_EQ(expected_destination_connection_id, destination_connection_id);
+ EXPECT_EQ(EmptyQuicConnectionId(), source_connection_id);
+ EXPECT_FALSE(retry_token_present);
+ EXPECT_EQ("", detailed_error);
+}
+
+TEST_P(QuicFramerTest, DispatcherParseClientVersionNegotiationProbePacket) {
+ // clang-format off
+ static const char packet[1200] = {
+ // IETF long header with fixed bit set, type initial, all-0 encrypted bits.
+ 0xc0,
+ // Version, part of the IETF space reserved for negotiation.
+ 0xca, 0xba, 0xda, 0xba,
+ // Destination connection ID length 8.
+ 0x08,
+ // 8-byte destination connection ID.
+ 0x56, 0x4e, 0x20, 0x70, 0x6c, 0x7a, 0x20, 0x21,
+ // Source connection ID length 0.
+ 0x00,
+ // 8 bytes of zeroes followed by 8 bytes of ones to ensure that this does
+ // not parse with any known version.
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ // 1 byte of zeroes to pad to 16 byte boundary.
+ 0x00,
+ // A polite greeting in case a human sees this in tcpdump.
+ 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x61, 0x63,
+ 0x6b, 0x65, 0x74, 0x20, 0x6f, 0x6e, 0x6c, 0x79,
+ 0x20, 0x65, 0x78, 0x69, 0x73, 0x74, 0x73, 0x20,
+ 0x74, 0x6f, 0x20, 0x74, 0x72, 0x69, 0x67, 0x67,
+ 0x65, 0x72, 0x20, 0x49, 0x45, 0x54, 0x46, 0x20,
+ 0x51, 0x55, 0x49, 0x43, 0x20, 0x76, 0x65, 0x72,
+ 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x6e, 0x65, 0x67,
+ 0x6f, 0x74, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+ 0x2e, 0x20, 0x50, 0x6c, 0x65, 0x61, 0x73, 0x65,
+ 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64,
+ 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x61, 0x20,
+ 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20,
+ 0x4e, 0x65, 0x67, 0x6f, 0x74, 0x69, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x20, 0x70, 0x61, 0x63, 0x6b,
+ 0x65, 0x74, 0x20, 0x69, 0x6e, 0x64, 0x69, 0x63,
+ 0x61, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x77, 0x68,
+ 0x61, 0x74, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69,
+ 0x6f, 0x6e, 0x73, 0x20, 0x79, 0x6f, 0x75, 0x20,
+ 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x2e,
+ 0x20, 0x54, 0x68, 0x61, 0x6e, 0x6b, 0x20, 0x79,
+ 0x6f, 0x75, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x68,
+ 0x61, 0x76, 0x65, 0x20, 0x61, 0x20, 0x6e, 0x69,
+ 0x63, 0x65, 0x20, 0x64, 0x61, 0x79, 0x2e, 0x00,
+ };
+ // clang-format on
+ char expected_destination_connection_id_bytes[] = {0x56, 0x4e, 0x20, 0x70,
+ 0x6c, 0x7a, 0x20, 0x21};
+ QuicConnectionId expected_destination_connection_id(
+ reinterpret_cast<const char*>(expected_destination_connection_id_bytes),
+ sizeof(expected_destination_connection_id_bytes));
+
+ QuicEncryptedPacket encrypted(reinterpret_cast<const char*>(packet),
+ sizeof(packet));
+ PacketHeaderFormat format = GOOGLE_QUIC_PACKET;
+ bool version_present = false, has_length_prefix = false;
+ QuicVersionLabel version_label = 33;
+ ParsedQuicVersion parsed_version = UnsupportedQuicVersion();
+ QuicConnectionId destination_connection_id = TestConnectionId(1);
+ QuicConnectionId source_connection_id = TestConnectionId(2);
+ bool retry_token_present = true;
+ QuicStringPiece retry_token;
+ std::string detailed_error = "foobar";
+ QuicErrorCode header_parse_result = QuicFramer::ParsePublicHeaderDispatcher(
+ encrypted, kQuicDefaultConnectionIdLength, &format, &version_present,
+ &has_length_prefix, &version_label, &parsed_version,
+ &destination_connection_id, &source_connection_id, &retry_token_present,
+ &retry_token, &detailed_error);
+ EXPECT_EQ(QUIC_NO_ERROR, header_parse_result);
+ EXPECT_EQ(IETF_QUIC_LONG_HEADER_PACKET, format);
+ EXPECT_TRUE(version_present);
+ EXPECT_TRUE(has_length_prefix);
+ EXPECT_EQ(0xcabadaba, version_label);
+ EXPECT_EQ(expected_destination_connection_id, destination_connection_id);
+ EXPECT_EQ(EmptyQuicConnectionId(), source_connection_id);
+ EXPECT_EQ("", detailed_error);
+}
+
+TEST_P(QuicFramerTest, ParseServerVersionNegotiationProbeResponseOld) {
+ SetQuicFlag(FLAGS_quic_prober_uses_length_prefixed_connection_ids, false);
// clang-format off
const char packet[] = {
// IETF long header with fixed bit set, type initial, all-0 encrypted bits.
@@ -13762,7 +13426,71 @@ TEST_P(QuicFramerTest, ParseServerVersionNegotiationProbeResponse) {
};
// clang-format on
char probe_payload_bytes[] = {0x56, 0x4e, 0x20, 0x70, 0x6c, 0x7a, 0x20, 0x21};
- char parsed_probe_payload_bytes[kQuicMaxConnectionIdLength] = {};
+ char parsed_probe_payload_bytes[255] = {};
+ uint8_t parsed_probe_payload_length = 0;
+ std::string parse_detailed_error = "";
+ EXPECT_TRUE(QuicFramer::ParseServerVersionNegotiationProbeResponse(
+ reinterpret_cast<const char*>(packet), sizeof(packet),
+ reinterpret_cast<char*>(parsed_probe_payload_bytes),
+ &parsed_probe_payload_length, &parse_detailed_error));
+ EXPECT_EQ("", parse_detailed_error);
+ test::CompareCharArraysWithHexError(
+ "parsed probe", parsed_probe_payload_bytes, parsed_probe_payload_length,
+ probe_payload_bytes, sizeof(probe_payload_bytes));
+}
+
+TEST_P(QuicFramerTest, ParseServerVersionNegotiationProbeResponse) {
+ SetQuicFlag(FLAGS_quic_prober_uses_length_prefixed_connection_ids, true);
+ // clang-format off
+ const char packet[] = {
+ // IETF long header with fixed bit set, type initial, all-0 encrypted bits.
+ 0xc0,
+ // Version of 0, indicating version negotiation.
+ 0x00, 0x00, 0x00, 0x00,
+ // Destination connection ID length 0, source connection ID length 8.
+ 0x00, 0x08,
+ // 8-byte source connection ID.
+ 0x56, 0x4e, 0x20, 0x70, 0x6c, 0x7a, 0x20, 0x21,
+ // A few supported versions.
+ 0xaa, 0xaa, 0xaa, 0xaa,
+ QUIC_VERSION_BYTES,
+ };
+ // clang-format on
+ char probe_payload_bytes[] = {0x56, 0x4e, 0x20, 0x70, 0x6c, 0x7a, 0x20, 0x21};
+ char parsed_probe_payload_bytes[255] = {};
+ uint8_t parsed_probe_payload_length = 0;
+ std::string parse_detailed_error = "";
+ EXPECT_TRUE(QuicFramer::ParseServerVersionNegotiationProbeResponse(
+ reinterpret_cast<const char*>(packet), sizeof(packet),
+ reinterpret_cast<char*>(parsed_probe_payload_bytes),
+ &parsed_probe_payload_length, &parse_detailed_error));
+ EXPECT_EQ("", parse_detailed_error);
+ test::CompareCharArraysWithHexError(
+ "parsed probe", parsed_probe_payload_bytes, parsed_probe_payload_length,
+ probe_payload_bytes, sizeof(probe_payload_bytes));
+}
+
+// Test the client-side workaround for b/139330014 where an old client expects
+// no length prefix but receives a length-prefixed response.
+TEST_P(QuicFramerTest, ParseBadServerVersionNegotiationProbeResponse) {
+ SetQuicFlag(FLAGS_quic_prober_uses_length_prefixed_connection_ids, false);
+ // clang-format off
+ const char packet[] = {
+ // IETF long header with fixed bit set, type initial, all-0 encrypted bits.
+ 0xc0,
+ // Version of 0, indicating version negotiation.
+ 0x00, 0x00, 0x00, 0x00,
+ // Destination connection ID length 0, source connection ID length 8.
+ 0x00, 0x08,
+ // 8-byte source connection ID.
+ 0x56, 0x4e, 0x20, 0x70, 0x6c, 0x7a, 0x20, 0x21,
+ // A few supported versions.
+ 0xaa, 0xaa, 0xaa, 0xaa,
+ QUIC_VERSION_BYTES,
+ };
+ // clang-format on
+ char probe_payload_bytes[] = {0x56, 0x4e, 0x20, 0x70, 0x6c, 0x7a, 0x20, 0x21};
+ char parsed_probe_payload_bytes[255] = {};
uint8_t parsed_probe_payload_length = 0;
std::string parse_detailed_error = "";
EXPECT_TRUE(QuicFramer::ParseServerVersionNegotiationProbeResponse(
@@ -13771,8 +13499,8 @@ TEST_P(QuicFramerTest, ParseServerVersionNegotiationProbeResponse) {
&parsed_probe_payload_length, &parse_detailed_error));
EXPECT_EQ("", parse_detailed_error);
test::CompareCharArraysWithHexError(
- "parsed probe", probe_payload_bytes, sizeof(probe_payload_bytes),
- parsed_probe_payload_bytes, parsed_probe_payload_length);
+ "parsed probe", parsed_probe_payload_bytes, parsed_probe_payload_length,
+ probe_payload_bytes, sizeof(probe_payload_bytes));
}
TEST_P(QuicFramerTest, ClientConnectionIdFromLongHeaderToClient) {
@@ -13782,13 +13510,11 @@ TEST_P(QuicFramerTest, ClientConnectionIdFromLongHeaderToClient) {
}
SetDecrypterLevel(ENCRYPTION_HANDSHAKE);
QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
- const unsigned char type_byte =
- framer_.transport_version() == QUIC_VERSION_44 ? 0xFC : 0xE3;
// clang-format off
unsigned char packet[] = {
// public flags (long header with packet type HANDSHAKE and
// 4-byte packet number)
- type_byte,
+ 0xE3,
// version
QUIC_VERSION_BYTES,
// connection ID lengths
@@ -13802,9 +13528,34 @@ TEST_P(QuicFramerTest, ClientConnectionIdFromLongHeaderToClient) {
// padding frame
0x00,
};
+ unsigned char packet99[] = {
+ // public flags (long header with packet type HANDSHAKE and
+ // 4-byte packet number)
+ 0xE3,
+ // version
+ QUIC_VERSION_BYTES,
+ // destination connection ID length
+ 0x08,
+ // destination connection ID
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // source connection ID length
+ 0x00,
+ // long header packet length
+ 0x05,
+ // packet number
+ 0x12, 0x34, 0x56, 0x00,
+ // padding frame
+ 0x00,
+ };
// clang-format on
- const bool parse_success = framer_.ProcessPacket(
- QuicEncryptedPacket(AsChars(packet), QUIC_ARRAYSIZE(packet), false));
+ unsigned char* p = packet;
+ size_t p_length = QUIC_ARRAYSIZE(packet);
+ if (framer_.transport_version() == QUIC_VERSION_99) {
+ p = packet99;
+ p_length = QUIC_ARRAYSIZE(packet99);
+ }
+ const bool parse_success =
+ framer_.ProcessPacket(QuicEncryptedPacket(AsChars(p), p_length, false));
if (!QuicUtils::VariableLengthConnectionIdAllowedForVersion(
framer_.transport_version())) {
EXPECT_FALSE(parse_success);
@@ -13812,14 +13563,6 @@ TEST_P(QuicFramerTest, ClientConnectionIdFromLongHeaderToClient) {
EXPECT_EQ("Invalid ConnectionId length.", framer_.detailed_error());
return;
}
- if (!GetQuicRestartFlag(quic_do_not_override_connection_id)) {
- // When the flag is disabled we expect processing to fail.
- EXPECT_FALSE(parse_success);
- EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, framer_.error());
- EXPECT_EQ("Client connection ID not supported yet.",
- framer_.detailed_error());
- return;
- }
EXPECT_TRUE(parse_success);
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
EXPECT_EQ("", framer_.detailed_error());
@@ -13835,13 +13578,11 @@ TEST_P(QuicFramerTest, ClientConnectionIdFromLongHeaderToServer) {
}
SetDecrypterLevel(ENCRYPTION_HANDSHAKE);
QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_SERVER);
- const unsigned char type_byte =
- framer_.transport_version() == QUIC_VERSION_44 ? 0xFC : 0xE3;
// clang-format off
unsigned char packet[] = {
// public flags (long header with packet type HANDSHAKE and
// 4-byte packet number)
- type_byte,
+ 0xE3,
// version
QUIC_VERSION_BYTES,
// connection ID lengths
@@ -13855,9 +13596,32 @@ TEST_P(QuicFramerTest, ClientConnectionIdFromLongHeaderToServer) {
// padding frame
0x00,
};
+ unsigned char packet99[] = {
+ // public flags (long header with packet type HANDSHAKE and
+ // 4-byte packet number)
+ 0xE3,
+ // version
+ QUIC_VERSION_BYTES,
+ // connection ID lengths
+ 0x00, 0x08,
+ // source connection ID
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // long header packet length
+ 0x05,
+ // packet number
+ 0x12, 0x34, 0x56, 0x00,
+ // padding frame
+ 0x00,
+ };
// clang-format on
- const bool parse_success = framer_.ProcessPacket(
- QuicEncryptedPacket(AsChars(packet), QUIC_ARRAYSIZE(packet), false));
+ unsigned char* p = packet;
+ size_t p_length = QUIC_ARRAYSIZE(packet);
+ if (framer_.transport_version() == QUIC_VERSION_99) {
+ p = packet99;
+ p_length = QUIC_ARRAYSIZE(packet99);
+ }
+ const bool parse_success =
+ framer_.ProcessPacket(QuicEncryptedPacket(AsChars(p), p_length, false));
if (!QuicUtils::VariableLengthConnectionIdAllowedForVersion(
framer_.transport_version())) {
EXPECT_FALSE(parse_success);
@@ -13865,8 +13629,7 @@ TEST_P(QuicFramerTest, ClientConnectionIdFromLongHeaderToServer) {
EXPECT_EQ("Invalid ConnectionId length.", framer_.detailed_error());
return;
}
- if (!framer_.version().SupportsClientConnectionIds() &&
- GetQuicRestartFlag(quic_do_not_override_connection_id)) {
+ if (!framer_.version().SupportsClientConnectionIds()) {
EXPECT_FALSE(parse_success);
EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, framer_.error());
EXPECT_EQ("Client connection ID not supported in this version.",
@@ -13957,6 +13720,87 @@ TEST_P(QuicFramerTest, ProcessAndValidateIetfConnectionIdLengthServer) {
EXPECT_EQ("", detailed_error);
}
+TEST_P(QuicFramerTest, TestExtendedErrorCodeParser) {
+ if (VersionHasIetfQuicFrames(framer_.transport_version())) {
+ return;
+ }
+ QuicConnectionCloseFrame frame;
+
+ frame.error_details = "this has no error code info in it";
+ MaybeExtractQuicErrorCode(&frame);
+ EXPECT_EQ(QUIC_IETF_GQUIC_ERROR_MISSING, frame.extracted_error_code);
+ EXPECT_EQ("this has no error code info in it", frame.error_details);
+
+ frame.error_details = "1234this does not have the colon in it";
+ MaybeExtractQuicErrorCode(&frame);
+ EXPECT_EQ(QUIC_IETF_GQUIC_ERROR_MISSING, frame.extracted_error_code);
+ EXPECT_EQ("1234this does not have the colon in it", frame.error_details);
+
+ frame.error_details = "1a234:this has a colon, but a malformed error number";
+ MaybeExtractQuicErrorCode(&frame);
+ EXPECT_EQ(QUIC_IETF_GQUIC_ERROR_MISSING, frame.extracted_error_code);
+ EXPECT_EQ("1a234:this has a colon, but a malformed error number",
+ frame.error_details);
+
+ frame.error_details = "1234:this is good";
+ MaybeExtractQuicErrorCode(&frame);
+ EXPECT_EQ(1234u, frame.extracted_error_code);
+ EXPECT_EQ("this is good", frame.error_details);
+
+ frame.error_details =
+ "1234 :this is not good, space between last digit and colon";
+ MaybeExtractQuicErrorCode(&frame);
+ EXPECT_EQ(QUIC_IETF_GQUIC_ERROR_MISSING, frame.extracted_error_code);
+ EXPECT_EQ("1234 :this is not good, space between last digit and colon",
+ frame.error_details);
+
+ frame.error_details = "123456789";
+ MaybeExtractQuicErrorCode(&frame);
+ EXPECT_EQ(QUIC_IETF_GQUIC_ERROR_MISSING,
+ frame.extracted_error_code); // Not good, all numbers, no :
+ EXPECT_EQ("123456789", frame.error_details);
+
+ frame.error_details = "1234:";
+ MaybeExtractQuicErrorCode(&frame);
+ EXPECT_EQ(1234u,
+ frame.extracted_error_code); // corner case.
+ EXPECT_EQ("", frame.error_details);
+
+ frame.error_details = "1234:5678";
+ MaybeExtractQuicErrorCode(&frame);
+ EXPECT_EQ(1234u,
+ frame.extracted_error_code); // another corner case.
+ EXPECT_EQ("5678", frame.error_details);
+
+ frame.error_details = "12345 6789:";
+ MaybeExtractQuicErrorCode(&frame);
+ EXPECT_EQ(QUIC_IETF_GQUIC_ERROR_MISSING,
+ frame.extracted_error_code); // Not good
+ EXPECT_EQ("12345 6789:", frame.error_details);
+
+ frame.error_details = ":no numbers, is not good";
+ MaybeExtractQuicErrorCode(&frame);
+ EXPECT_EQ(QUIC_IETF_GQUIC_ERROR_MISSING, frame.extracted_error_code);
+ EXPECT_EQ(":no numbers, is not good", frame.error_details);
+
+ frame.error_details = "qwer:also no numbers, is not good";
+ MaybeExtractQuicErrorCode(&frame);
+ EXPECT_EQ(QUIC_IETF_GQUIC_ERROR_MISSING, frame.extracted_error_code);
+ EXPECT_EQ("qwer:also no numbers, is not good", frame.error_details);
+
+ frame.error_details = " 1234:this is not good, space before first digit";
+ MaybeExtractQuicErrorCode(&frame);
+ EXPECT_EQ(QUIC_IETF_GQUIC_ERROR_MISSING, frame.extracted_error_code);
+ EXPECT_EQ(" 1234:this is not good, space before first digit",
+ frame.error_details);
+
+ frame.error_details = "1234:";
+ MaybeExtractQuicErrorCode(&frame);
+ EXPECT_EQ(1234u,
+ frame.extracted_error_code); // this is good
+ EXPECT_EQ("", frame.error_details);
+}
+
} // namespace
} // namespace test
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_ietf_framer_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_ietf_framer_test.cc
index dbbacdd8ddc..9a2b562a821 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_ietf_framer_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_ietf_framer_test.cc
@@ -102,7 +102,7 @@ class TestQuicVisitor : public QuicFramerVisitorInterface {
bool OnProtocolVersionMismatch(
ParsedQuicVersion /*received_version*/) override {
- return true;
+ return false;
}
bool OnUnauthenticatedPublicHeader(
@@ -122,6 +122,10 @@ class TestQuicVisitor : public QuicFramerVisitorInterface {
void OnCoalescedPacket(const QuicEncryptedPacket& /*packet*/) override {}
+ void OnUndecryptablePacket(const QuicEncryptedPacket& /*packet*/,
+ EncryptionLevel /*decryption_level*/,
+ bool /*has_decryption_key*/) override {}
+
bool OnStreamFrame(const QuicStreamFrame& /*frame*/) override { return true; }
bool OnCryptoFrame(const QuicCryptoFrame& /*frame*/) override { return true; }
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 a8d32918b5a..70d5ccb0459 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
@@ -640,12 +640,13 @@ void QuicPacketCreator::SerializePacket(char* encrypted_buffer,
std::unique_ptr<QuicEncryptedPacket>
QuicPacketCreator::SerializeVersionNegotiationPacket(
bool ietf_quic,
+ bool use_length_prefix,
const ParsedQuicVersionVector& supported_versions) {
DCHECK_EQ(Perspective::IS_SERVER, framer_->perspective());
std::unique_ptr<QuicEncryptedPacket> encrypted =
- QuicFramer::BuildVersionNegotiationPacket(server_connection_id_,
- client_connection_id_,
- ietf_quic, supported_versions);
+ QuicFramer::BuildVersionNegotiationPacket(
+ server_connection_id_, client_connection_id_, ietf_quic,
+ use_length_prefix, supported_versions);
DCHECK(encrypted);
DCHECK_GE(max_packet_length_, encrypted->length());
return encrypted;
@@ -761,10 +762,6 @@ SerializedPacket QuicPacketCreator::NoPacket() {
}
QuicConnectionId QuicPacketCreator::GetDestinationConnectionId() const {
- if (!GetQuicRestartFlag(quic_do_not_override_connection_id)) {
- return server_connection_id_;
- }
- QUIC_RESTART_FLAG_COUNT_N(quic_do_not_override_connection_id, 1, 7);
if (framer_->perspective() == Perspective::IS_SERVER) {
return client_connection_id_;
}
@@ -772,10 +769,6 @@ QuicConnectionId QuicPacketCreator::GetDestinationConnectionId() const {
}
QuicConnectionId QuicPacketCreator::GetSourceConnectionId() const {
- if (!GetQuicRestartFlag(quic_do_not_override_connection_id)) {
- return server_connection_id_;
- }
- QUIC_RESTART_FLAG_COUNT_N(quic_do_not_override_connection_id, 6, 7);
if (framer_->perspective() == Perspective::IS_CLIENT) {
return client_connection_id_;
}
@@ -784,16 +777,12 @@ QuicConnectionId QuicPacketCreator::GetSourceConnectionId() const {
QuicConnectionIdIncluded QuicPacketCreator::GetDestinationConnectionIdIncluded()
const {
- if (VersionHasIetfInvariantHeader(framer_->transport_version()) ||
- GetQuicRestartFlag(quic_do_not_override_connection_id)) {
- // In versions that do not support client connection IDs, the destination
- // connection ID is only sent from client to server.
- return (framer_->perspective() == Perspective::IS_CLIENT ||
- framer_->version().SupportsClientConnectionIds())
- ? CONNECTION_ID_PRESENT
- : CONNECTION_ID_ABSENT;
- }
- return server_connection_id_included_;
+ // In versions that do not support client connection IDs, the destination
+ // connection ID is only sent from client to server.
+ return (framer_->perspective() == Perspective::IS_CLIENT ||
+ framer_->version().SupportsClientConnectionIds())
+ ? CONNECTION_ID_PRESENT
+ : CONNECTION_ID_ABSENT;
}
QuicConnectionIdIncluded QuicPacketCreator::GetSourceConnectionIdIncluded()
@@ -806,9 +795,7 @@ QuicConnectionIdIncluded QuicPacketCreator::GetSourceConnectionIdIncluded()
framer_->version().SupportsClientConnectionIds())) {
return CONNECTION_ID_PRESENT;
}
- if (GetQuicRestartFlag(quic_do_not_override_connection_id) &&
- framer_->perspective() == Perspective::IS_SERVER) {
- QUIC_RESTART_FLAG_COUNT_N(quic_do_not_override_connection_id, 2, 7);
+ if (framer_->perspective() == Perspective::IS_SERVER) {
return server_connection_id_included_;
}
return CONNECTION_ID_ABSENT;
@@ -1068,8 +1055,6 @@ void QuicPacketCreator::SetClientConnectionId(
QuicConnectionId client_connection_id) {
DCHECK(client_connection_id.IsEmpty() ||
framer_->version().SupportsClientConnectionIds());
- DCHECK(client_connection_id.IsEmpty() ||
- GetQuicRestartFlag(quic_do_not_override_connection_id));
client_connection_id_ = client_connection_id;
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.h b/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.h
index 2c2fffb12fb..affc15c894f 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.h
@@ -187,6 +187,7 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator {
// Creates a version negotiation packet which supports |supported_versions|.
std::unique_ptr<QuicEncryptedPacket> SerializeVersionNegotiationPacket(
bool ietf_quic,
+ bool use_length_prefix,
const ParsedQuicVersionVector& supported_versions);
// Creates a connectivity probing packet for versions prior to version 99.
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 802c07b4ee6..ff9960f7d4b 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
@@ -813,8 +813,11 @@ TEST_P(QuicPacketCreatorTest, SerializeVersionNegotiationPacket) {
versions.push_back(test::QuicVersionMax());
const bool ietf_quic =
VersionHasIetfInvariantHeader(GetParam().version.transport_version);
+ const bool has_length_prefix =
+ GetParam().version.HasLengthPrefixedConnectionIds();
std::unique_ptr<QuicEncryptedPacket> encrypted(
- creator_.SerializeVersionNegotiationPacket(ietf_quic, versions));
+ creator_.SerializeVersionNegotiationPacket(ietf_quic, has_length_prefix,
+ versions));
{
InSequence s;
@@ -1820,6 +1823,9 @@ TEST_P(QuicPacketCreatorTest, GetGuaranteedLargestMessagePayload) {
if (QuicVersionHasLongHeaderLengths(version)) {
expected_largest_payload -= 2;
}
+ if (GetParam().version.HasLengthPrefixedConnectionIds()) {
+ expected_largest_payload -= 1;
+ }
EXPECT_EQ(expected_largest_payload,
creator_.GetGuaranteedLargestMessagePayload());
}
@@ -1920,17 +1926,11 @@ TEST_P(QuicPacketCreatorTest, RetryToken) {
}
TEST_P(QuicPacketCreatorTest, GetConnectionId) {
- if (!GetQuicRestartFlag(quic_do_not_override_connection_id)) {
- EXPECT_EQ(TestConnectionId(2), creator_.GetDestinationConnectionId());
- EXPECT_EQ(TestConnectionId(2), creator_.GetSourceConnectionId());
- return;
- }
EXPECT_EQ(TestConnectionId(2), creator_.GetDestinationConnectionId());
EXPECT_EQ(EmptyQuicConnectionId(), creator_.GetSourceConnectionId());
}
TEST_P(QuicPacketCreatorTest, ClientConnectionId) {
- SetQuicRestartFlag(quic_do_not_override_connection_id, true);
if (!client_framer_.version().SupportsClientConnectionIds()) {
return;
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packet_generator.cc b/chromium/net/third_party/quiche/src/quic/core/quic_packet_generator.cc
index fe170697f42..160222f27f4 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_packet_generator.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_packet_generator.cc
@@ -297,9 +297,10 @@ void QuicPacketGenerator::SetMaxPacketLength(QuicByteCount length) {
std::unique_ptr<QuicEncryptedPacket>
QuicPacketGenerator::SerializeVersionNegotiationPacket(
bool ietf_quic,
+ bool use_length_prefix,
const ParsedQuicVersionVector& supported_versions) {
- return packet_creator_.SerializeVersionNegotiationPacket(ietf_quic,
- supported_versions);
+ return packet_creator_.SerializeVersionNegotiationPacket(
+ ietf_quic, use_length_prefix, supported_versions);
}
OwningSerializedPacketPointer
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packet_generator.h b/chromium/net/third_party/quiche/src/quic/core/quic_packet_generator.h
index ea7da5d968c..c6902e0ad9b 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_packet_generator.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_packet_generator.h
@@ -141,6 +141,7 @@ class QUIC_EXPORT_PRIVATE QuicPacketGenerator {
// Creates a version negotiation packet which supports |supported_versions|.
std::unique_ptr<QuicEncryptedPacket> SerializeVersionNegotiationPacket(
bool ietf_quic,
+ bool use_length_prefix,
const ParsedQuicVersionVector& supported_versions);
// Creates a connectivity probing packet.
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packet_generator_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_packet_generator_test.cc
index cdb19b33373..9c2e3f3f0e3 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_packet_generator_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_packet_generator_test.cc
@@ -430,8 +430,9 @@ TEST_F(QuicPacketGeneratorTest, ConsumeData_NotWritable) {
MakeIOVector("foo", &iov_);
QuicConsumedData consumed = generator_.ConsumeData(
- QuicUtils::GetHeadersStreamId(framer_.transport_version()), &iov_, 1u,
- iov_.iov_len, 0, FIN);
+ QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
+ Perspective::IS_CLIENT),
+ &iov_, 1u, iov_.iov_len, 0, FIN);
EXPECT_EQ(0u, consumed.bytes_consumed);
EXPECT_FALSE(consumed.fin_consumed);
EXPECT_FALSE(generator_.HasPendingFrames());
@@ -443,8 +444,9 @@ TEST_F(QuicPacketGeneratorTest, ConsumeData_WritableAndShouldNotFlush) {
MakeIOVector("foo", &iov_);
QuicConsumedData consumed = generator_.ConsumeData(
- QuicUtils::GetHeadersStreamId(framer_.transport_version()), &iov_, 1u,
- iov_.iov_len, 0, FIN);
+ QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
+ Perspective::IS_CLIENT),
+ &iov_, 1u, iov_.iov_len, 0, FIN);
EXPECT_EQ(3u, consumed.bytes_consumed);
EXPECT_TRUE(consumed.fin_consumed);
EXPECT_TRUE(generator_.HasPendingFrames());
@@ -458,8 +460,9 @@ TEST_F(QuicPacketGeneratorTest, ConsumeData_WritableAndShouldFlush) {
.WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
MakeIOVector("foo", &iov_);
QuicConsumedData consumed = generator_.ConsumeData(
- QuicUtils::GetHeadersStreamId(framer_.transport_version()), &iov_, 1u,
- iov_.iov_len, 0, FIN);
+ QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
+ Perspective::IS_CLIENT),
+ &iov_, 1u, iov_.iov_len, 0, FIN);
generator_.Flush();
EXPECT_EQ(3u, consumed.bytes_consumed);
EXPECT_TRUE(consumed.fin_consumed);
@@ -564,9 +567,10 @@ TEST_F(QuicPacketGeneratorTest, ConsumeData_Handshake_PaddingDisabled) {
TEST_F(QuicPacketGeneratorTest, ConsumeData_EmptyData) {
delegate_.SetCanWriteAnything();
- EXPECT_QUIC_BUG(generator_.ConsumeData(QuicUtils::GetHeadersStreamId(
- framer_.transport_version()),
- nullptr, 0, 0, 0, NO_FIN),
+ EXPECT_QUIC_BUG(generator_.ConsumeData(
+ QuicUtils::QuicUtils::GetFirstBidirectionalStreamId(
+ framer_.transport_version(), Perspective::IS_CLIENT),
+ nullptr, 0, 0, 0, NO_FIN),
"Attempt to consume empty data without FIN.");
}
@@ -576,8 +580,9 @@ TEST_F(QuicPacketGeneratorTest,
MakeIOVector("foo", &iov_);
generator_.ConsumeData(
- QuicUtils::GetHeadersStreamId(framer_.transport_version()), &iov_, 1u,
- iov_.iov_len, 0, FIN);
+ QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
+ Perspective::IS_CLIENT),
+ &iov_, 1u, iov_.iov_len, 0, FIN);
MakeIOVector("quux", &iov_);
QuicConsumedData consumed =
generator_.ConsumeData(3, &iov_, 1u, iov_.iov_len, 3, NO_FIN);
@@ -592,12 +597,14 @@ TEST_F(QuicPacketGeneratorTest, ConsumeData_BatchOperations) {
MakeIOVector("foo", &iov_);
generator_.ConsumeData(
- QuicUtils::GetHeadersStreamId(framer_.transport_version()), &iov_, 1u,
- iov_.iov_len, 0, FIN);
+ QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
+ Perspective::IS_CLIENT),
+ &iov_, 1u, iov_.iov_len, 0, FIN);
MakeIOVector("quux", &iov_);
QuicConsumedData consumed = generator_.ConsumeData(
- QuicUtils::GetHeadersStreamId(framer_.transport_version()), &iov_, 1u,
- iov_.iov_len, 3, NO_FIN);
+ QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
+ Perspective::IS_CLIENT),
+ &iov_, 1u, iov_.iov_len, 3, NO_FIN);
EXPECT_EQ(4u, consumed.bytes_consumed);
EXPECT_FALSE(consumed.fin_consumed);
EXPECT_TRUE(generator_.HasPendingFrames());
@@ -650,8 +657,9 @@ TEST_F(QuicPacketGeneratorTest, ConsumeData_FramesPreviouslyQueued) {
// fitting.
MakeIOVector("foo", &iov_);
QuicConsumedData consumed = generator_.ConsumeData(
- QuicUtils::GetHeadersStreamId(framer_.transport_version()), &iov_, 1u,
- iov_.iov_len, 0, NO_FIN);
+ QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
+ Perspective::IS_CLIENT),
+ &iov_, 1u, iov_.iov_len, 0, NO_FIN);
EXPECT_EQ(3u, consumed.bytes_consumed);
EXPECT_FALSE(consumed.fin_consumed);
EXPECT_TRUE(generator_.HasPendingFrames());
@@ -661,8 +669,9 @@ TEST_F(QuicPacketGeneratorTest, ConsumeData_FramesPreviouslyQueued) {
// to be serialized, and it will be added to a new open packet.
MakeIOVector("bar", &iov_);
consumed = generator_.ConsumeData(
- QuicUtils::GetHeadersStreamId(framer_.transport_version()), &iov_, 1u,
- iov_.iov_len, 3, FIN);
+ QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
+ Perspective::IS_CLIENT),
+ &iov_, 1u, iov_.iov_len, 3, FIN);
EXPECT_EQ(3u, consumed.bytes_consumed);
EXPECT_TRUE(consumed.fin_consumed);
EXPECT_TRUE(generator_.HasPendingFrames());
@@ -688,8 +697,9 @@ TEST_F(QuicPacketGeneratorTest, ConsumeDataFastPath) {
EXPECT_CALL(delegate_, OnSerializedPacket(_))
.WillRepeatedly(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
QuicConsumedData consumed = generator_.ConsumeDataFastPath(
- QuicUtils::GetHeadersStreamId(framer_.transport_version()), &iov_, 1u,
- iov_.iov_len, 0, true);
+ QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
+ Perspective::IS_CLIENT),
+ &iov_, 1u, iov_.iov_len, 0, true);
EXPECT_EQ(10000u, consumed.bytes_consumed);
EXPECT_TRUE(consumed.fin_consumed);
EXPECT_FALSE(generator_.HasPendingFrames());
@@ -716,8 +726,9 @@ TEST_F(QuicPacketGeneratorTest, ConsumeDataLarge) {
EXPECT_CALL(delegate_, OnSerializedPacket(_))
.WillRepeatedly(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
QuicConsumedData consumed = generator_.ConsumeData(
- QuicUtils::GetHeadersStreamId(framer_.transport_version()), &iov_, 1u,
- iov_.iov_len, 0, FIN);
+ QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
+ Perspective::IS_CLIENT),
+ &iov_, 1u, iov_.iov_len, 0, FIN);
EXPECT_EQ(10000u, consumed.bytes_consumed);
EXPECT_TRUE(consumed.fin_consumed);
EXPECT_FALSE(generator_.HasPendingFrames());
@@ -759,8 +770,9 @@ TEST_F(QuicPacketGeneratorTest, ConsumeDataLargeSendAckFalse) {
QuicFrame(CreateRstStreamFrame()),
/*bundle_ack=*/true);
QuicConsumedData consumed = generator_.ConsumeData(
- QuicUtils::GetHeadersStreamId(framer_.transport_version()), &iov_, 1u,
- iov_.iov_len, 0, FIN);
+ QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
+ Perspective::IS_CLIENT),
+ &iov_, 1u, iov_.iov_len, 0, FIN);
generator_.Flush();
EXPECT_EQ(10000u, consumed.bytes_consumed);
@@ -789,8 +801,9 @@ TEST_F(QuicPacketGeneratorTest, ConsumeDataLargeSendAckTrue) {
EXPECT_CALL(delegate_, OnSerializedPacket(_))
.WillRepeatedly(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
QuicConsumedData consumed = generator_.ConsumeData(
- QuicUtils::GetHeadersStreamId(framer_.transport_version()), &iov_, 1u,
- iov_.iov_len, 0, FIN);
+ QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
+ Perspective::IS_CLIENT),
+ &iov_, 1u, iov_.iov_len, 0, FIN);
generator_.Flush();
EXPECT_EQ(10000u, consumed.bytes_consumed);
@@ -925,8 +938,8 @@ TEST_F(QuicPacketGeneratorTest, PacketTransmissionType) {
size_t data_len = 1324;
CreateData(data_len);
- QuicStreamId stream1_id =
- QuicUtils::GetHeadersStreamId(framer_.transport_version());
+ QuicStreamId stream1_id = QuicUtils::GetFirstBidirectionalStreamId(
+ framer_.transport_version(), Perspective::IS_CLIENT);
QuicConsumedData consumed =
generator_.ConsumeData(stream1_id, &iov_, 1u, iov_.iov_len, 0, NO_FIN);
EXPECT_EQ(data_len, consumed.bytes_consumed);
@@ -993,8 +1006,9 @@ TEST_F(QuicPacketGeneratorTest, SetMaxPacketLength_Initial) {
.WillRepeatedly(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
CreateData(data_len);
QuicConsumedData consumed = generator_.ConsumeData(
- QuicUtils::GetHeadersStreamId(framer_.transport_version()), &iov_, 1u,
- iov_.iov_len,
+ QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
+ Perspective::IS_CLIENT),
+ &iov_, 1u, iov_.iov_len,
/*offset=*/0, FIN);
EXPECT_EQ(data_len, consumed.bytes_consumed);
EXPECT_TRUE(consumed.fin_consumed);
@@ -1030,8 +1044,9 @@ TEST_F(QuicPacketGeneratorTest, SetMaxPacketLength_Middle) {
// Send two packets before packet size change.
CreateData(data_len);
QuicConsumedData consumed = generator_.ConsumeData(
- QuicUtils::GetHeadersStreamId(framer_.transport_version()), &iov_, 1u,
- iov_.iov_len,
+ QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
+ Perspective::IS_CLIENT),
+ &iov_, 1u, iov_.iov_len,
/*offset=*/0, NO_FIN);
generator_.Flush();
EXPECT_EQ(data_len, consumed.bytes_consumed);
@@ -1050,8 +1065,9 @@ TEST_F(QuicPacketGeneratorTest, SetMaxPacketLength_Middle) {
CreateData(data_len);
generator_.AttachPacketFlusher();
consumed = generator_.ConsumeData(
- QuicUtils::GetHeadersStreamId(framer_.transport_version()), &iov_, 1u,
- iov_.iov_len, data_len, FIN);
+ QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
+ Perspective::IS_CLIENT),
+ &iov_, 1u, iov_.iov_len, data_len, FIN);
generator_.Flush();
EXPECT_EQ(data_len, consumed.bytes_consumed);
EXPECT_TRUE(consumed.fin_consumed);
@@ -1080,8 +1096,9 @@ TEST_F(QuicPacketGeneratorTest, SetMaxPacketLength_MidpacketFlush) {
// should not cause packet serialization.
CreateData(first_write_len);
QuicConsumedData consumed = generator_.ConsumeData(
- QuicUtils::GetHeadersStreamId(framer_.transport_version()), &iov_, 1u,
- iov_.iov_len,
+ QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
+ Perspective::IS_CLIENT),
+ &iov_, 1u, iov_.iov_len,
/*offset=*/0, NO_FIN);
EXPECT_EQ(first_write_len, consumed.bytes_consumed);
EXPECT_FALSE(consumed.fin_consumed);
@@ -1113,8 +1130,9 @@ TEST_F(QuicPacketGeneratorTest, SetMaxPacketLength_MidpacketFlush) {
// trigger serialization of one packet, and queue another one.
CreateData(second_write_len);
consumed = generator_.ConsumeData(
- QuicUtils::GetHeadersStreamId(framer_.transport_version()), &iov_, 1u,
- iov_.iov_len,
+ QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
+ Perspective::IS_CLIENT),
+ &iov_, 1u, iov_.iov_len,
/*offset=*/first_write_len, FIN);
EXPECT_EQ(second_write_len, consumed.bytes_consumed);
EXPECT_TRUE(consumed.fin_consumed);
@@ -1201,8 +1219,9 @@ TEST_F(QuicPacketGeneratorTest, GenerateMtuDiscoveryPacket_SurroundedByData) {
// Send data before the MTU probe.
CreateData(data_len);
QuicConsumedData consumed = generator_.ConsumeData(
- QuicUtils::GetHeadersStreamId(framer_.transport_version()), &iov_, 1u,
- iov_.iov_len,
+ QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
+ Perspective::IS_CLIENT),
+ &iov_, 1u, iov_.iov_len,
/*offset=*/0, NO_FIN);
generator_.Flush();
EXPECT_EQ(data_len, consumed.bytes_consumed);
@@ -1219,8 +1238,9 @@ TEST_F(QuicPacketGeneratorTest, GenerateMtuDiscoveryPacket_SurroundedByData) {
CreateData(data_len);
generator_.AttachPacketFlusher();
consumed = generator_.ConsumeData(
- QuicUtils::GetHeadersStreamId(framer_.transport_version()), &iov_, 1u,
- iov_.iov_len,
+ QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
+ Perspective::IS_CLIENT),
+ &iov_, 1u, iov_.iov_len,
/*offset=*/data_len, FIN);
generator_.Flush();
EXPECT_EQ(data_len, consumed.bytes_consumed);
@@ -1445,8 +1465,9 @@ TEST_F(QuicPacketGeneratorTest, AddMessageFrame) {
MakeIOVector("foo", &iov_);
generator_.ConsumeData(
- QuicUtils::GetHeadersStreamId(framer_.transport_version()), &iov_, 1u,
- iov_.iov_len, 0, FIN);
+ QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
+ Perspective::IS_CLIENT),
+ &iov_, 1u, iov_.iov_len, 0, FIN);
EXPECT_EQ(MESSAGE_STATUS_SUCCESS,
generator_.AddMessageFrame(
1, MakeSpan(&allocator_, "message", &storage)));
@@ -1475,7 +1496,6 @@ TEST_F(QuicPacketGeneratorTest, AddMessageFrame) {
}
TEST_F(QuicPacketGeneratorTest, ConnectionId) {
- SetQuicRestartFlag(quic_do_not_override_connection_id, true);
generator_.SetServerConnectionId(TestConnectionId(0x1337));
EXPECT_EQ(TestConnectionId(0x1337), creator_->GetDestinationConnectionId());
EXPECT_EQ(EmptyQuicConnectionId(), creator_->GetSourceConnectionId());
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packets.cc b/chromium/net/third_party/quiche/src/quic/core/quic_packets.cc
index 4887e8273ad..2d6d0c92a6d 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_packets.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_packets.cc
@@ -21,8 +21,7 @@ namespace quic {
QuicConnectionId GetServerConnectionIdAsRecipient(
const QuicPacketHeader& header,
Perspective perspective) {
- if (perspective == Perspective::IS_SERVER ||
- !GetQuicRestartFlag(quic_do_not_override_connection_id)) {
+ if (perspective == Perspective::IS_SERVER) {
return header.destination_connection_id;
}
return header.source_connection_id;
@@ -31,7 +30,6 @@ QuicConnectionId GetServerConnectionIdAsRecipient(
QuicConnectionId GetClientConnectionIdAsRecipient(
const QuicPacketHeader& header,
Perspective perspective) {
- DCHECK(GetQuicRestartFlag(quic_do_not_override_connection_id));
if (perspective == Perspective::IS_CLIENT) {
return header.destination_connection_id;
}
@@ -40,40 +38,33 @@ QuicConnectionId GetClientConnectionIdAsRecipient(
QuicConnectionId GetServerConnectionIdAsSender(const QuicPacketHeader& header,
Perspective perspective) {
- if (perspective == Perspective::IS_CLIENT ||
- !GetQuicRestartFlag(quic_do_not_override_connection_id)) {
+ if (perspective == Perspective::IS_CLIENT) {
return header.destination_connection_id;
}
- QUIC_RESTART_FLAG_COUNT_N(quic_do_not_override_connection_id, 3, 7);
return header.source_connection_id;
}
QuicConnectionIdIncluded GetServerConnectionIdIncludedAsSender(
const QuicPacketHeader& header,
Perspective perspective) {
- if (perspective == Perspective::IS_CLIENT ||
- !GetQuicRestartFlag(quic_do_not_override_connection_id)) {
+ if (perspective == Perspective::IS_CLIENT) {
return header.destination_connection_id_included;
}
- QUIC_RESTART_FLAG_COUNT_N(quic_do_not_override_connection_id, 4, 7);
return header.source_connection_id_included;
}
QuicConnectionId GetClientConnectionIdAsSender(const QuicPacketHeader& header,
Perspective perspective) {
- if (perspective == Perspective::IS_CLIENT ||
- !GetQuicRestartFlag(quic_do_not_override_connection_id)) {
+ if (perspective == Perspective::IS_CLIENT) {
return header.source_connection_id;
}
- QUIC_RESTART_FLAG_COUNT_N(quic_do_not_override_connection_id, 7, 7);
return header.destination_connection_id;
}
QuicConnectionIdIncluded GetClientConnectionIdIncludedAsSender(
const QuicPacketHeader& header,
Perspective perspective) {
- if (perspective == Perspective::IS_CLIENT ||
- !GetQuicRestartFlag(quic_do_not_override_connection_id)) {
+ if (perspective == Perspective::IS_CLIENT) {
return header.source_connection_id_included;
}
return header.destination_connection_id_included;
@@ -127,13 +118,14 @@ size_t GetPacketHeaderSize(
// Long header.
size_t size = kPacketHeaderTypeSize + kConnectionIdLengthSize +
destination_connection_id_length +
- source_connection_id_length +
- (version > QUIC_VERSION_44 ? packet_number_length
- : PACKET_4BYTE_PACKET_NUMBER) +
+ source_connection_id_length + packet_number_length +
kQuicVersionSize;
if (include_diversification_nonce) {
size += kDiversificationNonceSize;
}
+ if (VersionHasLengthPrefixedConnectionIds(version)) {
+ size += kConnectionIdLengthSize;
+ }
DCHECK(QuicVersionHasLongHeaderLengths(version) ||
!GetQuicReloadableFlag(quic_fix_get_packet_header_size) ||
retry_token_length_length + retry_token_length + length_length ==
@@ -152,8 +144,6 @@ size_t GetPacketHeaderSize(
// Google QUIC versions <= 43 can only carry one connection ID.
DCHECK(destination_connection_id_length == 0 ||
source_connection_id_length == 0);
- DCHECK(source_connection_id_length == 0 ||
- GetQuicRestartFlag(quic_do_not_override_connection_id));
return kPublicFlagsSize + destination_connection_id_length +
source_connection_id_length +
(include_version ? kQuicVersionSize : 0) + packet_number_length +
@@ -284,6 +274,11 @@ QuicData::QuicData(const char* buffer, size_t length)
QuicData::QuicData(const char* buffer, size_t length, bool owns_buffer)
: buffer_(buffer), length_(length), owns_buffer_(owns_buffer) {}
+QuicData::QuicData(QuicStringPiece packet_data)
+ : buffer_(packet_data.data()),
+ length_(packet_data.length()),
+ owns_buffer_(false) {}
+
QuicData::~QuicData() {
if (owns_buffer_) {
delete[] const_cast<char*>(buffer_);
@@ -338,6 +333,9 @@ QuicEncryptedPacket::QuicEncryptedPacket(const char* buffer,
bool owns_buffer)
: QuicData(buffer, length, owns_buffer) {}
+QuicEncryptedPacket::QuicEncryptedPacket(QuicStringPiece data)
+ : QuicData(data) {}
+
std::unique_ptr<QuicEncryptedPacket> QuicEncryptedPacket::Clone() const {
char* buffer = new char[this->length()];
memcpy(buffer, this->data(), this->length());
@@ -508,6 +506,7 @@ ReceivedPacketInfo::ReceivedPacketInfo(const QuicSocketAddress& self_address,
packet(packet),
form(GOOGLE_QUIC_PACKET),
version_flag(false),
+ use_length_prefix(false),
version_label(0),
version(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
destination_connection_id(EmptyQuicConnectionId()),
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packets.h b/chromium/net/third_party/quiche/src/quic/core/quic_packets.h
index cf6099e14a2..5c34b64e1ae 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_packets.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_packets.h
@@ -204,8 +204,13 @@ struct QUIC_EXPORT_PRIVATE QuicIetfStatelessResetPacket {
class QUIC_EXPORT_PRIVATE QuicData {
public:
+ // Creates a QuicData from a buffer and length. Does not own the buffer.
QuicData(const char* buffer, size_t length);
+ // Creates a QuicData from a buffer and length,
+ // optionally taking ownership of the buffer.
QuicData(const char* buffer, size_t length, bool owns_buffer);
+ // Creates a QuicData from a QuicStringPiece. Does not own the buffer.
+ QuicData(QuicStringPiece data);
QuicData(const QuicData&) = delete;
QuicData& operator=(const QuicData&) = delete;
virtual ~QuicData();
@@ -263,8 +268,16 @@ class QUIC_EXPORT_PRIVATE QuicPacket : public QuicData {
class QUIC_EXPORT_PRIVATE QuicEncryptedPacket : public QuicData {
public:
+ // Creates a QuicEncryptedPacket from a buffer and length.
+ // Does not own the buffer.
QuicEncryptedPacket(const char* buffer, size_t length);
+ // Creates a QuicEncryptedPacket from a buffer and length,
+ // optionally taking ownership of the buffer.
QuicEncryptedPacket(const char* buffer, size_t length, bool owns_buffer);
+ // Creates a QuicEncryptedPacket from a QuicStringPiece.
+ // Does not own the buffer.
+ QuicEncryptedPacket(QuicStringPiece data);
+
QuicEncryptedPacket(const QuicEncryptedPacket&) = delete;
QuicEncryptedPacket& operator=(const QuicEncryptedPacket&) = delete;
@@ -425,6 +438,7 @@ struct QUIC_EXPORT_PRIVATE ReceivedPacketInfo {
// Fields below are populated by QuicFramer::ProcessPacketDispatcher.
PacketHeaderFormat form;
bool version_flag;
+ bool use_length_prefix;
QuicVersionLabel version_label;
ParsedQuicVersion version;
QuicConnectionId destination_connection_id;
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packets_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_packets_test.cc
index be35d201f19..7ee77979a0c 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_packets_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_packets_test.cc
@@ -24,14 +24,6 @@ class QuicPacketsTest : public QuicTest {};
TEST_F(QuicPacketsTest, GetServerConnectionIdAsRecipient) {
QuicPacketHeader header = CreateFakePacketHeader();
- if (!GetQuicRestartFlag(quic_do_not_override_connection_id)) {
- EXPECT_EQ(TestConnectionId(1),
- GetServerConnectionIdAsRecipient(header, Perspective::IS_SERVER));
- EXPECT_EQ(TestConnectionId(1),
- GetServerConnectionIdAsRecipient(header, Perspective::IS_CLIENT));
- return;
- }
-
EXPECT_EQ(TestConnectionId(1),
GetServerConnectionIdAsRecipient(header, Perspective::IS_SERVER));
EXPECT_EQ(TestConnectionId(2),
@@ -40,14 +32,6 @@ TEST_F(QuicPacketsTest, GetServerConnectionIdAsRecipient) {
TEST_F(QuicPacketsTest, GetServerConnectionIdAsSender) {
QuicPacketHeader header = CreateFakePacketHeader();
- if (!GetQuicRestartFlag(quic_do_not_override_connection_id)) {
- EXPECT_EQ(TestConnectionId(1),
- GetServerConnectionIdAsSender(header, Perspective::IS_SERVER));
- EXPECT_EQ(TestConnectionId(1),
- GetServerConnectionIdAsSender(header, Perspective::IS_CLIENT));
- return;
- }
-
EXPECT_EQ(TestConnectionId(2),
GetServerConnectionIdAsSender(header, Perspective::IS_SERVER));
EXPECT_EQ(TestConnectionId(1),
@@ -56,14 +40,6 @@ TEST_F(QuicPacketsTest, GetServerConnectionIdAsSender) {
TEST_F(QuicPacketsTest, GetServerConnectionIdIncludedAsSender) {
QuicPacketHeader header = CreateFakePacketHeader();
- if (!GetQuicRestartFlag(quic_do_not_override_connection_id)) {
- EXPECT_EQ(CONNECTION_ID_PRESENT, GetServerConnectionIdIncludedAsSender(
- header, Perspective::IS_SERVER));
- EXPECT_EQ(CONNECTION_ID_PRESENT, GetServerConnectionIdIncludedAsSender(
- header, Perspective::IS_CLIENT));
- return;
- }
-
EXPECT_EQ(CONNECTION_ID_ABSENT, GetServerConnectionIdIncludedAsSender(
header, Perspective::IS_SERVER));
EXPECT_EQ(CONNECTION_ID_PRESENT, GetServerConnectionIdIncludedAsSender(
@@ -72,14 +48,6 @@ TEST_F(QuicPacketsTest, GetServerConnectionIdIncludedAsSender) {
TEST_F(QuicPacketsTest, GetClientConnectionIdIncludedAsSender) {
QuicPacketHeader header = CreateFakePacketHeader();
- if (!GetQuicRestartFlag(quic_do_not_override_connection_id)) {
- EXPECT_EQ(CONNECTION_ID_ABSENT, GetClientConnectionIdIncludedAsSender(
- header, Perspective::IS_SERVER));
- EXPECT_EQ(CONNECTION_ID_ABSENT, GetClientConnectionIdIncludedAsSender(
- header, Perspective::IS_CLIENT));
- return;
- }
-
EXPECT_EQ(CONNECTION_ID_PRESENT, GetClientConnectionIdIncludedAsSender(
header, Perspective::IS_SERVER));
EXPECT_EQ(CONNECTION_ID_ABSENT, GetClientConnectionIdIncludedAsSender(
@@ -87,7 +55,6 @@ TEST_F(QuicPacketsTest, GetClientConnectionIdIncludedAsSender) {
}
TEST_F(QuicPacketsTest, GetClientConnectionIdAsRecipient) {
- SetQuicRestartFlag(quic_do_not_override_connection_id, true);
QuicPacketHeader header = CreateFakePacketHeader();
EXPECT_EQ(TestConnectionId(2),
GetClientConnectionIdAsRecipient(header, Perspective::IS_SERVER));
@@ -97,14 +64,6 @@ TEST_F(QuicPacketsTest, GetClientConnectionIdAsRecipient) {
TEST_F(QuicPacketsTest, GetClientConnectionIdAsSender) {
QuicPacketHeader header = CreateFakePacketHeader();
- if (!GetQuicRestartFlag(quic_do_not_override_connection_id)) {
- EXPECT_EQ(TestConnectionId(2),
- GetClientConnectionIdAsSender(header, Perspective::IS_SERVER));
- EXPECT_EQ(TestConnectionId(2),
- GetClientConnectionIdAsSender(header, Perspective::IS_CLIENT));
- return;
- }
-
EXPECT_EQ(TestConnectionId(1),
GetClientConnectionIdAsSender(header, Perspective::IS_SERVER));
EXPECT_EQ(TestConnectionId(2),
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_received_packet_manager.cc b/chromium/net/third_party/quiche/src/quic/core/quic_received_packet_manager.cc
index 2994748c8f9..e21f4c48b8e 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_received_packet_manager.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_received_packet_manager.cc
@@ -58,6 +58,8 @@ QuicReceivedPacketManager::QuicReceivedPacketManager(QuicConnectionStats* stats)
ack_decimation_delay_(kAckDecimationDelay),
unlimited_ack_decimation_(false),
fast_ack_after_quiescence_(false),
+ local_max_ack_delay_(
+ QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs)),
ack_timeout_(QuicTime::Zero()),
time_of_previous_received_packet_(QuicTime::Zero()),
was_last_packet_missing_(false) {
@@ -218,8 +220,7 @@ void QuicReceivedPacketManager::MaybeUpdateAckTimeout(
QuicPacketNumber last_received_packet_number,
QuicTime time_of_last_received_packet,
QuicTime now,
- const RttStats* rtt_stats,
- QuicTime::Delta local_max_ack_delay) {
+ const RttStats* rtt_stats) {
if (!ack_frame_updated_) {
// ACK frame has not been updated, nothing to do.
return;
@@ -251,7 +252,7 @@ void QuicReceivedPacketManager::MaybeUpdateAckTimeout(
// Wait for the minimum of the ack decimation delay or the delayed ack time
// before sending an ack.
QuicTime::Delta ack_delay = std::min(
- local_max_ack_delay, rtt_stats->min_rtt() * ack_decimation_delay_);
+ local_max_ack_delay_, rtt_stats->min_rtt() * ack_decimation_delay_);
if (fast_ack_after_quiescence_ && now - time_of_previous_received_packet_ >
rtt_stats->SmoothedOrInitialRtt()) {
// Ack the first packet out of queiscence faster, because QUIC does
@@ -273,7 +274,7 @@ void QuicReceivedPacketManager::MaybeUpdateAckTimeout(
// or TLP packets, which we'd like to acknowledge quickly.
MaybeUpdateAckTimeoutTo(now + QuicTime::Delta::FromMilliseconds(1));
} else {
- MaybeUpdateAckTimeoutTo(now + local_max_ack_delay);
+ MaybeUpdateAckTimeoutTo(now + local_max_ack_delay_);
}
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_received_packet_manager.h b/chromium/net/third_party/quiche/src/quic/core/quic_received_packet_manager.h
index aaae7f12f9e..293b03cf4db 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_received_packet_manager.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_received_packet_manager.h
@@ -64,8 +64,7 @@ class QUIC_EXPORT_PRIVATE QuicReceivedPacketManager {
QuicPacketNumber last_received_packet_number,
QuicTime time_of_last_received_packet,
QuicTime now,
- const RttStats* rtt_stats,
- QuicTime::Delta local_max_ack_delay);
+ const RttStats* rtt_stats);
// Resets ACK related states, called after an ACK is successfully sent.
void ResetAckStates();
@@ -119,6 +118,11 @@ class QUIC_EXPORT_PRIVATE QuicReceivedPacketManager {
ack_frequency_before_ack_decimation_ = new_value;
}
+ QuicTime::Delta local_max_ack_delay() const { return local_max_ack_delay_; }
+ void set_local_max_ack_delay(QuicTime::Delta local_max_ack_delay) {
+ local_max_ack_delay_ = local_max_ack_delay;
+ }
+
QuicTime ack_timeout() const { return ack_timeout_; }
private:
@@ -172,6 +176,9 @@ class QUIC_EXPORT_PRIVATE QuicReceivedPacketManager {
// was received.
bool fast_ack_after_quiescence_;
+ // The local node's maximum ack delay time. This is the maximum amount of
+ // time to wait before sending an acknowledgement.
+ QuicTime::Delta local_max_ack_delay_;
// Time that an ACK needs to be sent. 0 means no ACK is pending. Used when
// decide_when_to_send_acks_ is true.
QuicTime ack_timeout_;
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 86ac933d0ff..db5e2600bfb 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
@@ -90,7 +90,7 @@ class QuicReceivedPacketManagerTest : public QuicTestWithParam<TestParams> {
received_manager_.MaybeUpdateAckTimeout(
should_last_packet_instigate_acks,
QuicPacketNumber(last_received_packet_number), clock_.ApproximateNow(),
- clock_.ApproximateNow(), &rtt_stats_, kDelayedAckTime);
+ clock_.ApproximateNow(), &rtt_stats_);
}
void CheckAckTimeout(QuicTime time) {
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 5762333dabe..a70dd01b036 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
@@ -111,24 +111,22 @@ QuicSentPacketManager::QuicSentPacketManager(
ietf_style_2x_tlp_(false),
largest_mtu_acked_(0),
handshake_confirmed_(false),
- local_max_ack_delay_(
- QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs)),
peer_max_ack_delay_(
QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs)),
rtt_updated_(false),
acked_packets_iter_(last_ack_frame_.packets.rbegin()),
+ pto_enabled_(false),
+ max_probe_packets_per_pto_(2),
+ consecutive_pto_count_(0),
loss_removes_from_inflight_(
GetQuicReloadableFlag(quic_loss_removes_from_inflight)),
ignore_tlpr_if_no_pending_stream_data_(
GetQuicReloadableFlag(quic_ignore_tlpr_if_no_pending_stream_data)),
- fix_rto_retransmission_(
- GetQuicReloadableFlag(quic_fix_rto_retransmission)) {
+ fix_rto_retransmission_(false),
+ handshake_mode_disabled_(false) {
if (loss_removes_from_inflight_) {
QUIC_RELOADABLE_FLAG_COUNT(quic_loss_removes_from_inflight);
}
- if (fix_rto_retransmission_) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_fix_rto_retransmission);
- }
SetSendAlgorithm(congestion_control_type);
}
@@ -151,23 +149,51 @@ void QuicSentPacketManager::SetFromConfig(const QuicConfig& config) {
SetInitialRtt(QuicTime::Delta::FromMicroseconds(
config.GetInitialRoundTripTimeUsToSend()));
}
+ if (config.HasReceivedMaxAckDelayMs()) {
+ peer_max_ack_delay_ =
+ QuicTime::Delta::FromMilliseconds(config.ReceivedMaxAckDelayMs());
+ }
if (config.HasClientSentConnectionOption(kMAD0, perspective)) {
rtt_stats_.set_ignore_max_ack_delay(true);
}
if (config.HasClientSentConnectionOption(kMAD1, perspective)) {
- rtt_stats_.set_initial_max_ack_delay(local_max_ack_delay_);
- }
- if (config.HasClientSentConnectionOption(kMAD2, perspective)) {
- min_tlp_timeout_ = QuicTime::Delta::Zero();
+ rtt_stats_.set_initial_max_ack_delay(peer_max_ack_delay_);
}
- if (config.HasClientSentConnectionOption(kMAD3, perspective)) {
- min_rto_timeout_ = QuicTime::Delta::Zero();
- }
- if (config.HasClientSentConnectionOption(kMAD4, perspective)) {
- ietf_style_tlp_ = true;
+ if (GetQuicReloadableFlag(quic_sent_packet_manager_cleanup)) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_sent_packet_manager_cleanup);
+ if (config.HasClientSentConnectionOption(kMAD2, perspective)) {
+ // Set the minimum to the alarm granularity.
+ min_tlp_timeout_ = QuicTime::Delta::FromMilliseconds(1);
+ }
+ if (config.HasClientSentConnectionOption(kMAD3, perspective)) {
+ // Set the minimum to the alarm granularity.
+ min_rto_timeout_ = QuicTime::Delta::FromMilliseconds(1);
+ }
+ } else {
+ if (config.HasClientSentConnectionOption(kMAD2, perspective)) {
+ min_tlp_timeout_ = QuicTime::Delta::Zero();
+ }
+ if (config.HasClientSentConnectionOption(kMAD3, perspective)) {
+ min_rto_timeout_ = QuicTime::Delta::Zero();
+ }
+ if (config.HasClientSentConnectionOption(kMAD4, perspective)) {
+ ietf_style_tlp_ = true;
+ }
+ if (config.HasClientSentConnectionOption(kMAD5, perspective)) {
+ ietf_style_2x_tlp_ = true;
+ }
}
- if (config.HasClientSentConnectionOption(kMAD5, perspective)) {
- ietf_style_2x_tlp_ = true;
+
+ if (GetQuicReloadableFlag(quic_enable_pto) && fix_rto_retransmission_) {
+ if (config.HasClientSentConnectionOption(k2PTO, perspective)) {
+ pto_enabled_ = true;
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_pto, 2, 4);
+ }
+ if (config.HasClientSentConnectionOption(k1PTO, perspective)) {
+ pto_enabled_ = true;
+ max_probe_packets_per_pto_ = 1;
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_pto, 1, 4);
+ }
}
// Configure congestion control.
@@ -330,6 +356,7 @@ void QuicSentPacketManager::PostProcessNewlyAckedPackets(
// Reset all retransmit counters any time a new packet is acked.
consecutive_rto_count_ = 0;
consecutive_tlp_count_ = 0;
+ consecutive_pto_count_ = 0;
consecutive_crypto_retransmission_count_ = 0;
}
@@ -460,7 +487,7 @@ void QuicSentPacketManager::MarkForRetransmission(
<< "transmission_type: "
<< QuicUtils::TransmissionTypeToString(transmission_type);
// Handshake packets should never be sent as probing retransmissions.
- DCHECK(!transmission_info->has_crypto_handshake ||
+ DCHECK(pto_enabled_ || !transmission_info->has_crypto_handshake ||
transmission_type != PROBING_RETRANSMISSION);
if (!loss_removes_from_inflight_ &&
!RetransmissionLeavesBytesInFlight(transmission_type)) {
@@ -698,8 +725,10 @@ bool QuicSentPacketManager::OnPacketSent(
return in_flight;
}
-void QuicSentPacketManager::OnRetransmissionTimeout() {
- DCHECK(unacked_packets_.HasInFlightPackets());
+QuicSentPacketManager::RetransmissionTimeoutMode
+QuicSentPacketManager::OnRetransmissionTimeout() {
+ DCHECK(unacked_packets_.HasInFlightPackets() ||
+ (handshake_mode_disabled_ && !handshake_confirmed_));
DCHECK_EQ(0u, pending_timer_transmission_count_);
// Handshake retransmission, timer based loss detection, TLP, and RTO are
// implemented with a single alarm. The handshake alarm is set when the
@@ -708,16 +737,17 @@ void QuicSentPacketManager::OnRetransmissionTimeout() {
// The TLP alarm is always set to run for under an RTO.
switch (GetRetransmissionMode()) {
case HANDSHAKE_MODE:
+ DCHECK(!handshake_mode_disabled_);
++stats_->crypto_retransmit_count;
RetransmitCryptoPackets();
- return;
+ return HANDSHAKE_MODE;
case LOSS_MODE: {
++stats_->loss_timeout_count;
QuicByteCount prior_in_flight = unacked_packets_.bytes_in_flight();
const QuicTime now = clock_->Now();
InvokeLossDetection(now);
MaybeInvokeCongestionEvent(false, prior_in_flight, now);
- return;
+ return LOSS_MODE;
}
case TLP_MODE:
++stats_->tlp_count;
@@ -725,11 +755,17 @@ void QuicSentPacketManager::OnRetransmissionTimeout() {
pending_timer_transmission_count_ = 1;
// TLPs prefer sending new data instead of retransmitting data, so
// give the connection a chance to write before completing the TLP.
- return;
+ return TLP_MODE;
case RTO_MODE:
++stats_->rto_count;
RetransmitRtoPackets();
- return;
+ return RTO_MODE;
+ case PTO_MODE:
+ QUIC_DVLOG(1) << ENDPOINT << "PTO mode";
+ ++stats_->pto_count;
+ ++consecutive_pto_count_;
+ pending_timer_transmission_count_ = max_probe_packets_per_pto_;
+ return PTO_MODE;
}
}
@@ -765,6 +801,7 @@ void QuicSentPacketManager::RetransmitCryptoPackets() {
}
bool QuicSentPacketManager::MaybeRetransmitTailLossProbe() {
+ DCHECK(!pto_enabled_);
if (pending_timer_transmission_count_ == 0) {
return false;
}
@@ -793,6 +830,7 @@ bool QuicSentPacketManager::MaybeRetransmitOldestPacket(TransmissionType type) {
}
void QuicSentPacketManager::RetransmitRtoPackets() {
+ DCHECK(!pto_enabled_);
QUIC_BUG_IF(pending_timer_transmission_count_ > 0)
<< "Retransmissions already queued:" << pending_timer_transmission_count_;
// Mark two packets for retransmission.
@@ -848,15 +886,62 @@ void QuicSentPacketManager::RetransmitRtoPackets() {
}
}
+void QuicSentPacketManager::MaybeSendProbePackets() {
+ if (pending_timer_transmission_count_ == 0) {
+ return;
+ }
+ QuicPacketNumber packet_number = unacked_packets_.GetLeastUnacked();
+ std::vector<QuicPacketNumber> probing_packets;
+ for (QuicUnackedPacketMap::const_iterator it = unacked_packets_.begin();
+ it != unacked_packets_.end(); ++it, ++packet_number) {
+ if (it->state == OUTSTANDING &&
+ unacked_packets_.HasRetransmittableFrames(*it)) {
+ probing_packets.push_back(packet_number);
+ if (probing_packets.size() == pending_timer_transmission_count_) {
+ break;
+ }
+ }
+ }
+
+ for (QuicPacketNumber retransmission : probing_packets) {
+ QUIC_DVLOG(1) << ENDPOINT << "Marking " << retransmission
+ << " for probing retransmission";
+ MarkForRetransmission(retransmission, PROBING_RETRANSMISSION);
+ }
+ // It is possible that there is not enough outstanding data for probing.
+}
+
+void QuicSentPacketManager::AdjustPendingTimerTransmissions() {
+ if (pending_timer_transmission_count_ < max_probe_packets_per_pto_) {
+ // There are packets sent already, clear credit.
+ pending_timer_transmission_count_ = 0;
+ return;
+ }
+ // No packet gets sent, leave 1 credit to allow data to be write eventually.
+ pending_timer_transmission_count_ = 1;
+}
+
+void QuicSentPacketManager::DisableHandshakeMode() {
+ DCHECK(session_decides_what_to_write());
+ fix_rto_retransmission_ = true;
+ pto_enabled_ = true;
+ handshake_mode_disabled_ = true;
+}
+
QuicSentPacketManager::RetransmissionTimeoutMode
QuicSentPacketManager::GetRetransmissionMode() const {
- DCHECK(unacked_packets_.HasInFlightPackets());
- if (!handshake_confirmed_ && unacked_packets_.HasPendingCryptoPackets()) {
+ DCHECK(unacked_packets_.HasInFlightPackets() ||
+ (handshake_mode_disabled_ && !handshake_confirmed_));
+ if (!handshake_mode_disabled_ && !handshake_confirmed_ &&
+ unacked_packets_.HasPendingCryptoPackets()) {
return HANDSHAKE_MODE;
}
if (loss_algorithm_->GetLossTimeout() != QuicTime::Zero()) {
return LOSS_MODE;
}
+ if (pto_enabled_) {
+ return PTO_MODE;
+ }
if (consecutive_tlp_count_ < max_tail_loss_probes_) {
if (unacked_packets_.HasUnackedRetransmittableFrames()) {
return TLP_MODE;
@@ -934,13 +1019,21 @@ QuicTime::Delta QuicSentPacketManager::TimeUntilSend(QuicTime now) const {
}
const QuicTime QuicSentPacketManager::GetRetransmissionTime() const {
- // Don't set the timer if there is nothing to retransmit or we've already
- // queued a tlp transmission and it hasn't been sent yet.
- if (!unacked_packets_.HasInFlightPackets() ||
- pending_timer_transmission_count_ > 0) {
+ if (!unacked_packets_.HasInFlightPackets() &&
+ (!handshake_mode_disabled_ || handshake_confirmed_ ||
+ unacked_packets_.perspective() == Perspective::IS_SERVER)) {
+ // Do not set the timer if there is nothing in flight. However, to avoid
+ // handshake deadlock due to anti-amplification limit, client needs to set
+ // PTO timer when the handshake is not confirmed even there is nothing in
+ // flight.
return QuicTime::Zero();
}
- if (!unacked_packets_.HasUnackedRetransmittableFrames()) {
+ if (pending_timer_transmission_count_ > 0) {
+ // Do not set the timer if there is any credit left.
+ return QuicTime::Zero();
+ }
+ if (!fix_rto_retransmission_ &&
+ !unacked_packets_.HasUnackedRetransmittableFrames()) {
return QuicTime::Zero();
}
switch (GetRetransmissionMode()) {
@@ -950,6 +1043,7 @@ const QuicTime QuicSentPacketManager::GetRetransmissionTime() const {
case LOSS_MODE:
return loss_algorithm_->GetLossTimeout();
case TLP_MODE: {
+ DCHECK(!pto_enabled_);
// TODO(ianswett): When CWND is available, it would be preferable to
// set the timer based on the earliest retransmittable packet.
// Base the updated timer on the send time of the last packet.
@@ -959,6 +1053,7 @@ const QuicTime QuicSentPacketManager::GetRetransmissionTime() const {
return std::max(clock_->ApproximateNow(), tlp_time);
}
case RTO_MODE: {
+ DCHECK(!pto_enabled_);
// The RTO is based on the first outstanding packet.
const QuicTime sent_time = unacked_packets_.GetLastPacketSentTime();
QuicTime rto_time = sent_time + GetRetransmissionDelay();
@@ -967,6 +1062,19 @@ const QuicTime QuicSentPacketManager::GetRetransmissionTime() const {
unacked_packets_.GetLastPacketSentTime() + GetTailLossProbeDelay();
return std::max(tlp_time, rto_time);
}
+ case PTO_MODE: {
+ if (handshake_mode_disabled_ && !handshake_confirmed_ &&
+ !unacked_packets_.HasInFlightPackets()) {
+ DCHECK_EQ(Perspective::IS_CLIENT, unacked_packets_.perspective());
+ return std::max(clock_->ApproximateNow(),
+ unacked_packets_.GetLastCryptoPacketSentTime() +
+ GetProbeTimeoutDelay());
+ }
+ // Ensure PTO never gets set to a time in the past.
+ return std::max(
+ clock_->ApproximateNow(),
+ unacked_packets_.GetLastPacketSentTime() + GetProbeTimeoutDelay());
+ }
}
DCHECK(false);
return QuicTime::Zero();
@@ -1058,6 +1166,22 @@ const QuicTime::Delta QuicSentPacketManager::GetRetransmissionDelay(
return retransmission_delay;
}
+const QuicTime::Delta QuicSentPacketManager::GetProbeTimeoutDelay() const {
+ DCHECK(pto_enabled_);
+ if (rtt_stats_.smoothed_rtt().IsZero()) {
+ if (rtt_stats_.initial_rtt().IsZero()) {
+ return QuicTime::Delta::FromSeconds(1);
+ }
+ return 2 * rtt_stats_.initial_rtt();
+ }
+ const QuicTime::Delta pto_delay =
+ rtt_stats_.smoothed_rtt() +
+ std::max(4 * rtt_stats_.mean_deviation(),
+ QuicTime::Delta::FromMilliseconds(1)) +
+ peer_max_ack_delay_;
+ return pto_delay * (1 << consecutive_pto_count_);
+}
+
QuicTime::Delta QuicSentPacketManager::GetSlowStartDuration() const {
if (send_algorithm_->GetCongestionControlType() != kBBR) {
return QuicTime::Delta::Infinite();
@@ -1112,6 +1236,7 @@ void QuicSentPacketManager::OnConnectionMigration(AddressChangeType type) {
}
consecutive_rto_count_ = 0;
consecutive_tlp_count_ = 0;
+ consecutive_pto_count_ = 0;
rtt_stats_.OnConnectionMigration();
send_algorithm_->OnConnectionMigration();
}
@@ -1273,6 +1398,16 @@ void QuicSentPacketManager::SetInitialRtt(QuicTime::Delta rtt) {
rtt_stats_.set_initial_rtt(std::max(min_rtt, std::min(max_rtt, rtt)));
}
+void QuicSentPacketManager::SetSessionDecideWhatToWrite(
+ bool session_decides_what_to_write) {
+ if (GetQuicReloadableFlag(quic_fix_rto_retransmission3) &&
+ session_decides_what_to_write) {
+ fix_rto_retransmission_ = true;
+ QUIC_RELOADABLE_FLAG_COUNT(quic_fix_rto_retransmission3);
+ }
+ unacked_packets_.SetSessionDecideWhatToWrite(session_decides_what_to_write);
+}
+
void QuicSentPacketManager::EnableMultiplePacketNumberSpacesSupport() {
unacked_packets_.EnableMultiplePacketNumberSpacesSupport();
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h b/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h
index b08704de229..2d8381c7ca4 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h
@@ -91,6 +91,23 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager {
virtual void OnPathMtuIncreased(QuicPacketLength packet_size) = 0;
};
+ // The retransmission timer is a single timer which switches modes depending
+ // upon connection state.
+ enum RetransmissionTimeoutMode {
+ // A conventional TCP style RTO.
+ RTO_MODE,
+ // A tail loss probe. By default, QUIC sends up to two before RTOing.
+ TLP_MODE,
+ // Retransmission of handshake packets prior to handshake completion.
+ HANDSHAKE_MODE,
+ // Re-invoke the loss detection when a packet is not acked before the
+ // loss detection algorithm expects.
+ LOSS_MODE,
+ // A probe timeout. At least one probe packet must be sent when timer
+ // expires.
+ PTO_MODE,
+ };
+
QuicSentPacketManager(Perspective perspective,
const QuicClock* clock,
QuicRandom* random,
@@ -183,8 +200,9 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager {
TransmissionType transmission_type,
HasRetransmittableData has_retransmittable_data);
- // Called when the retransmission timer expires.
- void OnRetransmissionTimeout();
+ // Called when the retransmission timer expires and returns the retransmission
+ // mode.
+ RetransmissionTimeoutMode OnRetransmissionTimeout();
// Calculate the time until we can send the next packet to the wire.
// Note 1: When kUnknownWaitTime is returned, there is no need to poll
@@ -283,9 +301,7 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager {
EncryptionLevel ack_decrypted_level);
// Called to enable/disable letting session decide what to write.
- void SetSessionDecideWhatToWrite(bool session_decides_what_to_write) {
- unacked_packets_.SetSessionDecideWhatToWrite(session_decides_what_to_write);
- }
+ void SetSessionDecideWhatToWrite(bool session_decides_what_to_write);
void EnableMultiplePacketNumberSpacesSupport();
@@ -324,6 +340,8 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager {
size_t GetConsecutiveTlpCount() const { return consecutive_tlp_count_; }
+ size_t GetConsecutivePtoCount() const { return consecutive_pto_count_; }
+
void OnApplicationLimited();
const SendAlgorithmInterface* GetSendAlgorithm() const {
@@ -355,17 +373,11 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager {
return pending_timer_transmission_count_;
}
- QuicTime::Delta local_max_ack_delay() const { return local_max_ack_delay_; }
-
- void set_local_max_ack_delay(QuicTime::Delta local_max_ack_delay) {
- // The delayed ack time should never be more than one half the min RTO time.
- DCHECK_LE(local_max_ack_delay, (min_rto_timeout_ * 0.5));
- local_max_ack_delay_ = local_max_ack_delay;
- }
-
QuicTime::Delta peer_max_ack_delay() const { return peer_max_ack_delay_; }
void set_peer_max_ack_delay(QuicTime::Delta peer_max_ack_delay) {
+ // The delayed ack time should never be more than one half the min RTO time.
+ DCHECK_LE(peer_max_ack_delay, (min_rto_timeout_ * 0.5));
peer_max_ack_delay_ = peer_max_ack_delay;
}
@@ -383,6 +395,15 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager {
// Setting the send algorithm once the connection is underway is dangerous.
void SetSendAlgorithm(SendAlgorithmInterface* send_algorithm);
+ // Sends up to max_probe_packets_per_pto_ probe packets.
+ void MaybeSendProbePackets();
+
+ // Called to adjust pending_timer_transmission_count_ accordingly.
+ void AdjustPendingTimerTransmissions();
+
+ // Called to disable HANDSHAKE_MODE, and only PTO and LOSS modes are used.
+ void DisableHandshakeMode();
+
bool supports_multiple_packet_number_spaces() const {
return unacked_packets_.supports_multiple_packet_number_spaces();
}
@@ -393,24 +414,14 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager {
bool fix_rto_retransmission() const { return fix_rto_retransmission_; }
+ bool pto_enabled() const { return pto_enabled_; }
+
+ bool handshake_mode_disabled() const { return handshake_mode_disabled_; }
+
private:
friend class test::QuicConnectionPeer;
friend class test::QuicSentPacketManagerPeer;
- // The retransmission timer is a single timer which switches modes depending
- // upon connection state.
- enum RetransmissionTimeoutMode {
- // A conventional TCP style RTO.
- RTO_MODE,
- // A tail loss probe. By default, QUIC sends up to two before RTOing.
- TLP_MODE,
- // Retransmission of handshake packets prior to handshake completion.
- HANDSHAKE_MODE,
- // Re-invoke the loss detection when a packet is not acked before the
- // loss detection algorithm expects.
- LOSS_MODE,
- };
-
typedef QuicLinkedHashMap<QuicPacketNumber,
TransmissionType,
QuicPacketNumberHash>
@@ -452,6 +463,9 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager {
return GetRetransmissionDelay(consecutive_rto_count_);
}
+ // Returns the probe timeout.
+ const QuicTime::Delta GetProbeTimeoutDelay() const;
+
// Returns the newest transmission associated with a packet.
QuicPacketNumber GetNewestRetransmission(
QuicPacketNumber packet_number,
@@ -615,10 +629,6 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager {
QuicPacketNumber
largest_packets_peer_knows_is_acked_[NUM_PACKET_NUMBER_SPACES];
- // The local node's maximum ack delay time. This is the maximum amount of
- // time to wait before sending an acknowledgement.
- QuicTime::Delta local_max_ack_delay_;
-
// The maximum ACK delay time that the peer uses. Initialized to be the
// same as local_max_ack_delay_, may be changed via transport parameter
// negotiation.
@@ -634,14 +644,28 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager {
// OnAckRangeStart, and gradually moves in OnAckRange..
PacketNumberQueue::const_reverse_iterator acked_packets_iter_;
+ // Indicates whether PTO mode has been enabled. PTO mode unifies TLP and RTO
+ // modes.
+ bool pto_enabled_;
+
+ // Maximum number of probes to send when PTO fires.
+ size_t max_probe_packets_per_pto_;
+
+ // Number of times the PTO timer has fired in a row without receiving an ack.
+ size_t consecutive_pto_count_;
+
// Latched value of quic_loss_removes_from_inflight.
const bool loss_removes_from_inflight_;
// Latched value of quic_ignore_tlpr_if_no_pending_stream_data.
const bool ignore_tlpr_if_no_pending_stream_data_;
- // Latched value of quic_fix_rto_retransmission.
- const bool fix_rto_retransmission_;
+ // Latched value of quic_fix_rto_retransmission3 and
+ // session_decides_what_to_write.
+ bool fix_rto_retransmission_;
+
+ // True if HANDSHAKE mode has been disabled.
+ bool handshake_mode_disabled_;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager_test.cc
index 4fce40f1859..43b00945dc0 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager_test.cc
@@ -357,6 +357,20 @@ class QuicSentPacketManagerTest : public QuicTestWithParam<bool> {
pending.transmission_type, HAS_RETRANSMITTABLE_DATA);
}
+ void EnablePto(QuicTag tag) {
+ SetQuicReloadableFlag(quic_fix_rto_retransmission3, true);
+ manager_.SetSessionDecideWhatToWrite(true);
+ SetQuicReloadableFlag(quic_enable_pto, true);
+ QuicConfig config;
+ QuicTagVector options;
+ options.push_back(tag);
+ QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
+ manager_.SetFromConfig(config);
+ EXPECT_TRUE(manager_.pto_enabled());
+ }
+
QuicSentPacketManager manager_;
MockClock clock_;
QuicConnectionStats stats_;
@@ -2259,12 +2273,16 @@ TEST_P(QuicSentPacketManagerTest, NegotiateNoMinTLPFromOptionsAtServer) {
EXPECT_EQ(QuicTime::Delta::FromMicroseconds(100002),
QuicSentPacketManagerPeer::GetTailLossProbeDelay(&manager_, 0));
- // Send two packets, and the TLP should be 2 us.
+ // Send two packets, and the TLP should be 2 us or 1ms.
+ QuicTime::Delta expected_tlp_delay =
+ GetQuicReloadableFlag(quic_sent_packet_manager_cleanup)
+ ? QuicTime::Delta::FromMilliseconds(1)
+ : QuicTime::Delta::FromMicroseconds(2);
SendDataPacket(1);
SendDataPacket(2);
- EXPECT_EQ(QuicTime::Delta::FromMicroseconds(2),
+ EXPECT_EQ(expected_tlp_delay,
QuicSentPacketManagerPeer::GetTailLossProbeDelay(&manager_));
- EXPECT_EQ(QuicTime::Delta::FromMicroseconds(2),
+ EXPECT_EQ(expected_tlp_delay,
QuicSentPacketManagerPeer::GetTailLossProbeDelay(&manager_, 0));
}
@@ -2290,16 +2308,23 @@ TEST_P(QuicSentPacketManagerTest, NegotiateNoMinTLPFromOptionsAtClient) {
QuicSentPacketManagerPeer::GetTailLossProbeDelay(&manager_));
EXPECT_EQ(QuicTime::Delta::FromMicroseconds(100002),
QuicSentPacketManagerPeer::GetTailLossProbeDelay(&manager_, 0));
- // Send two packets, and the TLP should be 2 us.
+ // Send two packets, and the TLP should be 2 us or 1ms.
+ QuicTime::Delta expected_tlp_delay =
+ GetQuicReloadableFlag(quic_sent_packet_manager_cleanup)
+ ? QuicTime::Delta::FromMilliseconds(1)
+ : QuicTime::Delta::FromMicroseconds(2);
SendDataPacket(1);
SendDataPacket(2);
- EXPECT_EQ(QuicTime::Delta::FromMicroseconds(2),
+ EXPECT_EQ(expected_tlp_delay,
QuicSentPacketManagerPeer::GetTailLossProbeDelay(&manager_));
- EXPECT_EQ(QuicTime::Delta::FromMicroseconds(2),
+ EXPECT_EQ(expected_tlp_delay,
QuicSentPacketManagerPeer::GetTailLossProbeDelay(&manager_, 0));
}
TEST_P(QuicSentPacketManagerTest, NegotiateIETFTLPFromOptionsAtServer) {
+ if (GetQuicReloadableFlag(quic_sent_packet_manager_cleanup)) {
+ return;
+ }
QuicConfig config;
QuicTagVector options;
@@ -2328,6 +2353,9 @@ TEST_P(QuicSentPacketManagerTest, NegotiateIETFTLPFromOptionsAtServer) {
}
TEST_P(QuicSentPacketManagerTest, NegotiateIETFTLPFromOptionsAtClient) {
+ if (GetQuicReloadableFlag(quic_sent_packet_manager_cleanup)) {
+ return;
+ }
QuicConfig client_config;
QuicTagVector options;
@@ -2369,14 +2397,22 @@ TEST_P(QuicSentPacketManagerTest, NegotiateNoMinRTOFromOptionsAtServer) {
RttStats* rtt_stats = const_cast<RttStats*>(manager_.GetRttStats());
rtt_stats->UpdateRtt(QuicTime::Delta::FromMicroseconds(1),
QuicTime::Delta::Zero(), QuicTime::Zero());
- EXPECT_EQ(QuicTime::Delta::FromMicroseconds(1),
+ QuicTime::Delta expected_rto_delay =
+ GetQuicReloadableFlag(quic_sent_packet_manager_cleanup)
+ ? QuicTime::Delta::FromMilliseconds(1)
+ : QuicTime::Delta::FromMicroseconds(1);
+ EXPECT_EQ(expected_rto_delay,
QuicSentPacketManagerPeer::GetRetransmissionDelay(&manager_));
- EXPECT_EQ(QuicTime::Delta::FromMicroseconds(1),
+ EXPECT_EQ(expected_rto_delay,
QuicSentPacketManagerPeer::GetRetransmissionDelay(&manager_, 0));
// The TLP with fewer than 2 packets outstanding includes 1/2 min RTO(0ms).
- EXPECT_EQ(QuicTime::Delta::FromMicroseconds(2),
+ QuicTime::Delta expected_tlp_delay =
+ GetQuicReloadableFlag(quic_sent_packet_manager_cleanup)
+ ? QuicTime::Delta::FromMicroseconds(502)
+ : QuicTime::Delta::FromMicroseconds(2);
+ EXPECT_EQ(expected_tlp_delay,
QuicSentPacketManagerPeer::GetTailLossProbeDelay(&manager_));
- EXPECT_EQ(QuicTime::Delta::FromMicroseconds(2),
+ EXPECT_EQ(expected_tlp_delay,
QuicSentPacketManagerPeer::GetTailLossProbeDelay(&manager_, 0));
}
@@ -2394,14 +2430,22 @@ TEST_P(QuicSentPacketManagerTest, NegotiateNoMinRTOFromOptionsAtClient) {
RttStats* rtt_stats = const_cast<RttStats*>(manager_.GetRttStats());
rtt_stats->UpdateRtt(QuicTime::Delta::FromMicroseconds(1),
QuicTime::Delta::Zero(), QuicTime::Zero());
- EXPECT_EQ(QuicTime::Delta::FromMicroseconds(1),
+ QuicTime::Delta expected_rto_delay =
+ GetQuicReloadableFlag(quic_sent_packet_manager_cleanup)
+ ? QuicTime::Delta::FromMilliseconds(1)
+ : QuicTime::Delta::FromMicroseconds(1);
+ EXPECT_EQ(expected_rto_delay,
QuicSentPacketManagerPeer::GetRetransmissionDelay(&manager_));
- EXPECT_EQ(QuicTime::Delta::FromMicroseconds(1),
+ EXPECT_EQ(expected_rto_delay,
QuicSentPacketManagerPeer::GetRetransmissionDelay(&manager_, 0));
// The TLP with fewer than 2 packets outstanding includes 1/2 min RTO(0ms).
- EXPECT_EQ(QuicTime::Delta::FromMicroseconds(2),
+ QuicTime::Delta expected_tlp_delay =
+ GetQuicReloadableFlag(quic_sent_packet_manager_cleanup)
+ ? QuicTime::Delta::FromMicroseconds(502)
+ : QuicTime::Delta::FromMicroseconds(2);
+ EXPECT_EQ(expected_tlp_delay,
QuicSentPacketManagerPeer::GetTailLossProbeDelay(&manager_));
- EXPECT_EQ(QuicTime::Delta::FromMicroseconds(2),
+ EXPECT_EQ(expected_tlp_delay,
QuicSentPacketManagerPeer::GetTailLossProbeDelay(&manager_, 0));
}
@@ -2902,15 +2946,10 @@ TEST_P(QuicSentPacketManagerTest, PacketInLimbo) {
uint64_t acked2[] = {5, 6};
uint64_t loss[] = {2};
- if (GetQuicReloadableFlag(quic_fix_packets_acked)) {
- // Verify packet 2 is detected lost.
- EXPECT_CALL(notifier_, OnFrameLost(_)).Times(1);
- ExpectAcksAndLosses(true, acked2, QUIC_ARRAYSIZE(acked2), loss,
- QUIC_ARRAYSIZE(loss));
- } else {
- // Packet 2 in limbo, bummer.
- ExpectAcksAndLosses(true, acked2, QUIC_ARRAYSIZE(acked2), nullptr, 0);
- }
+ // Verify packet 2 is detected lost.
+ EXPECT_CALL(notifier_, OnFrameLost(_)).Times(1);
+ ExpectAcksAndLosses(true, acked2, QUIC_ARRAYSIZE(acked2), loss,
+ QUIC_ARRAYSIZE(loss));
manager_.OnAckFrameStart(QuicPacketNumber(6), QuicTime::Delta::Infinite(),
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(7));
@@ -2942,7 +2981,7 @@ TEST_P(QuicSentPacketManagerTest, RtoFiresNoPacketToRetransmit) {
EXPECT_CALL(notifier_, RetransmitFrames(_, _)).Times(0);
manager_.OnRetransmissionTimeout();
EXPECT_EQ(2u, stats_.rto_count);
- if (GetQuicReloadableFlag(quic_fix_rto_retransmission)) {
+ if (GetQuicReloadableFlag(quic_fix_rto_retransmission3)) {
// Verify a credit is raised up.
EXPECT_EQ(1u, manager_.pending_timer_transmission_count());
} else {
@@ -2950,6 +2989,151 @@ TEST_P(QuicSentPacketManagerTest, RtoFiresNoPacketToRetransmit) {
}
}
+TEST_P(QuicSentPacketManagerTest, ComputingProbeTimeout) {
+ EnablePto(k2PTO);
+ EXPECT_CALL(*send_algorithm_, PacingRate(_))
+ .WillRepeatedly(Return(QuicBandwidth::Zero()));
+ EXPECT_CALL(*send_algorithm_, GetCongestionWindow())
+ .WillRepeatedly(Return(10 * kDefaultTCPMSS));
+ RttStats* rtt_stats = const_cast<RttStats*>(manager_.GetRttStats());
+ rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(100),
+ QuicTime::Delta::Zero(), QuicTime::Zero());
+ QuicTime::Delta srtt = rtt_stats->smoothed_rtt();
+
+ SendDataPacket(1, ENCRYPTION_FORWARD_SECURE);
+ // Verify PTO is correctly set.
+ QuicTime::Delta expected_pto_delay =
+ srtt + 4 * rtt_stats->mean_deviation() +
+ QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
+ EXPECT_EQ(clock_.Now() + expected_pto_delay,
+ manager_.GetRetransmissionTime());
+
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10));
+ SendDataPacket(2, ENCRYPTION_FORWARD_SECURE);
+ // Verify PTO is correctly set based on sent time of packet 2.
+ EXPECT_EQ(clock_.Now() + expected_pto_delay,
+ manager_.GetRetransmissionTime());
+ EXPECT_EQ(0u, stats_.pto_count);
+
+ // Invoke PTO.
+ clock_.AdvanceTime(expected_pto_delay);
+ manager_.OnRetransmissionTimeout();
+ EXPECT_EQ(QuicTime::Delta::Zero(), manager_.TimeUntilSend(clock_.Now()));
+ EXPECT_EQ(1u, stats_.pto_count);
+
+ // Verify two probe packets get sent.
+ EXPECT_CALL(notifier_, RetransmitFrames(_, _))
+ .Times(2)
+ .WillOnce(WithArgs<1>(Invoke([this](TransmissionType type) {
+ RetransmitDataPacket(3, type, ENCRYPTION_FORWARD_SECURE);
+ })))
+ .WillOnce(WithArgs<1>(Invoke([this](TransmissionType type) {
+ RetransmitDataPacket(4, type, ENCRYPTION_FORWARD_SECURE);
+ })));
+ manager_.MaybeSendProbePackets();
+ // Verify PTO period gets set to twice the current value.
+ QuicTime sent_time = clock_.Now();
+ EXPECT_EQ(sent_time + expected_pto_delay * 2,
+ manager_.GetRetransmissionTime());
+
+ // Received ACK for packets 1 and 2.
+ uint64_t acked[] = {1, 2};
+ ExpectAcksAndLosses(true, acked, QUIC_ARRAYSIZE(acked), nullptr, 0);
+ manager_.OnAckFrameStart(QuicPacketNumber(2), QuicTime::Delta::Infinite(),
+ clock_.Now());
+ manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(3));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1),
+ ENCRYPTION_FORWARD_SECURE));
+ expected_pto_delay =
+ rtt_stats->SmoothedOrInitialRtt() +
+ std::max(4 * rtt_stats->mean_deviation(),
+ QuicTime::Delta::FromMilliseconds(1)) +
+ QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
+
+ // Verify PTO is correctly re-armed based on sent time of packet 4.
+ EXPECT_EQ(sent_time + expected_pto_delay, manager_.GetRetransmissionTime());
+}
+
+TEST_P(QuicSentPacketManagerTest, SendOneProbePacket) {
+ EnablePto(k1PTO);
+ EXPECT_CALL(*send_algorithm_, PacingRate(_))
+ .WillRepeatedly(Return(QuicBandwidth::Zero()));
+ EXPECT_CALL(*send_algorithm_, GetCongestionWindow())
+ .WillRepeatedly(Return(10 * kDefaultTCPMSS));
+
+ SendDataPacket(1, ENCRYPTION_FORWARD_SECURE);
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10));
+ SendDataPacket(2, ENCRYPTION_FORWARD_SECURE);
+
+ RttStats* rtt_stats = const_cast<RttStats*>(manager_.GetRttStats());
+ rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(100),
+ QuicTime::Delta::Zero(), QuicTime::Zero());
+ QuicTime::Delta srtt = rtt_stats->smoothed_rtt();
+ // Verify PTO period is correctly set.
+ QuicTime::Delta expected_pto_delay =
+ srtt + 4 * rtt_stats->mean_deviation() +
+ QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
+ EXPECT_EQ(clock_.Now() + expected_pto_delay,
+ manager_.GetRetransmissionTime());
+
+ // Invoke PTO.
+ clock_.AdvanceTime(expected_pto_delay);
+ manager_.OnRetransmissionTimeout();
+ EXPECT_EQ(QuicTime::Delta::Zero(), manager_.TimeUntilSend(clock_.Now()));
+
+ // Verify one probe packet gets sent.
+ EXPECT_CALL(notifier_, RetransmitFrames(_, _))
+ .WillOnce(WithArgs<1>(Invoke([this](TransmissionType type) {
+ RetransmitDataPacket(3, type, ENCRYPTION_FORWARD_SECURE);
+ })));
+ manager_.MaybeSendProbePackets();
+}
+
+TEST_P(QuicSentPacketManagerTest, DisableHandshakeModeClient) {
+ QuicSentPacketManagerPeer::SetPerspective(&manager_, Perspective::IS_CLIENT);
+ manager_.SetSessionDecideWhatToWrite(true);
+ manager_.DisableHandshakeMode();
+ // Send CHLO.
+ SendCryptoPacket(1);
+ EXPECT_NE(QuicTime::Zero(), manager_.GetRetransmissionTime());
+ // Ack packet 1.
+ ExpectAck(1);
+ manager_.OnAckFrameStart(QuicPacketNumber(1), QuicTime::Delta::Infinite(),
+ clock_.Now());
+ manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1),
+ ENCRYPTION_INITIAL));
+ EXPECT_EQ(0u, manager_.GetBytesInFlight());
+ // Verify retransmission timeout is not zero because handshake is not
+ // confirmed although there is no in flight packet.
+ EXPECT_NE(QuicTime::Zero(), manager_.GetRetransmissionTime());
+ // Fire PTO.
+ EXPECT_EQ(QuicSentPacketManager::PTO_MODE,
+ manager_.OnRetransmissionTimeout());
+}
+
+TEST_P(QuicSentPacketManagerTest, DisableHandshakeModeServer) {
+ manager_.SetSessionDecideWhatToWrite(true);
+ manager_.DisableHandshakeMode();
+ // Send SHLO.
+ SendCryptoPacket(1);
+ EXPECT_NE(QuicTime::Zero(), manager_.GetRetransmissionTime());
+ // Ack packet 1.
+ ExpectAck(1);
+ manager_.OnAckFrameStart(QuicPacketNumber(1), QuicTime::Delta::Infinite(),
+ clock_.Now());
+ manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1),
+ ENCRYPTION_INITIAL));
+ EXPECT_EQ(0u, manager_.GetBytesInFlight());
+ // Verify retransmission timeout is not set on server side because there is
+ // nothing in flight.
+ EXPECT_EQ(QuicTime::Zero(), manager_.GetRetransmissionTime());
+}
+
} // namespace
} // namespace test
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_session.cc b/chromium/net/third_party/quiche/src/quic/core/quic_session.cc
index 221d75eb000..57de3771543 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
@@ -47,10 +47,12 @@ class ClosedStreamsCleanUpDelegate : public QuicAlarm::Delegate {
#define ENDPOINT \
(perspective() == Perspective::IS_SERVER ? "Server: " : "Client: ")
-QuicSession::QuicSession(QuicConnection* connection,
- Visitor* owner,
- const QuicConfig& config,
- const ParsedQuicVersionVector& supported_versions)
+QuicSession::QuicSession(
+ QuicConnection* connection,
+ Visitor* owner,
+ const QuicConfig& config,
+ const ParsedQuicVersionVector& supported_versions,
+ QuicStreamCount num_expected_unidirectional_static_streams)
: connection_(connection),
visitor_(owner),
write_blocked_streams_(connection->transport_version()),
@@ -69,7 +71,7 @@ QuicSession::QuicSession(QuicConnection* connection,
num_outgoing_static_streams_(0),
num_incoming_static_streams_(0),
num_locally_closed_incoming_streams_highest_offset_(0),
- error_(QUIC_NO_ERROR),
+ on_closed_frame_(QUIC_NO_ERROR, ""),
flow_controller_(
this,
QuicUtils::GetInvalidStreamId(connection->transport_version()),
@@ -88,10 +90,18 @@ QuicSession::QuicSession(QuicConnection* connection,
control_frame_manager_(this),
last_message_id_(0),
closed_streams_clean_up_alarm_(nullptr),
- supported_versions_(supported_versions) {
+ supported_versions_(supported_versions),
+ use_http2_priority_write_scheduler_(false),
+ is_configured_(false),
+ num_expected_unidirectional_static_streams_(
+ num_expected_unidirectional_static_streams) {
closed_streams_clean_up_alarm_ =
QuicWrapUnique<QuicAlarm>(connection_->alarm_factory()->CreateAlarm(
new ClosedStreamsCleanUpDelegate(this)));
+ if (perspective() == Perspective::IS_SERVER &&
+ connection_->version().handshake_protocol == PROTOCOL_TLS1_3) {
+ config_.SetStatelessResetTokenToSend(GetStatelessResetToken());
+ }
}
void QuicSession::Initialize() {
@@ -106,32 +116,28 @@ void QuicSession::Initialize() {
DCHECK_EQ(QuicUtils::GetCryptoStreamId(connection_->transport_version()),
GetMutableCryptoStream()->id());
-
- QuicStreamId id =
- QuicUtils::GetCryptoStreamId(connection_->transport_version());
- if (VersionHasIetfQuicFrames(connection_->transport_version())) {
- v99_streamid_manager_.RegisterStaticStream(id, false);
- }
}
QuicSession::~QuicSession() {
QUIC_LOG_IF(WARNING, !zombie_streams_.empty()) << "Still have zombie streams";
}
-void QuicSession::RegisterStaticStream(std::unique_ptr<QuicStream> stream,
- bool stream_already_counted) {
+void QuicSession::RegisterStaticStream(std::unique_ptr<QuicStream> stream) {
DCHECK(stream->is_static());
QuicStreamId stream_id = stream->id();
stream_map_[stream_id] = std::move(stream);
- if (VersionHasIetfQuicFrames(connection_->transport_version())) {
- v99_streamid_manager_.RegisterStaticStream(stream_id,
- stream_already_counted);
- }
if (IsIncomingStream(stream_id)) {
++num_incoming_static_streams_;
} else {
++num_outgoing_static_streams_;
}
+ if (VersionHasIetfQuicFrames(transport_version()) &&
+ !QuicUtils::IsBidirectionalStreamId(stream_id)) {
+ DCHECK_LE(num_incoming_static_streams_,
+ num_expected_unidirectional_static_streams_);
+ DCHECK_LE(num_outgoing_static_streams_,
+ num_expected_unidirectional_static_streams_);
+ }
}
void QuicSession::PendingStreamOnStreamFrame(const QuicStreamFrame& frame) {
@@ -157,6 +163,10 @@ void QuicSession::PendingStreamOnStreamFrame(const QuicStreamFrame& frame) {
DCHECK(IsClosedStream(stream_id) || IsOpenStream(stream_id))
<< "Stream " << stream_id << " not created";
pending_stream_map_.erase(stream_id);
+ return;
+ }
+ if (pending->sequencer()->IsClosed()) {
+ ClosePendingStream(stream_id);
}
}
@@ -313,6 +323,7 @@ void QuicSession::PendingStreamOnRstStream(const QuicRstStreamFrame& frame) {
}
pending->OnRstStreamFrame(frame);
+ SendRstStream(stream_id, QUIC_RST_ACKNOWLEDGEMENT, 0);
ClosePendingStream(stream_id);
}
@@ -386,8 +397,9 @@ void QuicSession::OnConnectionClosed(const QuicConnectionCloseFrame& frame,
RecordConnectionCloseAtServer(frame.quic_error_code, source);
}
- if (error_ == QUIC_NO_ERROR) {
- error_ = frame.quic_error_code;
+ if (on_closed_frame_.extracted_error_code == QUIC_NO_ERROR) {
+ // Save all of the connection close information
+ on_closed_frame_ = frame;
}
// Copy all non static streams in a new map for the ease of deleting.
@@ -418,8 +430,8 @@ void QuicSession::OnConnectionClosed(const QuicConnectionCloseFrame& frame,
if (visitor_) {
visitor_->OnConnectionClosed(connection_->connection_id(),
- frame.quic_error_code, frame.error_details,
- source);
+ frame.extracted_error_code,
+ frame.error_details, source);
}
}
@@ -437,10 +449,10 @@ void QuicSession::OnSuccessfulVersionNegotiation(
GetMutableCryptoStream()->OnSuccessfulVersionNegotiation(version);
}
-void QuicSession::OnConnectivityProbeReceived(
- const QuicSocketAddress& /*self_address*/,
- const QuicSocketAddress& peer_address) {
- if (perspective() == Perspective::IS_SERVER) {
+void QuicSession::OnPacketReceived(const QuicSocketAddress& /*self_address*/,
+ const QuicSocketAddress& peer_address,
+ bool is_connectivity_probe) {
+ if (is_connectivity_probe && perspective() == Perspective::IS_SERVER) {
// Server only sends back a connectivity probe after received a
// connectivity probe from a new peer address.
connection_->SendConnectivityProbingResponsePacket(peer_address);
@@ -463,10 +475,10 @@ void QuicSession::OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) {
QuicUtils::GetInvalidStreamId(connection_->transport_version())) {
// This is a window update that applies to the connection, rather than an
// individual stream.
- QUIC_DLOG(INFO) << ENDPOINT
- << "Received connection level flow control window "
- "update with byte offset: "
- << frame.byte_offset;
+ QUIC_DVLOG(1) << ENDPOINT
+ << "Received connection level flow control window "
+ "update with byte offset: "
+ << frame.byte_offset;
flow_controller_.UpdateSendWindowOffset(frame.byte_offset);
return;
}
@@ -561,11 +573,24 @@ void QuicSession::OnCanWrite() {
size_t num_writes = flow_controller_.IsBlocked()
? write_blocked_streams_.NumBlockedSpecialStreams()
: write_blocked_streams_.NumBlockedStreams();
- if (num_writes == 0 && !control_frame_manager_.WillingToWrite()) {
+ if (num_writes == 0 && !control_frame_manager_.WillingToWrite() &&
+ (!QuicVersionUsesCryptoFrames(connection_->transport_version()) ||
+ !GetCryptoStream()->HasBufferedCryptoFrames())) {
return;
}
QuicConnection::ScopedPacketFlusher flusher(connection_);
+ if (QuicVersionUsesCryptoFrames(connection_->transport_version())) {
+ QuicCryptoStream* crypto_stream = GetMutableCryptoStream();
+ if (crypto_stream->HasBufferedCryptoFrames()) {
+ crypto_stream->WriteBufferedCryptoFrames();
+ }
+ if (crypto_stream->HasBufferedCryptoFrames()) {
+ // Cannot finish writing buffered crypto frames, connection is write
+ // blocked.
+ return;
+ }
+ }
if (control_frame_manager_.WillingToWrite()) {
control_frame_manager_.OnCanWrite();
}
@@ -615,6 +640,10 @@ bool QuicSession::WillingAndAbleToWrite() const {
// 3) If the crypto or headers streams are blocked, or
// 4) connection is not flow control blocked and there are write blocked
// streams.
+ if (QuicVersionUsesCryptoFrames(connection_->transport_version()) &&
+ HasPendingHandshake()) {
+ return true;
+ }
return control_frame_manager_.WillingToWrite() ||
!streams_with_pending_retransmission_.empty() ||
write_blocked_streams_.HasWriteBlockedSpecialStream() ||
@@ -624,9 +653,8 @@ bool QuicSession::WillingAndAbleToWrite() const {
bool QuicSession::HasPendingHandshake() const {
if (QuicVersionUsesCryptoFrames(connection_->transport_version())) {
- // Writing CRYPTO frames is not subject to flow control, so there can't be
- // pending data to write, only pending retransmissions.
- return GetCryptoStream()->HasPendingCryptoRetransmission();
+ return GetCryptoStream()->HasPendingCryptoRetransmission() ||
+ GetCryptoStream()->HasBufferedCryptoFrames();
}
return QuicContainsKey(
streams_with_pending_retransmission_,
@@ -879,19 +907,7 @@ void QuicSession::CloseStreamInner(QuicStreamId stream_id, bool locally_reset) {
void QuicSession::ClosePendingStream(QuicStreamId stream_id) {
QUIC_DVLOG(1) << ENDPOINT << "Closing stream " << stream_id;
- if (pending_stream_map_.find(stream_id) == pending_stream_map_.end()) {
- QUIC_BUG << ENDPOINT << "Stream is already closed: " << stream_id;
- return;
- }
-
- SendRstStream(stream_id, QUIC_RST_ACKNOWLEDGEMENT, 0);
-
- // The pending stream may have been deleted and removed during SendRstStream.
- // Remove the stream from pending stream map iff it is still in the map.
- if (pending_stream_map_.find(stream_id) != pending_stream_map_.end()) {
- pending_stream_map_.erase(stream_id);
- }
-
+ pending_stream_map_.erase(stream_id);
if (VersionHasIetfQuicFrames(connection_->transport_version())) {
v99_streamid_manager_.OnStreamClosed(stream_id);
}
@@ -954,8 +970,7 @@ void QuicSession::OnConfigNegotiated() {
}
QUIC_DVLOG(1) << "Setting Bidirectional outgoing_max_streams_ to "
<< max_streams;
- v99_streamid_manager_.AdjustMaxOpenOutgoingBidirectionalStreams(
- max_streams);
+ v99_streamid_manager_.SetMaxOpenOutgoingBidirectionalStreams(max_streams);
max_streams = 0;
if (config_.HasReceivedMaxIncomingUnidirectionalStreams()) {
@@ -963,8 +978,7 @@ void QuicSession::OnConfigNegotiated() {
}
QUIC_DVLOG(1) << "Setting Unidirectional outgoing_max_streams_ to "
<< max_streams;
- v99_streamid_manager_.AdjustMaxOpenOutgoingUnidirectionalStreams(
- max_streams);
+ v99_streamid_manager_.SetMaxOpenOutgoingUnidirectionalStreams(max_streams);
} else {
uint32_t max_streams = 0;
if (config_.HasReceivedMaxIncomingBidirectionalStreams()) {
@@ -993,6 +1007,31 @@ void QuicSession::OnConfigNegotiated() {
if (ContainsQuicTag(config_.ReceivedConnectionOptions(), kIFWA)) {
AdjustInitialFlowControlWindows(1024 * 1024);
}
+ if (GetQuicReloadableFlag(quic_use_http2_priority_write_scheduler) &&
+ ContainsQuicTag(config_.ReceivedConnectionOptions(), kH2PR) &&
+ !VersionHasIetfQuicFrames(connection_->transport_version())) {
+ // Enable HTTP2 (tree-style) priority write scheduler.
+ use_http2_priority_write_scheduler_ =
+ write_blocked_streams_.SwitchWriteScheduler(
+ spdy::WriteSchedulerType::HTTP2,
+ connection_->transport_version());
+ } else if (GetQuicReloadableFlag(quic_enable_fifo_write_scheduler) &&
+ ContainsQuicTag(config_.ReceivedConnectionOptions(), kFIFO)) {
+ // Enable FIFO write scheduler.
+ if (write_blocked_streams_.SwitchWriteScheduler(
+ spdy::WriteSchedulerType::FIFO,
+ connection_->transport_version())) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_enable_fifo_write_scheduler);
+ }
+ } else if (GetQuicReloadableFlag(quic_enable_lifo_write_scheduler) &&
+ ContainsQuicTag(config_.ReceivedConnectionOptions(), kLIFO)) {
+ // Enable LIFO write scheduler.
+ if (write_blocked_streams_.SwitchWriteScheduler(
+ spdy::WriteSchedulerType::LIFO,
+ connection_->transport_version())) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_enable_lifo_write_scheduler);
+ }
+ }
}
config_.SetStatelessResetTokenToSend(GetStatelessResetToken());
@@ -1028,6 +1067,7 @@ void QuicSession::OnConfigNegotiated() {
OnNewSessionFlowControlWindow(
config_.ReceivedInitialSessionFlowControlWindowBytes());
}
+ is_configured_ = true;
}
void QuicSession::AdjustInitialFlowControlWindows(size_t stream_window) {
@@ -1120,14 +1160,7 @@ void QuicSession::OnNewSessionFlowControlWindow(QuicStreamOffset new_window) {
void QuicSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) {
switch (event) {
- // TODO(satyamshekhar): Move the logic of setting the encrypter/decrypter
- // to QuicSession since it is the glue.
- case ENCRYPTION_FIRST_ESTABLISHED:
- // Given any streams blocked by encryption a chance to write.
- OnCanWrite();
- break;
-
- case ENCRYPTION_REESTABLISHED:
+ case ENCRYPTION_ESTABLISHED:
// Retransmit originally packets that were sent, since they can't be
// decrypted by the peer.
connection_->RetransmitUnackedPackets(ALL_INITIAL_RETRANSMISSION);
@@ -1155,19 +1188,21 @@ void QuicSession::OnCryptoHandshakeMessageSent(
void QuicSession::OnCryptoHandshakeMessageReceived(
const CryptoHandshakeMessage& /*message*/) {}
-void QuicSession::RegisterStreamPriority(QuicStreamId id,
- bool is_static,
- SpdyPriority priority) {
- write_blocked_streams()->RegisterStream(id, is_static, priority);
+void QuicSession::RegisterStreamPriority(
+ QuicStreamId id,
+ bool is_static,
+ const spdy::SpdyStreamPrecedence& precedence) {
+ write_blocked_streams()->RegisterStream(id, is_static, precedence);
}
void QuicSession::UnregisterStreamPriority(QuicStreamId id, bool is_static) {
write_blocked_streams()->UnregisterStream(id, is_static);
}
-void QuicSession::UpdateStreamPriority(QuicStreamId id,
- SpdyPriority new_priority) {
- write_blocked_streams()->UpdateStreamPriority(id, new_priority);
+void QuicSession::UpdateStreamPriority(
+ QuicStreamId id,
+ const spdy::SpdyStreamPrecedence& new_precedence) {
+ write_blocked_streams()->UpdateStreamPriority(id, new_precedence);
}
QuicConfig* QuicSession::config() {
@@ -1321,7 +1356,8 @@ PendingStream* QuicSession::GetOrCreatePendingStream(QuicStreamId stream_id) {
QuicStream* QuicSession::GetOrCreateDynamicStream(
const QuicStreamId stream_id) {
- DCHECK(!GetQuicReloadableFlag(quic_inline_getorcreatedynamicstream));
+ DCHECK(!GetQuicReloadableFlag(quic_inline_getorcreatedynamicstream) ||
+ !GetQuicReloadableFlag(quic_handle_staticness_for_spdy_stream));
StreamMap::iterator it = stream_map_.find(stream_id);
if (it != stream_map_.end()) {
return it->second.get();
@@ -1906,5 +1942,17 @@ size_t QuicSession::max_open_incoming_unidirectional_streams() const {
return stream_id_manager_.max_open_incoming_streams();
}
+std::vector<QuicStringPiece>::const_iterator QuicSession::SelectAlpn(
+ const std::vector<QuicStringPiece>& alpns) const {
+ const std::string alpn = AlpnForVersion(connection()->version());
+ return std::find(alpns.cbegin(), alpns.cend(), alpn);
+}
+
+void QuicSession::OnAlpnSelected(QuicStringPiece alpn) {
+ QUIC_DLOG(INFO) << (perspective() == Perspective::IS_SERVER ? "Server: "
+ : "Client: ")
+ << "ALPN selected: " << alpn;
+}
+
#undef ENDPOINT // undef for jumbo builds
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_session.h b/chromium/net/third_party/quiche/src/quic/core/quic_session.h
index b7c02122f93..16c7efc7a16 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
@@ -8,6 +8,7 @@
#define QUICHE_QUIC_CORE_QUIC_SESSION_H_
#include <cstddef>
+#include <cstdint>
#include <map>
#include <memory>
#include <string>
@@ -70,15 +71,9 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface,
// CryptoHandshakeEvent enumerates the events generated by a QuicCryptoStream.
enum CryptoHandshakeEvent {
- // ENCRYPTION_FIRST_ESTABLISHED indicates that a full client hello has been
- // sent by a client and that subsequent packets will be encrypted. (Client
- // only.)
- ENCRYPTION_FIRST_ESTABLISHED,
- // ENCRYPTION_REESTABLISHED indicates that a client hello was rejected by
- // the server and thus the encryption key has been updated. Therefore the
- // connection should resend any packets that were sent under
- // ENCRYPTION_ZERO_RTT. (Client only.)
- ENCRYPTION_REESTABLISHED,
+ // ENCRYPTION_ESTABLISHED indicates that a client hello has been sent and
+ // subsequent packets will be encrypted. (Client only.)
+ ENCRYPTION_ESTABLISHED,
// HANDSHAKE_CONFIRMED, in a client, indicates the server has accepted
// our handshake. In a server it indicates that a full, valid client hello
// has been received. (Client and server.)
@@ -89,7 +84,8 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface,
QuicSession(QuicConnection* connection,
Visitor* owner,
const QuicConfig& config,
- const ParsedQuicVersionVector& supported_versions);
+ const ParsedQuicVersionVector& supported_versions,
+ QuicStreamCount num_expected_unidirectional_static_streams);
QuicSession(const QuicSession&) = delete;
QuicSession& operator=(const QuicSession&) = delete;
@@ -110,9 +106,9 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface,
void OnWriteBlocked() override;
void OnSuccessfulVersionNegotiation(
const ParsedQuicVersion& version) override;
- void OnConnectivityProbeReceived(
- const QuicSocketAddress& self_address,
- const QuicSocketAddress& peer_address) override;
+ void OnPacketReceived(const QuicSocketAddress& self_address,
+ const QuicSocketAddress& peer_address,
+ bool is_connectivity_probe) override;
void OnCanWrite() override;
bool SendProbingData() override;
void OnCongestionWindowChange(QuicTime /*now*/) override {}
@@ -240,8 +236,7 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface,
// Called by the QuicCryptoStream when the handshake enters a new state.
//
// Clients will call this function in the order:
- // ENCRYPTION_FIRST_ESTABLISHED
- // zero or more ENCRYPTION_REESTABLISHED
+ // zero or more ENCRYPTION_ESTABLISHED
// HANDSHAKE_CONFIRMED
//
// Servers will simply call it once with HANDSHAKE_CONFIRMED.
@@ -256,16 +251,18 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface,
const CryptoHandshakeMessage& message);
// Called by the stream on creation to set priority in the write blocked list.
- virtual void RegisterStreamPriority(QuicStreamId id,
- bool is_static,
- spdy::SpdyPriority priority);
+ virtual void RegisterStreamPriority(
+ QuicStreamId id,
+ bool is_static,
+ const spdy::SpdyStreamPrecedence& precedence);
// Called by the stream on deletion to clear priority from the write blocked
// list.
virtual void UnregisterStreamPriority(QuicStreamId id, bool is_static);
// Called by the stream on SetPriority to update priority on the write blocked
// list.
- virtual void UpdateStreamPriority(QuicStreamId id,
- spdy::SpdyPriority new_priority);
+ virtual void UpdateStreamPriority(
+ QuicStreamId id,
+ const spdy::SpdyStreamPrecedence& new_precedence);
// Returns mutable config for this session. Returned config is owned
// by QuicSession.
@@ -288,19 +285,19 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface,
return connection_->connection_id();
}
- // Returns the number of currently open streams, excluding the reserved
- // headers and crypto streams, and never counting unfinished streams.
+ // Returns the number of currently open streams, excluding static streams, and
+ // never counting unfinished streams.
size_t GetNumActiveStreams() const;
// Returns the number of currently draining streams.
size_t GetNumDrainingStreams() const;
- // Returns the number of currently open peer initiated streams, excluding the
- // reserved headers and crypto streams.
+ // Returns the number of currently open peer initiated streams, excluding
+ // static streams.
size_t GetNumOpenIncomingStreams() const;
- // Returns the number of currently open self initiated streams, excluding the
- // reserved headers and crypto streams.
+ // Returns the number of currently open self initiated streams, excluding
+ // static streams.
size_t GetNumOpenOutgoingStreams() const;
// Returns the number of open peer initiated static streams.
@@ -317,7 +314,7 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface,
// connection-level flow control but not by its own stream-level flow control.
// The stream will be given a chance to write when a connection-level
// WINDOW_UPDATE arrives.
- void MarkConnectionLevelWriteBlocked(QuicStreamId id);
+ virtual void MarkConnectionLevelWriteBlocked(QuicStreamId id);
// Called when stream |id| is done waiting for acks either because all data
// gets acked or is not interested in data being acked (which happens when
@@ -348,7 +345,20 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface,
bool goaway_received() const { return goaway_received_; }
- QuicErrorCode error() const { return error_; }
+ // Returns the Google QUIC error code
+ QuicErrorCode error() const { return on_closed_frame_.extracted_error_code; }
+ uint64_t transport_close_frame_type() const {
+ return on_closed_frame_.transport_close_frame_type;
+ }
+ QuicConnectionCloseType close_type() const {
+ return on_closed_frame_.close_type;
+ }
+ QuicIetfTransportErrorCodes transport_error_code() const {
+ return on_closed_frame_.transport_error_code;
+ }
+ uint16_t application_error_code() const {
+ return on_closed_frame_.application_error_code;
+ }
Perspective perspective() const { return connection_->perspective(); }
@@ -377,7 +387,7 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface,
virtual void StreamDraining(QuicStreamId id);
// Returns true if this stream should yield writes to another blocked stream.
- bool ShouldYield(QuicStreamId stream_id);
+ virtual bool ShouldYield(QuicStreamId stream_id);
// Set transmission type of next sending packets.
void SetTransmissionType(TransmissionType type);
@@ -432,6 +442,39 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface,
return connection_->transport_version();
}
+ bool use_http2_priority_write_scheduler() const {
+ return use_http2_priority_write_scheduler_;
+ }
+
+ bool is_configured() const { return is_configured_; }
+
+ QuicStreamCount num_expected_unidirectional_static_streams() const {
+ return num_expected_unidirectional_static_streams_;
+ }
+
+ // Set the number of unidirectional stream that the peer is allowed to open to
+ // be |max_stream| + |num_expected_static_streams_|.
+ void ConfigureMaxIncomingDynamicStreamsToSend(QuicStreamCount max_stream) {
+ config_.SetMaxIncomingUnidirectionalStreamsToSend(
+ max_stream + num_expected_unidirectional_static_streams_);
+ }
+
+ // Returns the ALPN values to negotiate on this session.
+ virtual std::vector<std::string> GetAlpnsToOffer() const {
+ // TODO(vasilvv): this currently sets HTTP/3 by default. Switch all
+ // non-HTTP applications to appropriate ALPNs.
+ return std::vector<std::string>({AlpnForVersion(connection()->version())});
+ }
+
+ // Provided a list of ALPNs offered by the client, selects an ALPN from the
+ // list, or alpns.end() if none of the ALPNs are acceptable.
+ virtual std::vector<QuicStringPiece>::const_iterator SelectAlpn(
+ const std::vector<QuicStringPiece>& alpns) const;
+
+ // Called when the ALPN of the connection is established for a connection that
+ // uses TLS handshake.
+ virtual void OnAlpnSelected(QuicStringPiece alpn);
+
protected:
using StreamMap = QuicSmallMap<QuicStreamId, std::unique_ptr<QuicStream>, 10>;
@@ -505,8 +548,7 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface,
// |stream| as static in stream id manager. |stream_already_counted| is true
// if |stream| is created from pending stream and is already known as an open
// stream.
- void RegisterStaticStream(std::unique_ptr<QuicStream> stream,
- bool stream_already_counted);
+ void RegisterStaticStream(std::unique_ptr<QuicStream> stream);
StreamMap& stream_map() { return stream_map_; }
const StreamMap& stream_map() const { return stream_map_; }
@@ -518,7 +560,10 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface,
void set_largest_peer_created_stream_id(
QuicStreamId largest_peer_created_stream_id);
- void set_error(QuicErrorCode error) { error_ = error; }
+ void set_error(QuicErrorCode error) {
+ on_closed_frame_.extracted_error_code = error;
+ }
+
QuicWriteBlockedList* write_blocked_streams() {
return &write_blocked_streams_;
}
@@ -569,6 +614,8 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface,
return false;
}
+ bool IsHandshakeConfirmed() { return is_handshake_confirmed_; }
+
private:
friend class test::QuicSessionPeer;
@@ -684,8 +731,8 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface,
// locally_closed_streams_highest_offset_.
size_t num_locally_closed_incoming_streams_highest_offset_;
- // The latched error with which the connection was closed.
- QuicErrorCode error_;
+ // Received information for a connection close.
+ QuicConnectionCloseFrame on_closed_frame_;
// Used for connection-level flow control.
QuicFlowController flow_controller_;
@@ -719,6 +766,17 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface,
// Supported version list used by the crypto handshake only. Please note, this
// list may be a superset of the connection framer's supported versions.
ParsedQuicVersionVector supported_versions_;
+
+ // If true, write_blocked_streams_ uses HTTP2 (tree-style) priority write
+ // scheduler.
+ bool use_http2_priority_write_scheduler_;
+
+ // Initialized to false. Set to true when the session has been properly
+ // configured and is ready for general operation.
+ bool is_configured_;
+
+ // The number of expected static streams.
+ QuicStreamCount num_expected_unidirectional_static_streams_;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_session_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_session_test.cc
index 90577d54483..7480eeedb32 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
@@ -142,7 +142,8 @@ class TestSession : public QuicSession {
: QuicSession(connection,
session_visitor,
DefaultQuicConfig(),
- CurrentSupportedVersions()),
+ CurrentSupportedVersions(),
+ /*num_expected_unidirectional_static_streams = */ 0),
crypto_stream_(this),
writev_consumes_all_data_(false),
uses_pending_streams_(false),
@@ -153,7 +154,10 @@ class TestSession : public QuicSession {
QuicMakeUnique<NullEncrypter>(connection->perspective()));
}
- ~TestSession() override { delete connection(); }
+ ~TestSession() override {
+ EXPECT_TRUE(is_configured());
+ delete connection();
+ }
TestCryptoStream* GetMutableCryptoStream() override {
return &crypto_stream_;
@@ -237,7 +241,7 @@ class TestSession : public QuicSession {
}
bool ShouldKeepConnectionAlive() const override {
- return GetNumOpenDynamicStreams() > 0;
+ return GetNumActiveStreams() > 0;
}
QuicConsumedData WritevData(QuicStream* stream,
@@ -329,7 +333,13 @@ class QuicSessionTestBase : public QuicTestWithParam<ParsedQuicVersion> {
kInitialStreamFlowControlWindowForTest);
session_.config()->SetInitialSessionFlowControlWindowToSend(
kInitialSessionFlowControlWindowForTest);
+
+ QuicConfigPeer::SetReceivedMaxIncomingBidirectionalStreams(
+ session_.config(), kDefaultMaxStreamsPerConnection);
+ QuicConfigPeer::SetReceivedMaxIncomingUnidirectionalStreams(
+ session_.config(), kDefaultMaxStreamsPerConnection);
connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
+ session_.OnConfigNegotiated();
TestCryptoStream* crypto_stream = session_.GetMutableCryptoStream();
EXPECT_CALL(*crypto_stream, HasPendingRetransmission())
.Times(testing::AnyNumber());
@@ -890,7 +900,7 @@ TEST_P(QuicSessionTestServer, TestBatchedWrites) {
// Now let stream 4 do the 2nd of its 3 writes, but add a block for a high
// priority stream 6. 4 should be preempted. 6 will write but *not* block so
// will cede back to 4.
- stream6->SetPriority(kV3HighestPriority);
+ stream6->SetPriority(spdy::SpdyStreamPrecedence(kV3HighestPriority));
EXPECT_CALL(*stream4, OnCanWrite())
.WillOnce(Invoke([this, stream4, stream6]() {
session_.SendLargeFakeData(stream4, 6000);
@@ -917,6 +927,88 @@ TEST_P(QuicSessionTestServer, TestBatchedWrites) {
session_.OnCanWrite();
}
+TEST_P(QuicSessionTestServer, Http2Priority) {
+ if (VersionHasIetfQuicFrames(GetParam().transport_version)) {
+ return;
+ }
+ SetQuicReloadableFlag(quic_use_http2_priority_write_scheduler, true);
+ QuicTagVector copt;
+ copt.push_back(kH2PR);
+ QuicConfigPeer::SetReceivedConnectionOptions(session_.config(), copt);
+ session_.OnConfigNegotiated();
+ ASSERT_TRUE(session_.use_http2_priority_write_scheduler());
+
+ session_.set_writev_consumes_all_data(true);
+ TestStream* stream2 = session_.CreateOutgoingBidirectionalStream();
+ TestStream* stream4 = session_.CreateOutgoingBidirectionalStream();
+ TestStream* stream6 = session_.CreateOutgoingBidirectionalStream();
+
+ session_.set_writev_consumes_all_data(true);
+ /*
+ 0
+ /|\
+ 2 4 6
+ */
+ session_.MarkConnectionLevelWriteBlocked(stream2->id());
+ session_.MarkConnectionLevelWriteBlocked(stream4->id());
+ session_.MarkConnectionLevelWriteBlocked(stream6->id());
+
+ // Verify streams are scheduled round robin.
+ InSequence s;
+ EXPECT_CALL(*stream2, OnCanWrite());
+ EXPECT_CALL(*stream4, OnCanWrite());
+ EXPECT_CALL(*stream6, OnCanWrite());
+ session_.OnCanWrite();
+
+ /*
+ 0
+ |
+ 4
+ / \
+ 2 6
+ */
+ // Update stream 4's priority.
+ stream4->SetPriority(
+ spdy::SpdyStreamPrecedence(0, spdy::kHttp2DefaultStreamWeight, true));
+ session_.MarkConnectionLevelWriteBlocked(stream2->id());
+ session_.MarkConnectionLevelWriteBlocked(stream4->id());
+ session_.MarkConnectionLevelWriteBlocked(stream6->id());
+
+ EXPECT_CALL(*stream4, OnCanWrite()).WillOnce(Invoke([this, stream4]() {
+ session_.MarkConnectionLevelWriteBlocked(stream4->id());
+ }));
+ EXPECT_CALL(*stream4, OnCanWrite());
+ EXPECT_CALL(*stream2, OnCanWrite());
+ session_.OnCanWrite();
+ EXPECT_CALL(*stream6, OnCanWrite());
+ session_.OnCanWrite();
+
+ /*
+ 0
+ |
+ 6
+ |
+ 4
+ |
+ 2
+ */
+ // Update stream 6's priority.
+ stream6->SetPriority(
+ spdy::SpdyStreamPrecedence(0, spdy::kHttp2DefaultStreamWeight, true));
+ session_.MarkConnectionLevelWriteBlocked(stream2->id());
+ session_.MarkConnectionLevelWriteBlocked(stream4->id());
+ session_.MarkConnectionLevelWriteBlocked(stream6->id());
+
+ EXPECT_CALL(*stream6, OnCanWrite()).WillOnce(Invoke([this, stream6]() {
+ session_.MarkConnectionLevelWriteBlocked(stream6->id());
+ }));
+ EXPECT_CALL(*stream6, OnCanWrite());
+ EXPECT_CALL(*stream4, OnCanWrite());
+ session_.OnCanWrite();
+ EXPECT_CALL(*stream2, OnCanWrite());
+ session_.OnCanWrite();
+}
+
TEST_P(QuicSessionTestServer, OnCanWriteBundlesStreams) {
// Encryption needs to be established before data can be sent.
CryptoHandshakeMessage msg;
@@ -1168,6 +1260,7 @@ TEST_P(QuicSessionTestServer, SendGoAway) {
// GoAway frames are not in version 99
return;
}
+ connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
MockPacketWriter* writer = static_cast<MockPacketWriter*>(
QuicConnectionPeer::GetWriter(session_.connection()));
EXPECT_CALL(*writer, WritePacket(_, _, _, _, _))
@@ -1235,8 +1328,8 @@ TEST_P(QuicSessionTestServer, ServerReplyToConnectivityProbe) {
connection_->OnPathChallengeFrame(
QuicPathChallengeFrame(0, path_frame_buffer1_));
}
- session_.OnConnectivityProbeReceived(session_.self_address(),
- new_peer_address);
+ session_.OnPacketReceived(session_.self_address(), new_peer_address,
+ /*is_connectivity_probe=*/true);
EXPECT_EQ(old_peer_address, session_.peer_address());
}
@@ -1275,8 +1368,8 @@ TEST_P(QuicSessionTestServer, ServerReplyToConnectivityProbes) {
QuicPathChallengeFrame(0, path_frame_buffer1_));
connection_->OnPathChallengeFrame(
QuicPathChallengeFrame(0, path_frame_buffer2_));
- session_.OnConnectivityProbeReceived(session_.self_address(),
- old_peer_address);
+ session_.OnPacketReceived(session_.self_address(), old_peer_address,
+ /*is_connectivity_probe=*/true);
}
TEST_P(QuicSessionTestServer, IncreasedTimeoutAfterCryptoHandshake) {
@@ -1289,7 +1382,7 @@ TEST_P(QuicSessionTestServer, IncreasedTimeoutAfterCryptoHandshake) {
}
TEST_P(QuicSessionTestServer, OnStreamFrameFinStaticStreamId) {
- if (connection_->version().DoesNotHaveHeadersStream()) {
+ if (VersionUsesQpack(connection_->transport_version())) {
return;
}
QuicStreamId headers_stream_id =
@@ -1308,7 +1401,7 @@ TEST_P(QuicSessionTestServer, OnStreamFrameFinStaticStreamId) {
}
TEST_P(QuicSessionTestServer, OnRstStreamStaticStreamId) {
- if (connection_->version().DoesNotHaveHeadersStream()) {
+ if (VersionUsesQpack(connection_->transport_version())) {
return;
}
QuicStreamId headers_stream_id =
@@ -1712,7 +1805,7 @@ TEST_P(QuicSessionTestServer, NoPendingStreams) {
}
TEST_P(QuicSessionTestServer, PendingStreams) {
- if (!VersionHasIetfQuicFrames(transport_version())) {
+ if (!VersionHasStreamType(transport_version())) {
return;
}
session_.set_uses_pending_streams(true);
@@ -1721,15 +1814,17 @@ TEST_P(QuicSessionTestServer, PendingStreams) {
transport_version(), Perspective::IS_CLIENT);
QuicStreamFrame data1(stream_id, true, 10, QuicStringPiece("HT"));
session_.OnStreamFrame(data1);
+ EXPECT_TRUE(QuicSessionPeer::GetPendingStream(&session_, stream_id));
EXPECT_EQ(0, session_.num_incoming_streams_created());
QuicStreamFrame data2(stream_id, false, 0, QuicStringPiece("HT"));
session_.OnStreamFrame(data2);
+ EXPECT_FALSE(QuicSessionPeer::GetPendingStream(&session_, stream_id));
EXPECT_EQ(1, session_.num_incoming_streams_created());
}
TEST_P(QuicSessionTestServer, RstPendingStreams) {
- if (!VersionHasIetfQuicFrames(transport_version())) {
+ if (!VersionHasStreamType(transport_version())) {
return;
}
session_.set_uses_pending_streams(true);
@@ -1738,6 +1833,7 @@ TEST_P(QuicSessionTestServer, RstPendingStreams) {
transport_version(), Perspective::IS_CLIENT);
QuicStreamFrame data1(stream_id, true, 10, QuicStringPiece("HT"));
session_.OnStreamFrame(data1);
+ EXPECT_TRUE(QuicSessionPeer::GetPendingStream(&session_, stream_id));
EXPECT_EQ(0, session_.num_incoming_streams_created());
EXPECT_EQ(0u, session_.GetNumOpenIncomingStreams());
@@ -1747,17 +1843,35 @@ TEST_P(QuicSessionTestServer, RstPendingStreams) {
QuicRstStreamFrame rst1(kInvalidControlFrameId, stream_id,
QUIC_ERROR_PROCESSING_STREAM, 12);
session_.OnRstStream(rst1);
+ EXPECT_FALSE(QuicSessionPeer::GetPendingStream(&session_, stream_id));
EXPECT_EQ(0, session_.num_incoming_streams_created());
EXPECT_EQ(0u, session_.GetNumOpenIncomingStreams());
QuicStreamFrame data2(stream_id, false, 0, QuicStringPiece("HT"));
session_.OnStreamFrame(data2);
+ EXPECT_FALSE(QuicSessionPeer::GetPendingStream(&session_, stream_id));
+ EXPECT_EQ(0, session_.num_incoming_streams_created());
+ EXPECT_EQ(0u, session_.GetNumOpenIncomingStreams());
+}
+
+TEST_P(QuicSessionTestServer, OnFinPendingStreams) {
+ if (!VersionHasStreamType(transport_version())) {
+ return;
+ }
+ session_.set_uses_pending_streams(true);
+
+ QuicStreamId stream_id = QuicUtils::GetFirstUnidirectionalStreamId(
+ transport_version(), Perspective::IS_CLIENT);
+ QuicStreamFrame data(stream_id, true, 0, "");
+ session_.OnStreamFrame(data);
+
+ EXPECT_FALSE(QuicSessionPeer::GetPendingStream(&session_, stream_id));
EXPECT_EQ(0, session_.num_incoming_streams_created());
EXPECT_EQ(0u, session_.GetNumOpenIncomingStreams());
}
TEST_P(QuicSessionTestServer, PendingStreamOnWindowUpdate) {
- if (!VersionHasIetfQuicFrames(transport_version())) {
+ if (!VersionHasStreamType(transport_version())) {
return;
}
@@ -1766,6 +1880,7 @@ TEST_P(QuicSessionTestServer, PendingStreamOnWindowUpdate) {
transport_version(), Perspective::IS_CLIENT);
QuicStreamFrame data1(stream_id, true, 10, QuicStringPiece("HT"));
session_.OnStreamFrame(data1);
+ EXPECT_TRUE(QuicSessionPeer::GetPendingStream(&session_, stream_id));
EXPECT_EQ(0, session_.num_incoming_streams_created());
QuicWindowUpdateFrame window_update_frame(kInvalidControlFrameId, stream_id,
0);
@@ -2579,6 +2694,31 @@ TEST_P(QuicSessionTestServer, OnStopSendingInputValidStream) {
EXPECT_TRUE(stream->write_side_closed());
}
+TEST_P(QuicSessionTestServer, WriteBufferedCryptoFrames) {
+ if (!QuicVersionUsesCryptoFrames(connection_->transport_version())) {
+ return;
+ }
+ std::string data(1350, 'a');
+ TestCryptoStream* crypto_stream = session_.GetMutableCryptoStream();
+ // Only consumed 1000 bytes.
+ EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_INITIAL, 1350, 0))
+ .WillOnce(Return(1000));
+ crypto_stream->WriteCryptoData(ENCRYPTION_INITIAL, data);
+ EXPECT_TRUE(session_.HasPendingHandshake());
+ EXPECT_TRUE(session_.WillingAndAbleToWrite());
+
+ EXPECT_CALL(*connection_, SendCryptoData(_, _, _)).Times(0);
+ crypto_stream->WriteCryptoData(ENCRYPTION_ZERO_RTT, data);
+
+ EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_INITIAL, 350, 1000))
+ .WillOnce(Return(350));
+ EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_ZERO_RTT, 1350, 0))
+ .WillOnce(Return(1350));
+ session_.OnCanWrite();
+ EXPECT_FALSE(session_.HasPendingHandshake());
+ EXPECT_FALSE(session_.WillingAndAbleToWrite());
+}
+
} // namespace
} // namespace test
} // namespace quic
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 8ef4717dc7a..eb8b96ba491 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
@@ -58,13 +58,12 @@ PendingStream::PendingStream(QuicStreamId id, QuicSession* session)
sequencer_(this) {}
void PendingStream::OnDataAvailable() {
- // It will be called when pending stream receives its first byte. But this
- // call should simply be ignored so that data remains in sequencer.
+ // Data should be kept in the sequencer so that
+ // QuicSession::ProcessPendingStream() can read it.
}
void PendingStream::OnFinRead() {
- QUIC_BUG << "OnFinRead should not be called.";
- CloseConnectionWithDetails(QUIC_INTERNAL_ERROR, "Unexpected fin read");
+ DCHECK(sequencer_.IsClosed());
}
void PendingStream::AddBytesConsumed(QuicByteCount bytes) {
@@ -74,6 +73,7 @@ void PendingStream::AddBytesConsumed(QuicByteCount bytes) {
}
void PendingStream::Reset(QuicRstStreamErrorCode error) {
+ // TODO: RESET_STREAM must not be sent for READ_UNIDIRECTIONAL stream.
session_->SendRstStream(id_, error, 0);
}
@@ -173,6 +173,11 @@ void PendingStream::MarkConsumed(size_t num_bytes) {
sequencer_.MarkConsumed(num_bytes);
}
+void PendingStream::StopReading() {
+ QUIC_DVLOG(1) << "Stop reading from pending stream " << id();
+ sequencer_.StopReading();
+}
+
QuicStream::QuicStream(PendingStream* pending, StreamType type, bool is_static)
: QuicStream(pending->id_,
pending->session_,
@@ -236,7 +241,12 @@ QuicStream::QuicStream(QuicStreamId id,
: sequencer_(std::move(sequencer)),
id_(id),
session_(session),
- priority_(kDefaultPriority),
+ precedence_(
+ session->use_http2_priority_write_scheduler()
+ ? spdy::SpdyStreamPrecedence(0,
+ spdy::kHttp2DefaultStreamWeight,
+ false)
+ : spdy::SpdyStreamPrecedence(kDefaultPriority)),
stream_bytes_read_(stream_bytes_read),
stream_error_(QUIC_STREAM_NO_ERROR),
connection_error_(QUIC_NO_ERROR),
@@ -276,7 +286,7 @@ QuicStream::QuicStream(QuicStreamId id,
}
SetFromConfig();
if (type_ != CRYPTO) {
- session_->RegisterStreamPriority(id, is_static_, priority_);
+ session_->RegisterStreamPriority(id, is_static_, precedence_);
}
}
@@ -432,13 +442,13 @@ void QuicStream::CloseConnectionWithDetails(QuicErrorCode error,
error, details, ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
}
-SpdyPriority QuicStream::priority() const {
- return priority_;
+const spdy::SpdyStreamPrecedence& QuicStream::precedence() const {
+ return precedence_;
}
-void QuicStream::SetPriority(SpdyPriority priority) {
- priority_ = priority;
- session_->UpdateStreamPriority(id(), priority);
+void QuicStream::SetPriority(const spdy::SpdyStreamPrecedence& precedence) {
+ precedence_ = precedence;
+ session_->UpdateStreamPriority(id(), precedence);
}
void QuicStream::WriteOrBufferData(
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 6f5536d3991..c8e5012767a 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
@@ -78,6 +78,10 @@ class QUIC_EXPORT_PRIVATE PendingStream
void MarkConsumed(size_t num_bytes);
+ // Tells the sequencer to ignore all incoming data itself and not call
+ // OnDataAvailable().
+ void StopReading();
+
private:
friend class QuicStream;
@@ -176,11 +180,11 @@ class QUIC_EXPORT_PRIVATE QuicStream
virtual void OnConnectionClosed(QuicErrorCode error,
ConnectionCloseSource source);
- spdy::SpdyPriority priority() const;
+ const spdy::SpdyStreamPrecedence& precedence() const;
// Sets priority_ to priority. This should only be called before bytes are
// written to the server.
- void SetPriority(spdy::SpdyPriority priority);
+ void SetPriority(const spdy::SpdyStreamPrecedence& precedence);
// Returns true if this stream is still waiting for acks of sent data.
// This will return false if all data has been acked, or if the stream
@@ -456,8 +460,8 @@ class QUIC_EXPORT_PRIVATE QuicStream
QuicStreamId id_;
// Pointer to the owning QuicSession object.
QuicSession* session_;
- // The priority of the stream, once parsed.
- spdy::SpdyPriority priority_;
+ // The precedence of the stream, once parsed.
+ spdy::SpdyStreamPrecedence precedence_;
// Bytes read refers to payload bytes only: they do not include framing,
// encryption overhead etc.
uint64_t stream_bytes_read_;
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager.cc b/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager.cc
index f38477688e0..440b97adc19 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager.cc
@@ -30,14 +30,12 @@ QuicStreamIdManager::QuicStreamIdManager(
outgoing_max_streams_(max_allowed_outgoing_streams),
next_outgoing_stream_id_(GetFirstOutgoingStreamId()),
outgoing_stream_count_(0),
- outgoing_static_stream_count_(0),
using_default_max_streams_(true),
incoming_actual_max_streams_(max_allowed_incoming_streams),
// Advertised max starts at actual because it's communicated in the
// handshake.
incoming_advertised_max_streams_(max_allowed_incoming_streams),
incoming_initial_max_open_streams_(max_allowed_incoming_streams),
- incoming_static_stream_count_(0),
incoming_stream_count_(0),
largest_peer_created_stream_id_(
QuicUtils::GetInvalidStreamId(transport_version())),
@@ -55,7 +53,7 @@ bool QuicStreamIdManager::OnMaxStreamsFrame(const QuicMaxStreamsFrame& frame) {
const QuicStreamCount current_outgoing_max_streams = outgoing_max_streams_;
// Set the limit to be exactly the stream count in the frame.
- if (!ConfigureMaxOpenOutgoingStreams(frame.stream_count)) {
+ if (!SetMaxOpenOutgoingStreams(frame.stream_count)) {
return false;
}
// If we were at the previous limit and this MAX_STREAMS frame
@@ -99,8 +97,7 @@ bool QuicStreamIdManager::OnStreamsBlockedFrame(
// Used when configuration has been done and we have an initial
// maximum stream count from the peer.
-bool QuicStreamIdManager::ConfigureMaxOpenOutgoingStreams(
- size_t max_open_streams) {
+bool QuicStreamIdManager::SetMaxOpenOutgoingStreams(size_t max_open_streams) {
if (using_default_max_streams_) {
// This is the first MAX_STREAMS/transport negotiation we've received. Treat
// this a bit differently than later ones. The difference is that
@@ -133,43 +130,11 @@ bool QuicStreamIdManager::ConfigureMaxOpenOutgoingStreams(
return true;
}
-void QuicStreamIdManager::SetMaxOpenOutgoingStreams(size_t max_open_streams) {
- QUIC_BUG_IF(!using_default_max_streams_);
- // TODO(fkastenholz): when static streams are removed from I-Quic, this
- // should be revised to invoke ConfigureMaxOpen...
- AdjustMaxOpenOutgoingStreams(max_open_streams);
-}
-
-// Adjust the outgoing stream limit - max_open_streams is the limit, not
-// including static streams. If the new stream limit wraps, will peg
-// the limit at the implementation max.
-// TODO(fkastenholz): AdjustMax is cognizant of the number of static streams and
-// sets the maximum to be max_streams + number_of_statics. This should be
-// removed from IETF QUIC when static streams are gone.
-void QuicStreamIdManager::AdjustMaxOpenOutgoingStreams(
- size_t max_open_streams) {
- if ((outgoing_static_stream_count_ + max_open_streams) < max_open_streams) {
- // New limit causes us to wrap, set limit to be the implementation maximum.
- ConfigureMaxOpenOutgoingStreams(
- QuicUtils::GetMaxStreamCount(unidirectional_, perspective()));
- return;
- }
- // Does not wrap, set limit to what is requested.
- ConfigureMaxOpenOutgoingStreams(outgoing_static_stream_count_ +
- max_open_streams);
-}
-
void QuicStreamIdManager::SetMaxOpenIncomingStreams(size_t max_open_streams) {
QuicStreamCount implementation_max =
QuicUtils::GetMaxStreamCount(unidirectional_, perspective());
- QuicStreamCount new_max =
- std::min(implementation_max,
- static_cast<QuicStreamCount>(max_open_streams +
- incoming_static_stream_count_));
- if (new_max < max_open_streams) {
- // wrapped around ...
- new_max = implementation_max;
- }
+ QuicStreamCount new_max = std::min(
+ implementation_max, static_cast<QuicStreamCount>(max_open_streams));
if (new_max < incoming_stream_count_) {
session_->connection()->CloseConnection(
QUIC_MAX_STREAMS_ERROR, "Stream limit less than existing stream count",
@@ -221,7 +186,8 @@ QuicStreamId QuicStreamIdManager::GetNextOutgoingStreamId() {
// TODO(fkastenholz): Should we close the connection?
QUIC_BUG_IF(outgoing_stream_count_ >= outgoing_max_streams_)
<< "Attempt to allocate a new outgoing stream that would exceed the "
- "limit";
+ "limit ("
+ << outgoing_max_streams_ << ")";
QuicStreamId id = next_outgoing_stream_id_;
next_outgoing_stream_id_ += QuicUtils::StreamIdDelta(transport_version());
outgoing_stream_count_++;
@@ -239,63 +205,6 @@ bool QuicStreamIdManager::CanOpenNextOutgoingStream() {
return false;
}
-bool QuicStreamIdManager::RegisterStaticStream(QuicStreamId stream_id,
- bool stream_already_counted) {
- DCHECK_NE(QuicUtils::IsBidirectionalStreamId(stream_id), unidirectional_);
- if (IsIncomingStream(stream_id)) {
- // This code is predicated on static stream ids being allocated densely, in
- // order, and starting with the first stream allowed. QUIC_BUG if this is
- // not so.
- // This is a stream id for a stream that is started by the peer, deal with
- // the incoming stream ids. Increase the floor and adjust everything
- // accordingly.
-
- QUIC_BUG_IF(incoming_actual_max_streams_ >
- QuicUtils::GetMaxStreamCount(unidirectional_, perspective()));
-
- // If we have reached the limit on stream creation, do not create
- // the static stream; return false.
- if (incoming_stream_count_ >=
- QuicUtils::GetMaxStreamCount(unidirectional_, perspective())) {
- return false;
- }
-
- if (incoming_actual_max_streams_ <
- QuicUtils::GetMaxStreamCount(unidirectional_, perspective())) {
- incoming_actual_max_streams_++;
- }
- if (incoming_advertised_max_streams_ <
- QuicUtils::GetMaxStreamCount(unidirectional_, perspective())) {
- incoming_advertised_max_streams_++;
- }
-
- if (!stream_already_counted) {
- incoming_stream_count_++;
- }
- incoming_static_stream_count_++;
- return true;
- }
-
- QUIC_BUG_IF(!using_default_max_streams_)
- << "Attempted to allocate static stream (id " << stream_id
- << ") after receiving a MAX_STREAMS frame";
-
- // If we have reached the limit on stream creation, do not create
- // the static stream; return false.
- if (outgoing_max_streams_ >=
- QuicUtils::GetMaxStreamCount(unidirectional_, perspective())) {
- return false;
- }
-
- // Increase the outgoing_max_streams_ limit to reflect the semantic that
- // outgoing_max_streams_ was inialized to a "maximum request/response" count
- // and only becomes a maximum stream count when we receive the first
- // MAX_STREAMS.
- outgoing_max_streams_++;
- outgoing_static_stream_count_++;
- return true;
-}
-
// Stream_id is the id of a new incoming stream. Check if it can be
// created (doesn't violate limits, etc).
bool QuicStreamIdManager::MaybeIncreaseLargestPeerStreamId(
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager.h b/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager.h
index d0b08246204..baba5ac8a3e 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager.h
@@ -47,12 +47,10 @@ class QUIC_EXPORT_PRIVATE QuicStreamIdManager {
", outgoing_max_streams_: ", outgoing_max_streams_,
", next_outgoing_stream_id_: ", next_outgoing_stream_id_,
", outgoing_stream_count_: ", outgoing_stream_count_,
- ", outgoing_static_stream_count_: ", outgoing_static_stream_count_,
", using_default_max_streams_: ", using_default_max_streams_,
", incoming_actual_max_streams_: ", incoming_actual_max_streams_,
", incoming_advertised_max_streams_: ",
incoming_advertised_max_streams_,
- ", incoming_static_stream_count_: ", incoming_static_stream_count_,
", incoming_stream_count_: ", incoming_stream_count_,
", available_streams_.size(): ", available_streams_.size(),
", largest_peer_created_stream_id_: ", largest_peer_created_stream_id_,
@@ -88,37 +86,14 @@ class QUIC_EXPORT_PRIVATE QuicStreamIdManager {
// allocates a stream ID past the peer specified limit.
QuicStreamId GetNextOutgoingStreamId();
- // Set the outgoing stream limits to be |max_open_streams| plus the number
- // of static streams that have been opened. For outgoing and incoming,
- // respectively.
- // SetMaxOpenOutgoingStreams will QUIC_BUG if it is called after
- // a MAX_STREAMS frame has been received.
- // TODO(fkastenholz): When static streams disappear, these should be removed.
- void SetMaxOpenOutgoingStreams(size_t max_open_streams);
void SetMaxOpenIncomingStreams(size_t max_open_streams);
- // Adjust the outgoing stream limit - max_open_streams is the limit, not
- // including static streams. Does not QUIC_BUG if it is called _after_
- // receiving a MAX_STREAMS.
- void AdjustMaxOpenOutgoingStreams(size_t max_open_streams);
-
// Sets the maximum number of outgoing streams to max_open_streams.
// Used when configuration has been done and we have an initial
// maximum stream count from the peer. Note that if the stream count is such
// that it would result in stream ID values that are greater than the
// implementation limit, it pegs the count at the implementation limit.
- bool ConfigureMaxOpenOutgoingStreams(size_t max_open_streams);
-
- // Register a new stream as a static stream. This is used so that the
- // advertised MAX STREAMS can be calculated based on the start of the
- // dynamic stream space. This method will take any stream ID, one that either
- // this node or the peer will initiate.
- // If |stream_already_counted| is true, the stream is already counted as an
- // open stream else where, so no need to count it again.
- // Returns false if this fails because the new static stream would cause the
- // stream limit to be exceeded.
- bool RegisterStaticStream(QuicStreamId stream_id,
- bool stream_already_counted);
+ bool SetMaxOpenOutgoingStreams(size_t max_open_streams);
// Checks if the incoming stream ID exceeds the MAX_STREAMS limit. If the
// limit is exceeded, closes the connection and returns false. Uses the
@@ -134,10 +109,6 @@ class QUIC_EXPORT_PRIVATE QuicStreamIdManager {
// Return true if given stream is peer initiated.
bool IsIncomingStream(QuicStreamId id) const;
- size_t outgoing_static_stream_count() const {
- return outgoing_static_stream_count_;
- }
-
size_t incoming_initial_max_open_streams() const {
return incoming_initial_max_open_streams_;
}
@@ -203,8 +174,6 @@ class QUIC_EXPORT_PRIVATE QuicStreamIdManager {
bool unidirectional_;
// This is the number of streams that this node can initiate.
- // This limit applies to both static and dynamic streams - the total
- // of the two can not exceed this count.
// This limit is:
// - Initiated to a value specified in the constructor
// - May be updated when the config is received.
@@ -219,11 +188,6 @@ class QUIC_EXPORT_PRIVATE QuicStreamIdManager {
// outgoing_max_streams_.
QuicStreamCount outgoing_stream_count_;
- // Number of outgoing static streams created.
- // TODO(fkastenholz): Remove when static streams no longer supported for IETF
- // QUIC.
- QuicStreamCount outgoing_static_stream_count_;
-
// Set to true while the default (from the constructor) outgoing stream limit
// is in use. It is set to false when either a MAX STREAMS frame is received
// or the transport negotiation completes and sets the stream limit (this is
@@ -232,12 +196,7 @@ class QUIC_EXPORT_PRIVATE QuicStreamIdManager {
// until we receive an authoritative value from the peer.
// outgoing_max_streams_ is initialized in the constructor
// to some hard-coded value, which may or may not be consistent
- // with what the peer wants. Furthermore, as we create outgoing
- // static streams, the cap raises as static streams get inserted
- // "beneath" the dynamic streams because, prior to receiving
- // a MAX_STREAMS, the values setting the limit are interpreted
- // as "number of request/responses" that can be created. Once
- // a MAX_STREAMS is received, it becomes a hard limit.
+ // with what the peer wants.
bool using_default_max_streams_;
// FOR INCOMING STREAMS
@@ -249,11 +208,6 @@ class QUIC_EXPORT_PRIVATE QuicStreamIdManager {
// Initial maximum on the number of open streams allowed.
QuicStreamCount incoming_initial_max_open_streams_;
- // Number of outgoing static streams created.
- // TODO(fkastenholz): Remove when static streams no longer supported for IETF
- // QUIC.
- QuicStreamCount incoming_static_stream_count_;
-
// This is the number of streams that have been created -- some are still
// open, the others have been closed. It is the number that is compared
// against MAX_STREAMS when deciding whether to accept a new stream or not.
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager_test.cc
index 30ff954f236..19e4d59fe14 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager_test.cc
@@ -194,18 +194,8 @@ INSTANTIATE_TEST_SUITE_P(Tests, QuicStreamIdManagerTestClient, testing::Bool());
TEST_P(QuicStreamIdManagerTestClient, StreamIdManagerClientInitialization) {
// These fields are inited via the QuicSession constructor to default
// values defined as a constant.
- // If bidi, Crypto stream default created at start up, it is one
- // more stream to account for since initialization is "number of
- // request/responses" & crypto is added in to that, not streams.
- size_t extra_stream_count = 0;
- if (GetParam() && !QuicVersionUsesCryptoFrames(transport_version())) {
- extra_stream_count = 1;
- }
- EXPECT_EQ(kDefaultMaxStreamsPerConnection + extra_stream_count,
+ EXPECT_EQ(kDefaultMaxStreamsPerConnection,
stream_id_manager_->outgoing_max_streams());
- // Test is predicated on having 1 static stream going if bidi, 0 if not...)
- EXPECT_EQ(extra_stream_count,
- stream_id_manager_->outgoing_static_stream_count());
EXPECT_EQ(kDefaultMaxStreamsPerConnection,
stream_id_manager_->incoming_actual_max_streams());
@@ -230,29 +220,6 @@ TEST_P(QuicStreamIdManagerTestClient, CheckMaxStreamsWindow1) {
EXPECT_EQ(1u, stream_id_manager_->max_streams_window());
}
-// Test that stream counts that would exceed the implementation maximum are
-// safely handled.
-// First, check that setting up to and including the implementation maximum
-// is OK.
-TEST_P(QuicStreamIdManagerTestClient, CheckMaxStreamsBadValuesToMaxOkOutgoing) {
- QuicStreamCount implementation_max =
- QuicUtils::GetMaxStreamCount(!GetParam(), /* GetParam==true for bidi */
- Perspective::IS_CLIENT);
- stream_id_manager_->AdjustMaxOpenOutgoingStreams(implementation_max - 1u);
- // If bidi, Crypto stream default created at start up, it is one
- // more stream to account for since initialization is "number of
- // request/responses" & crypto is added in to that, not streams.
- size_t extra_stream_count = 0;
- if (GetParam() && !QuicVersionUsesCryptoFrames(transport_version())) {
- extra_stream_count = 1;
- }
- EXPECT_EQ(implementation_max - 1u + extra_stream_count,
- stream_id_manager_->outgoing_max_streams());
-
- stream_id_manager_->AdjustMaxOpenOutgoingStreams(implementation_max);
- EXPECT_EQ(implementation_max, stream_id_manager_->outgoing_max_streams());
-}
-
// Now check that setting to a value larger than the maximum fails.
TEST_P(QuicStreamIdManagerTestClient,
CheckMaxStreamsBadValuesOverMaxFailsOutgoing) {
@@ -263,7 +230,7 @@ TEST_P(QuicStreamIdManagerTestClient,
EXPECT_LT(stream_id_manager_->outgoing_max_streams(), implementation_max);
// Try to go over.
- stream_id_manager_->AdjustMaxOpenOutgoingStreams(implementation_max + 1);
+ stream_id_manager_->SetMaxOpenOutgoingStreams(implementation_max + 1);
// Should be pegged at the max.
EXPECT_EQ(implementation_max, stream_id_manager_->outgoing_max_streams());
}
@@ -388,15 +355,14 @@ TEST_P(QuicStreamIdManagerTestClient, StreamIdManagerClientOnMaxStreamsFrame) {
QuicStreamCount initial_stream_count =
// need to know the number of request/response streams.
// This is the total number of outgoing streams (which includes both
- // req/resp and statics) minus just the statics...
- stream_id_manager_->outgoing_max_streams() -
- stream_id_manager_->outgoing_static_stream_count();
+ // req/resp and statics).
+ stream_id_manager_->outgoing_max_streams();
QuicMaxStreamsFrame frame;
// Even though the stream count in the frame is < the initial maximum,
- // it is should be ignored since the initial max was set via
- // the constructor (an educated guess) and the MAX STREAMS frame
+ // it shouldn't be ignored since the initial max was set via
+ // the constructor (an educated guess) but the MAX STREAMS frame
// is authoritative.
frame.stream_count = initial_stream_count - 1;
@@ -491,20 +457,12 @@ TEST_P(QuicStreamIdManagerTestClient, StreamIdManagerOnStreamsBlockedFrame) {
TEST_P(QuicStreamIdManagerTestClient, StreamIdManagerGetNextOutgoingStream) {
// Number of streams we can open and the first one we should get when
// opening...
- int number_of_streams = kDefaultMaxStreamsPerConnection;
+ size_t number_of_streams = kDefaultMaxStreamsPerConnection;
QuicStreamId stream_id =
IsUnidi() ? session_->next_outgoing_unidirectional_stream_id()
: session_->next_outgoing_bidirectional_stream_id();
- // If bidi, Crypto stream default created at start up, it is one
- // more stream to account for since initialization is "number of
- // request/responses" & crypto is added in to that, not streams.
- size_t extra_stream_count = 0;
- if (IsBidi() && !QuicVersionUsesCryptoFrames(transport_version())) {
- extra_stream_count = 1;
- }
- EXPECT_EQ(number_of_streams + extra_stream_count,
- stream_id_manager_->outgoing_max_streams());
+ EXPECT_EQ(number_of_streams, stream_id_manager_->outgoing_max_streams());
while (number_of_streams) {
EXPECT_TRUE(stream_id_manager_->CanOpenNextOutgoingStream());
EXPECT_EQ(stream_id, stream_id_manager_->GetNextOutgoingStreamId());
@@ -522,7 +480,7 @@ TEST_P(QuicStreamIdManagerTestClient, StreamIdManagerGetNextOutgoingStream) {
// If bidi, Crypto stream default created at start up, it is one
// more stream to account for since initialization is "number of
// request/responses" & crypto is added in to that, not streams.
- EXPECT_EQ(kDefaultMaxStreamsPerConnection + extra_stream_count,
+ EXPECT_EQ(kDefaultMaxStreamsPerConnection,
session_->save_frame().max_streams_frame.stream_count);
// If we try to get the next id (above the limit), it should cause a quic-bug.
EXPECT_QUIC_BUG(
@@ -625,46 +583,6 @@ TEST_P(QuicStreamIdManagerTestClient, StreamIdManagerServerMaxStreams) {
session_->save_frame().max_streams_frame.stream_count);
}
-// Test that registering static stream IDs causes the stream limit to rise
-// accordingly. This is server/client agnostic.
-TEST_P(QuicStreamIdManagerTestClient, TestStaticStreamAdjustment) {
- QuicStreamId first_dynamic =
- QuicStreamIdManagerPeer::GetFirstIncomingStreamId(stream_id_manager_);
- QuicStreamCount actual_max =
- stream_id_manager_->incoming_actual_max_streams();
-
- // First test will register the first dynamic stream id as being for a static
- // stream.
- stream_id_manager_->RegisterStaticStream(first_dynamic,
- /*stream_already_counted = */ false);
- // Should go up by 1 stream/stream id.
- EXPECT_EQ(actual_max + 1u, stream_id_manager_->incoming_actual_max_streams());
-}
-
-// Check that the OnMaxStreamFrame logic properly handles all the
-// cases of offered max streams and outgoing_static_stream_count_,
-// checking for the wrap conditions. Tests in client perspective, necessary
-// because internally, some calculations depend on the client/server
-// perspective.
-TEST_P(QuicStreamIdManagerTestClient, TestMaxStreamsWrapChecks) {
- QuicStreamCount max_stream_count =
- QuicUtils::GetMaxStreamCount(IsUnidi(), Perspective::IS_CLIENT);
- QuicMaxStreamsFrame frame;
- frame.unidirectional = IsUnidi();
-
- // Check the case where the offered stream count is less than the
- // maximum
- frame.stream_count = max_stream_count - 10;
- EXPECT_TRUE(stream_id_manager_->OnMaxStreamsFrame(frame));
- EXPECT_EQ(max_stream_count - 10u, stream_id_manager_->outgoing_max_streams());
-
- // Now check if the offered count is larger than the max.
- // The count should be pegged at the max.
- frame.stream_count = max_stream_count + 10;
- EXPECT_TRUE(stream_id_manager_->OnMaxStreamsFrame(frame));
- EXPECT_EQ(max_stream_count, stream_id_manager_->outgoing_max_streams());
-}
-
// Check that edge conditions of the stream count in a STREAMS_BLOCKED frame
// are. properly handled.
TEST_P(QuicStreamIdManagerTestClient, StreamsBlockedEdgeConditions) {
@@ -787,15 +705,8 @@ TEST_P(QuicStreamIdManagerTestServer, StreamIdManagerServerInitialization) {
// values defined as a constant.
EXPECT_EQ(kDefaultMaxStreamsPerConnection,
stream_id_manager_->incoming_initial_max_open_streams());
- // If bidi, Crypto stream default created at start up, it is one
- // more stream to account for since initialization is "number of
- // request/responses" & crypto is added in to that, not streams.
- // Since this is the server, the stream is incoming.
- size_t extra_stream_count = 0;
- if (IsBidi() && !QuicVersionUsesCryptoFrames(transport_version())) {
- extra_stream_count = 1;
- }
- EXPECT_EQ(kDefaultMaxStreamsPerConnection + extra_stream_count,
+
+ EXPECT_EQ(kDefaultMaxStreamsPerConnection,
stream_id_manager_->incoming_actual_max_streams());
EXPECT_EQ(kDefaultMaxStreamsPerConnection,
stream_id_manager_->outgoing_max_streams());
@@ -843,30 +754,6 @@ TEST_P(QuicStreamIdManagerTestServer, ExtremeMaybeIncreaseLargestPeerStreamId) {
stream_id_manager_->MaybeIncreaseLargestPeerStreamId(too_big_stream_id));
}
-// Check that the OnMaxStreamFrame logic properly handles all the
-// cases of offered max streams and outgoing_static_stream_count_,
-// checking for the wrap conditions. Tests in server perspective, necessary
-// because internally, some calculations depend on the client/server
-// perspective.
-TEST_P(QuicStreamIdManagerTestServer, TestMaxStreamsWrapChecks) {
- QuicStreamCount max_stream_count =
- QuicUtils::GetMaxStreamCount(IsUnidi(), Perspective::IS_SERVER);
- QuicMaxStreamsFrame frame;
- frame.unidirectional = IsUnidi();
-
- // Check the case where the offered stream count is less than the
- // implementation maximum,
- frame.stream_count = max_stream_count - 10;
- EXPECT_TRUE(stream_id_manager_->OnMaxStreamsFrame(frame));
- EXPECT_EQ(max_stream_count - 10u, stream_id_manager_->outgoing_max_streams());
-
- // Check the case where the offered stream count is greater than the
- // implementation maximum. The count should peg at the maximum.
- frame.stream_count = max_stream_count + 10;
- EXPECT_TRUE(stream_id_manager_->OnMaxStreamsFrame(frame));
- EXPECT_EQ(max_stream_count, stream_id_manager_->outgoing_max_streams());
-}
-
} // namespace
} // namespace test
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer.cc b/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer.cc
index 9e47a6f4e34..dc7b0cd291d 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
@@ -16,6 +16,7 @@
#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_clock.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
@@ -42,10 +43,16 @@ void QuicStreamSequencer::OnStreamFrame(const QuicStreamFrame& frame) {
const size_t data_len = frame.data_length;
if (frame.fin) {
- CloseStreamAtOffset(frame.offset + data_len);
+ bool should_process_data = CloseStreamAtOffset(frame.offset + data_len);
if (data_len == 0) {
return;
}
+ if (GetQuicReloadableFlag(quic_no_stream_data_after_reset)) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_no_stream_data_after_reset);
+ if (!should_process_data) {
+ return;
+ }
+ }
}
OnFrameData(byte_offset, data_len, frame.data_buffer);
}
@@ -109,24 +116,25 @@ void QuicStreamSequencer::OnFrameData(QuicStreamOffset byte_offset,
}
}
-void QuicStreamSequencer::CloseStreamAtOffset(QuicStreamOffset offset) {
+bool QuicStreamSequencer::CloseStreamAtOffset(QuicStreamOffset offset) {
const QuicStreamOffset kMaxOffset =
std::numeric_limits<QuicStreamOffset>::max();
// If there is a scheduled close, the new offset should match it.
if (close_offset_ != kMaxOffset && offset != close_offset_) {
stream_->Reset(QUIC_MULTIPLE_TERMINATION_OFFSETS);
- return;
+ return false;
}
close_offset_ = offset;
MaybeCloseStream();
+ return true;
}
-bool QuicStreamSequencer::MaybeCloseStream() {
+void QuicStreamSequencer::MaybeCloseStream() {
if (blocked_ || !IsClosed()) {
- return false;
+ return;
}
QUIC_DVLOG(1) << "Passing up termination, as we've processed "
@@ -143,7 +151,6 @@ bool QuicStreamSequencer::MaybeCloseStream() {
stream_->OnDataAvailable();
}
buffered_frames_.Clear();
- return true;
}
int QuicStreamSequencer::GetReadableRegions(iovec* iov, size_t iov_len) const {
@@ -162,11 +169,6 @@ bool QuicStreamSequencer::PeekRegion(QuicStreamOffset offset,
return buffered_frames_.PeekRegion(offset, iov);
}
-bool QuicStreamSequencer::PrefetchNextRegion(iovec* iov) {
- DCHECK(!blocked_);
- return buffered_frames_.PrefetchNextRegion(iov);
-}
-
void QuicStreamSequencer::Read(std::string* buffer) {
DCHECK(!blocked_);
buffer->resize(buffer->size() + ReadableBytes());
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 5888a4a3cd8..a735a1ebbf5 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
@@ -86,10 +86,6 @@ class QUIC_EXPORT_PRIVATE QuicStreamSequencer {
// not been received yet or has already been consumed.
bool PeekRegion(QuicStreamOffset offset, iovec* iov) const;
- // Fills in one iovec with the next unread region.
- // Returns false if no readable region is available.
- bool PrefetchNextRegion(iovec* iov);
-
// Copies the data into the iov_len buffers provided. Returns the number of
// bytes read. Any buffered data no longer in use will be released.
// TODO(rch): remove this method and instead implement it as a helper method
@@ -167,11 +163,13 @@ class QUIC_EXPORT_PRIVATE QuicStreamSequencer {
void FlushBufferedFrames();
// Wait until we've seen 'offset' bytes, and then terminate the stream.
- void CloseStreamAtOffset(QuicStreamOffset offset);
+ // Returns true if |stream_| is still available to receive data, and false if
+ // |stream_| is reset.
+ bool CloseStreamAtOffset(QuicStreamOffset offset);
// If we've received a FIN and have processed all remaining data, then inform
// the stream of FIN, and clear buffers.
- bool MaybeCloseStream();
+ void MaybeCloseStream();
// Shared implementation between OnStreamFrame and OnCryptoFrame.
void OnFrameData(QuicStreamOffset byte_offset,
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 e68925b1fc7..89a6ad750f3 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
@@ -33,8 +33,7 @@ QuicStreamSequencerBuffer::QuicStreamSequencerBuffer(size_t max_capacity_bytes)
: max_buffer_capacity_bytes_(max_capacity_bytes),
blocks_count_(CalculateBlockCount(max_capacity_bytes)),
total_bytes_read_(0),
- blocks_(nullptr),
- total_bytes_prefetched_(0) {
+ blocks_(nullptr) {
Clear();
}
@@ -53,7 +52,6 @@ void QuicStreamSequencerBuffer::Clear() {
num_bytes_buffered_ = 0;
bytes_received_.Clear();
bytes_received_.Add(0, total_bytes_read_);
- total_bytes_prefetched_ = total_bytes_read_;
}
bool QuicStreamSequencerBuffer::RetireBlock(size_t idx) {
@@ -267,8 +265,6 @@ QuicErrorCode QuicStreamSequencerBuffer::Readv(const iovec* dest_iov,
}
}
}
- total_bytes_prefetched_ =
- std::max(total_bytes_prefetched_, total_bytes_read_);
return QUIC_NO_ERROR;
}
@@ -367,19 +363,6 @@ bool QuicStreamSequencerBuffer::PeekRegion(QuicStreamOffset offset,
return true;
}
-bool QuicStreamSequencerBuffer::PrefetchNextRegion(iovec* iov) {
- DCHECK(iov);
- DCHECK_LE(total_bytes_read_, total_bytes_prefetched_);
- DCHECK_LE(total_bytes_prefetched_, FirstMissingByte());
-
- if (!PeekRegion(total_bytes_prefetched_, iov)) {
- return false;
- }
-
- total_bytes_prefetched_ += iov->iov_len;
- return true;
-}
-
bool QuicStreamSequencerBuffer::MarkConsumed(size_t bytes_used) {
if (bytes_used > ReadableBytes()) {
return false;
@@ -400,8 +383,7 @@ bool QuicStreamSequencerBuffer::MarkConsumed(size_t bytes_used) {
RetireBlockIfEmpty(block_idx);
}
}
- total_bytes_prefetched_ =
- std::max(total_bytes_read_, total_bytes_prefetched_);
+
return true;
}
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 b0478c02b70..93b723f1781 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
@@ -137,16 +137,6 @@ class QUIC_EXPORT_PRIVATE QuicStreamSequencerBuffer {
// Does not consume data.
bool PeekRegion(QuicStreamOffset offset, iovec* iov) const;
- // DEPRECATED, use PeekRegion() instead.
- // Called to return the next region that has not been returned by this method
- // previously, except if Clear() has been called then prefetch offset is set
- // to BytesConsumed(), and if Readv() or MarkConsumed() reads further than
- // prefetch offset, then offset is set to beginning of not yet consumed area.
- // This method only returns reference of underlying data. The caller is
- // responsible for copying and consuming the data.
- // Returns true if the data is read, false otherwise.
- bool PrefetchNextRegion(iovec* iov);
-
// Called after GetReadableRegions() to free up |bytes_used| space if these
// bytes are processed.
// Pre-requisite: bytes_used <= available bytes to read.
@@ -243,10 +233,8 @@ class QUIC_EXPORT_PRIVATE QuicStreamSequencerBuffer {
// Currently received data.
QuicIntervalSet<QuicStreamOffset> bytes_received_;
-
- // Total number of bytes that have been prefetched.
- QuicStreamOffset total_bytes_prefetched_;
};
+
} // namespace quic
#endif // QUICHE_QUIC_CORE_QUIC_STREAM_SEQUENCER_BUFFER_H_
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 20dbe05f0ae..a7872dd2485 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
@@ -583,101 +583,6 @@ TEST_F(QuicStreamSequencerBufferTest, GetReadableRegionTillGap) {
IovecToStringPiece(iov));
}
-TEST_F(QuicStreamSequencerBufferTest, PrefetchEmptyBuffer) {
- iovec iov;
- EXPECT_FALSE(buffer_->PrefetchNextRegion(&iov));
-}
-
-TEST_F(QuicStreamSequencerBufferTest, PrefetchInitialBuffer) {
- std::string source(kBlockSizeBytes, 'a');
- buffer_->OnStreamData(0, source, &written_, &error_details_);
- iovec iov;
- EXPECT_TRUE(buffer_->PrefetchNextRegion(&iov));
- EXPECT_EQ(source, IovecToStringPiece(iov));
-}
-
-TEST_F(QuicStreamSequencerBufferTest, PrefetchBufferWithOffset) {
- std::string source(1024, 'a');
- buffer_->OnStreamData(0, source, &written_, &error_details_);
- iovec iov;
- EXPECT_TRUE(buffer_->PrefetchNextRegion(&iov));
- EXPECT_EQ(source, IovecToStringPiece(iov));
- // The second frame goes into the same block.
- std::string source2(800, 'a');
- buffer_->OnStreamData(1024, source2, &written_, &error_details_);
- EXPECT_TRUE(buffer_->PrefetchNextRegion(&iov));
- EXPECT_EQ(source2, IovecToStringPiece(iov));
-}
-
-TEST_F(QuicStreamSequencerBufferTest, PrefetchBufferWithMultipleBlocks) {
- const size_t data_size = 1024;
- std::string source(data_size, 'a');
- buffer_->OnStreamData(0, source, &written_, &error_details_);
- iovec iov;
- EXPECT_TRUE(buffer_->PrefetchNextRegion(&iov));
- EXPECT_EQ(source, IovecToStringPiece(iov));
- std::string source2(kBlockSizeBytes, 'b');
- buffer_->OnStreamData(data_size, source2, &written_, &error_details_);
- EXPECT_TRUE(buffer_->PrefetchNextRegion(&iov));
- EXPECT_EQ(std::string(kBlockSizeBytes - data_size, 'b'),
- IovecToStringPiece(iov));
- EXPECT_TRUE(buffer_->PrefetchNextRegion(&iov));
- EXPECT_EQ(std::string(data_size, 'b'), IovecToStringPiece(iov));
-}
-
-TEST_F(QuicStreamSequencerBufferTest, PrefetchBufferAfterBlockRetired) {
- std::string source(kBlockSizeBytes, 'a');
- buffer_->OnStreamData(0, source, &written_, &error_details_);
- iovec iov;
- EXPECT_TRUE(buffer_->PrefetchNextRegion(&iov));
- EXPECT_EQ(source, IovecToStringPiece(iov));
- // Read the whole block so it's retired.
- char dest[kBlockSizeBytes];
- helper_->Read(dest, kBlockSizeBytes);
-
- std::string source2(300, 'b');
- buffer_->OnStreamData(kBlockSizeBytes, source2, &written_, &error_details_);
-
- EXPECT_TRUE(buffer_->PrefetchNextRegion(&iov));
- EXPECT_EQ(source2, IovecToStringPiece(iov));
-}
-
-TEST_F(QuicStreamSequencerBufferTest, PrefetchContinously) {
- std::string source(kBlockSizeBytes, 'a');
- buffer_->OnStreamData(0, source, &written_, &error_details_);
- iovec iov;
- EXPECT_TRUE(buffer_->PrefetchNextRegion(&iov));
- EXPECT_EQ(source, IovecToStringPiece(iov));
- std::string source2(kBlockSizeBytes, 'b');
- buffer_->OnStreamData(kBlockSizeBytes, source2, &written_, &error_details_);
- EXPECT_TRUE(buffer_->PrefetchNextRegion(&iov));
- EXPECT_EQ(source2, IovecToStringPiece(iov));
-}
-
-TEST_F(QuicStreamSequencerBufferTest, ConsumeMoreThanPrefetch) {
- std::string source(100, 'a');
- buffer_->OnStreamData(0, source, &written_, &error_details_);
- char dest[30];
- helper_->Read(dest, 30);
- iovec iov;
- EXPECT_TRUE(buffer_->PrefetchNextRegion(&iov));
- EXPECT_EQ(std::string(70, 'a'), IovecToStringPiece(iov));
- std::string source2(100, 'b');
- buffer_->OnStreamData(100, source2, &written_, &error_details_);
- buffer_->MarkConsumed(100);
- EXPECT_TRUE(buffer_->PrefetchNextRegion(&iov));
- EXPECT_EQ(std::string(70, 'b'), IovecToStringPiece(iov));
-}
-
-TEST_F(QuicStreamSequencerBufferTest, PrefetchMoreThanBufferHas) {
- std::string source(100, 'a');
- buffer_->OnStreamData(0, source, &written_, &error_details_);
- iovec iov;
- EXPECT_TRUE(buffer_->PrefetchNextRegion(&iov));
- EXPECT_EQ(std::string(100, 'a'), IovecToStringPiece(iov));
- EXPECT_FALSE(buffer_->PrefetchNextRegion(&iov));
-}
-
TEST_F(QuicStreamSequencerBufferTest, PeekEmptyBuffer) {
iovec iov;
EXPECT_FALSE(buffer_->PeekRegion(0, &iov));
@@ -1179,29 +1084,6 @@ TEST_F(QuicStreamSequencerBufferRandomIOTest, RandomWriteAndConsumeInPlace) {
EXPECT_LE(bytes_to_buffer_, total_bytes_written_);
}
-// Regression test for https://crbug.com/969391.
-TEST_F(QuicStreamSequencerBufferTest, PrefetchAfterClear) {
- // Write a few bytes.
- const std::string kData("foo");
- EXPECT_EQ(QUIC_NO_ERROR, buffer_->OnStreamData(/* offset = */ 0, kData,
- &written_, &error_details_));
- EXPECT_EQ(kData.size(), written_);
-
- // Prefetch all buffered data.
- iovec iov;
- EXPECT_TRUE(buffer_->PrefetchNextRegion(&iov));
- EXPECT_EQ(kData, IovecToStringPiece(iov));
-
- // No more data to prefetch.
- EXPECT_FALSE(buffer_->PrefetchNextRegion(&iov));
-
- // Clear all buffered data.
- buffer_->Clear();
-
- // Still no data to prefetch.
- EXPECT_FALSE(buffer_->PrefetchNextRegion(&iov));
-}
-
} // anonymous namespace
} // namespace test
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 60525f8484b..b57fa6e32c7 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
@@ -758,6 +758,17 @@ TEST_F(QuicStreamSequencerTest, StopReadingWithLevelTriggered) {
OnFinFrame(6u, "ghi");
}
+// Regression test for https://crbug.com/992486.
+TEST_F(QuicStreamSequencerTest, CorruptFinFrames) {
+ SetQuicReloadableFlag(quic_no_stream_data_after_reset, true);
+ EXPECT_CALL(stream_, OnDataAvailable()).Times(1);
+ EXPECT_CALL(stream_, Reset(QUIC_MULTIPLE_TERMINATION_OFFSETS));
+
+ OnFinFrame(0u, "");
+ OnFinFrame(0u, "a");
+ EXPECT_FALSE(sequencer_->HasBytesToRead());
+}
+
} // namespace
} // namespace test
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_stream_test.cc
index ee9676f03b7..d371866e944 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
@@ -143,9 +143,9 @@ class QuicStreamTestBase : public QuicTestWithParam<ParsedQuicVersion> {
uint32_t initial_flow_control_window_bytes_;
QuicTime::Delta zero_;
ParsedQuicVersionVector supported_versions_;
- const QuicStreamId kTestStreamId =
- QuicUtils::GetHeadersStreamId(GetParam().transport_version) +
- QuicUtils::StreamIdDelta(GetParam().transport_version);
+ QuicStreamId kTestStreamId =
+ GetNthClientInitiatedBidirectionalStreamId(GetParam().transport_version,
+ 1);
};
// Non parameterized QuicStreamTest used for tests that do not
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 cb29a40fbfe..f4a4f893ae7 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
@@ -206,17 +206,20 @@ void QuicTimeWaitListManager::SendVersionNegotiationPacket(
QuicConnectionId server_connection_id,
QuicConnectionId client_connection_id,
bool ietf_quic,
+ bool use_length_prefix,
const ParsedQuicVersionVector& supported_versions,
const QuicSocketAddress& self_address,
const QuicSocketAddress& peer_address,
std::unique_ptr<QuicPerPacketContext> packet_context) {
std::unique_ptr<QuicEncryptedPacket> version_packet =
- QuicFramer::BuildVersionNegotiationPacket(server_connection_id,
- client_connection_id, ietf_quic,
- supported_versions);
- QUIC_DVLOG(2) << "Dispatcher sending version negotiation packet: {"
+ QuicFramer::BuildVersionNegotiationPacket(
+ server_connection_id, client_connection_id, ietf_quic,
+ use_length_prefix, supported_versions);
+ QUIC_DVLOG(2) << "Dispatcher sending version negotiation packet {"
<< ParsedQuicVersionVectorToString(supported_versions) << "}, "
- << (ietf_quic ? "" : "!") << "ietf_quic:" << std::endl
+ << (ietf_quic ? "" : "!") << "ietf_quic, "
+ << (use_length_prefix ? "" : "!")
+ << "use_length_prefix:" << std::endl
<< QuicTextUtils::HexDump(QuicStringPiece(
version_packet->data(), version_packet->length()));
SendOrQueuePacket(QuicMakeUnique<QueuedPacket>(self_address, peer_address,
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 c53632c8e35..9a807c0b6ae 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
@@ -125,6 +125,7 @@ class QuicTimeWaitListManager : public QuicBlockedWriterInterface {
QuicConnectionId server_connection_id,
QuicConnectionId client_connection_id,
bool ietf_quic,
+ bool use_length_prefix,
const ParsedQuicVersionVector& supported_versions,
const QuicSocketAddress& self_address,
const QuicSocketAddress& peer_address,
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 0d9e32ac62c..4caae880736 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
@@ -251,50 +251,67 @@ TEST_F(QuicTimeWaitListManagerTest, CheckStatelessConnectionIdInTimeWait) {
TEST_F(QuicTimeWaitListManagerTest, SendVersionNegotiationPacket) {
std::unique_ptr<QuicEncryptedPacket> packet(
- QuicFramer::BuildVersionNegotiationPacket(connection_id_,
- EmptyQuicConnectionId(), false,
- AllSupportedVersions()));
+ QuicFramer::BuildVersionNegotiationPacket(
+ connection_id_, EmptyQuicConnectionId(), /*ietf_quic=*/false,
+ /*use_length_prefix=*/false, AllSupportedVersions()));
EXPECT_CALL(writer_, WritePacket(_, packet->length(), self_address_.host(),
peer_address_, _))
.WillOnce(Return(WriteResult(WRITE_STATUS_OK, 1)));
time_wait_list_manager_.SendVersionNegotiationPacket(
- connection_id_, EmptyQuicConnectionId(), false, AllSupportedVersions(),
- self_address_, peer_address_, QuicMakeUnique<QuicPerPacketContext>());
+ connection_id_, EmptyQuicConnectionId(), /*ietf_quic=*/false,
+ /*use_length_prefix=*/false, AllSupportedVersions(), self_address_,
+ peer_address_, QuicMakeUnique<QuicPerPacketContext>());
+ EXPECT_EQ(0u, time_wait_list_manager_.num_connections());
+}
+
+TEST_F(QuicTimeWaitListManagerTest,
+ SendIetfVersionNegotiationPacketWithoutLengthPrefix) {
+ std::unique_ptr<QuicEncryptedPacket> packet(
+ QuicFramer::BuildVersionNegotiationPacket(
+ connection_id_, EmptyQuicConnectionId(), /*ietf_quic=*/true,
+ /*use_length_prefix=*/false, AllSupportedVersions()));
+ EXPECT_CALL(writer_, WritePacket(_, packet->length(), self_address_.host(),
+ peer_address_, _))
+ .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 1)));
+
+ time_wait_list_manager_.SendVersionNegotiationPacket(
+ connection_id_, EmptyQuicConnectionId(), /*ietf_quic=*/true,
+ /*use_length_prefix=*/false, AllSupportedVersions(), self_address_,
+ peer_address_, QuicMakeUnique<QuicPerPacketContext>());
EXPECT_EQ(0u, time_wait_list_manager_.num_connections());
}
TEST_F(QuicTimeWaitListManagerTest, SendIetfVersionNegotiationPacket) {
std::unique_ptr<QuicEncryptedPacket> packet(
- QuicFramer::BuildVersionNegotiationPacket(connection_id_,
- EmptyQuicConnectionId(), true,
- AllSupportedVersions()));
+ QuicFramer::BuildVersionNegotiationPacket(
+ connection_id_, EmptyQuicConnectionId(), /*ietf_quic=*/true,
+ /*use_length_prefix=*/true, AllSupportedVersions()));
EXPECT_CALL(writer_, WritePacket(_, packet->length(), self_address_.host(),
peer_address_, _))
.WillOnce(Return(WriteResult(WRITE_STATUS_OK, 1)));
time_wait_list_manager_.SendVersionNegotiationPacket(
- connection_id_, EmptyQuicConnectionId(), true, AllSupportedVersions(),
- self_address_, peer_address_, QuicMakeUnique<QuicPerPacketContext>());
+ connection_id_, EmptyQuicConnectionId(), /*ietf_quic=*/true,
+ /*use_length_prefix=*/true, AllSupportedVersions(), self_address_,
+ peer_address_, QuicMakeUnique<QuicPerPacketContext>());
EXPECT_EQ(0u, time_wait_list_manager_.num_connections());
}
TEST_F(QuicTimeWaitListManagerTest,
SendIetfVersionNegotiationPacketWithClientConnectionId) {
- // Client connection IDs cannot be used unless this flag is true.
- SetQuicRestartFlag(quic_do_not_override_connection_id, true);
-
std::unique_ptr<QuicEncryptedPacket> packet(
- QuicFramer::BuildVersionNegotiationPacket(connection_id_,
- TestConnectionId(0x33), true,
- AllSupportedVersions()));
+ QuicFramer::BuildVersionNegotiationPacket(
+ connection_id_, TestConnectionId(0x33), /*ietf_quic=*/true,
+ /*use_length_prefix=*/true, AllSupportedVersions()));
EXPECT_CALL(writer_, WritePacket(_, packet->length(), self_address_.host(),
peer_address_, _))
.WillOnce(Return(WriteResult(WRITE_STATUS_OK, 1)));
time_wait_list_manager_.SendVersionNegotiationPacket(
- connection_id_, TestConnectionId(0x33), true, AllSupportedVersions(),
- self_address_, peer_address_, QuicMakeUnique<QuicPerPacketContext>());
+ connection_id_, TestConnectionId(0x33), /*ietf_quic=*/true,
+ /*use_length_prefix=*/true, AllSupportedVersions(), self_address_,
+ peer_address_, QuicMakeUnique<QuicPerPacketContext>());
EXPECT_EQ(0u, time_wait_list_manager_.num_connections());
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_types.cc b/chromium/net/third_party/quiche/src/quic/core/quic_types.cc
index 102b60ecf63..46f809de3b4 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_types.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_types.cc
@@ -4,6 +4,10 @@
#include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include <cstdint>
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h"
+
namespace quic {
QuicConsumedData::QuicConsumedData(size_t bytes_consumed, bool fin_consumed)
@@ -75,52 +79,396 @@ std::ostream& operator<<(std::ostream& os, const WriteResult& s) {
MessageResult::MessageResult(MessageStatus status, QuicMessageId message_id)
: status(status), message_id(message_id) {}
-std::ostream& operator<<(std::ostream& os,
- const QuicIetfTransportErrorCodes& c) {
+#define RETURN_STRING_LITERAL(x) \
+ case x: \
+ return #x;
+
+std::string QuicIetfTransportErrorCodeString(QuicIetfTransportErrorCodes c) {
if (static_cast<uint16_t>(c) >= 0xff00u) {
- os << "Private value: " << c;
- return os;
+ return QuicStrCat("Private value: ", static_cast<uint16_t>(c));
}
switch (c) {
- case NO_IETF_QUIC_ERROR:
- os << "NO_IETF_QUIC_ERROR";
- break;
- case INTERNAL_ERROR:
- os << "INTERNAL_ERROR";
- break;
- case SERVER_BUSY_ERROR:
- os << "SERVER_BUSY_ERROR";
- break;
- case FLOW_CONTROL_ERROR:
- os << "FLOW_CONTROL_ERROR";
- break;
- case STREAM_LIMIT_ERROR:
- os << "STREAM_LIMIT_ERROR";
- break;
- case STREAM_STATE_ERROR:
- os << "STREAM_STATE_ERROR";
- break;
- case FINAL_SIZE_ERROR:
- os << "FINAL_SIZE_ERROR";
- break;
- case FRAME_ENCODING_ERROR:
- os << "FRAME_ENCODING_ERROR";
- break;
- case TRANSPORT_PARAMETER_ERROR:
- os << "TRANSPORT_PARAMETER_ERROR";
- break;
- case VERSION_NEGOTIATION_ERROR:
- os << "VERSION_NEGOTIATION_ERROR";
- break;
- case PROTOCOL_VIOLATION:
- os << "PROTOCOL_VIOLATION";
- break;
- case INVALID_MIGRATION:
- os << "INVALID_MIGRATION";
+ RETURN_STRING_LITERAL(NO_IETF_QUIC_ERROR);
+ RETURN_STRING_LITERAL(INTERNAL_ERROR);
+ RETURN_STRING_LITERAL(SERVER_BUSY_ERROR);
+ RETURN_STRING_LITERAL(FLOW_CONTROL_ERROR);
+ RETURN_STRING_LITERAL(STREAM_LIMIT_ERROR);
+ RETURN_STRING_LITERAL(STREAM_STATE_ERROR);
+ RETURN_STRING_LITERAL(FINAL_SIZE_ERROR);
+ RETURN_STRING_LITERAL(FRAME_ENCODING_ERROR);
+ RETURN_STRING_LITERAL(TRANSPORT_PARAMETER_ERROR);
+ RETURN_STRING_LITERAL(VERSION_NEGOTIATION_ERROR);
+ RETURN_STRING_LITERAL(PROTOCOL_VIOLATION);
+ RETURN_STRING_LITERAL(INVALID_MIGRATION);
+ default:
+ return QuicStrCat("Unknown Transport Error Code Value: ",
+ static_cast<uint16_t>(c));
+ }
+}
+
+std::ostream& operator<<(std::ostream& os,
+ const QuicIetfTransportErrorCodes& c) {
+ os << QuicIetfTransportErrorCodeString(c);
+ return os;
+}
+
+QuicErrorCodeToIetfMapping QuicErrorCodeToTransportErrorCode(
+ QuicErrorCode error) {
+ switch (error) {
+ // TODO(fkastenholz): Currently, all QuicError codes will map
+ // to application error codes and the original Google QUIC error
+ // code. This will change over time as we go through all calls to
+ // CloseConnection() and see whether the call is a Transport or an
+ // Application close and what the translated code should be.
+ case QUIC_NO_ERROR:
+ return {true, {static_cast<uint64_t>(QUIC_NO_ERROR)}};
+ case QUIC_INTERNAL_ERROR:
+ return {true, {static_cast<uint64_t>(QUIC_INTERNAL_ERROR)}};
+ case QUIC_STREAM_DATA_AFTER_TERMINATION:
+ return {true,
+ {static_cast<uint64_t>(QUIC_STREAM_DATA_AFTER_TERMINATION)}};
+ case QUIC_INVALID_PACKET_HEADER:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_PACKET_HEADER)}};
+ case QUIC_INVALID_FRAME_DATA:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_FRAME_DATA)}};
+ case QUIC_MISSING_PAYLOAD:
+ return {true, {static_cast<uint64_t>(QUIC_MISSING_PAYLOAD)}};
+ case QUIC_INVALID_FEC_DATA:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_FEC_DATA)}};
+ case QUIC_INVALID_STREAM_DATA:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_STREAM_DATA)}};
+ case QUIC_OVERLAPPING_STREAM_DATA:
+ return {true, {static_cast<uint64_t>(QUIC_OVERLAPPING_STREAM_DATA)}};
+ case QUIC_UNENCRYPTED_STREAM_DATA:
+ return {true, {static_cast<uint64_t>(QUIC_UNENCRYPTED_STREAM_DATA)}};
+ case QUIC_ATTEMPT_TO_SEND_UNENCRYPTED_STREAM_DATA:
+ return {true,
+ {static_cast<uint64_t>(
+ QUIC_ATTEMPT_TO_SEND_UNENCRYPTED_STREAM_DATA)}};
+ case QUIC_MAYBE_CORRUPTED_MEMORY:
+ return {true, {static_cast<uint64_t>(QUIC_MAYBE_CORRUPTED_MEMORY)}};
+ case QUIC_UNENCRYPTED_FEC_DATA:
+ return {true, {static_cast<uint64_t>(QUIC_UNENCRYPTED_FEC_DATA)}};
+ case QUIC_INVALID_RST_STREAM_DATA:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_RST_STREAM_DATA)}};
+ case QUIC_INVALID_CONNECTION_CLOSE_DATA:
+ return {true,
+ {static_cast<uint64_t>(QUIC_INVALID_CONNECTION_CLOSE_DATA)}};
+ case QUIC_INVALID_GOAWAY_DATA:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_GOAWAY_DATA)}};
+ case QUIC_INVALID_WINDOW_UPDATE_DATA:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_WINDOW_UPDATE_DATA)}};
+ case QUIC_INVALID_BLOCKED_DATA:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_BLOCKED_DATA)}};
+ case QUIC_INVALID_STOP_WAITING_DATA:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_STOP_WAITING_DATA)}};
+ case QUIC_INVALID_PATH_CLOSE_DATA:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_PATH_CLOSE_DATA)}};
+ case QUIC_INVALID_ACK_DATA:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_ACK_DATA)}};
+ case QUIC_INVALID_MESSAGE_DATA:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_MESSAGE_DATA)}};
+ case QUIC_INVALID_VERSION_NEGOTIATION_PACKET:
+ return {true,
+ {static_cast<uint64_t>(QUIC_INVALID_VERSION_NEGOTIATION_PACKET)}};
+ case QUIC_INVALID_PUBLIC_RST_PACKET:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_PUBLIC_RST_PACKET)}};
+ case QUIC_DECRYPTION_FAILURE:
+ return {true, {static_cast<uint64_t>(QUIC_DECRYPTION_FAILURE)}};
+ case QUIC_ENCRYPTION_FAILURE:
+ return {true, {static_cast<uint64_t>(QUIC_ENCRYPTION_FAILURE)}};
+ case QUIC_PACKET_TOO_LARGE:
+ return {true, {static_cast<uint64_t>(QUIC_PACKET_TOO_LARGE)}};
+ case QUIC_PEER_GOING_AWAY:
+ return {true, {static_cast<uint64_t>(QUIC_PEER_GOING_AWAY)}};
+ case QUIC_INVALID_STREAM_ID:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_STREAM_ID)}};
+ case QUIC_INVALID_PRIORITY:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_PRIORITY)}};
+ case QUIC_TOO_MANY_OPEN_STREAMS:
+ return {true, {static_cast<uint64_t>(QUIC_TOO_MANY_OPEN_STREAMS)}};
+ case QUIC_TOO_MANY_AVAILABLE_STREAMS:
+ return {true, {static_cast<uint64_t>(QUIC_TOO_MANY_AVAILABLE_STREAMS)}};
+ case QUIC_PUBLIC_RESET:
+ return {true, {static_cast<uint64_t>(QUIC_PUBLIC_RESET)}};
+ case QUIC_INVALID_VERSION:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_VERSION)}};
+ case QUIC_INVALID_HEADER_ID:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_HEADER_ID)}};
+ case QUIC_INVALID_NEGOTIATED_VALUE:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_NEGOTIATED_VALUE)}};
+ case QUIC_DECOMPRESSION_FAILURE:
+ return {true, {static_cast<uint64_t>(QUIC_DECOMPRESSION_FAILURE)}};
+ case QUIC_NETWORK_IDLE_TIMEOUT:
+ return {true, {static_cast<uint64_t>(QUIC_NETWORK_IDLE_TIMEOUT)}};
+ case QUIC_HANDSHAKE_TIMEOUT:
+ return {true, {static_cast<uint64_t>(QUIC_HANDSHAKE_TIMEOUT)}};
+ case QUIC_ERROR_MIGRATING_ADDRESS:
+ return {true, {static_cast<uint64_t>(QUIC_ERROR_MIGRATING_ADDRESS)}};
+ case QUIC_ERROR_MIGRATING_PORT:
+ return {true, {static_cast<uint64_t>(QUIC_ERROR_MIGRATING_PORT)}};
+ case QUIC_PACKET_WRITE_ERROR:
+ return {true, {static_cast<uint64_t>(QUIC_PACKET_WRITE_ERROR)}};
+ case QUIC_PACKET_READ_ERROR:
+ return {true, {static_cast<uint64_t>(QUIC_PACKET_READ_ERROR)}};
+ case QUIC_EMPTY_STREAM_FRAME_NO_FIN:
+ return {true, {static_cast<uint64_t>(QUIC_EMPTY_STREAM_FRAME_NO_FIN)}};
+ case QUIC_INVALID_HEADERS_STREAM_DATA:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_HEADERS_STREAM_DATA)}};
+ case QUIC_HEADERS_STREAM_DATA_DECOMPRESS_FAILURE:
+ return {
+ true,
+ {static_cast<uint64_t>(QUIC_HEADERS_STREAM_DATA_DECOMPRESS_FAILURE)}};
+ case QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA:
+ return {
+ true,
+ {static_cast<uint64_t>(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA)}};
+ case QUIC_FLOW_CONTROL_SENT_TOO_MUCH_DATA:
+ return {true,
+ {static_cast<uint64_t>(QUIC_FLOW_CONTROL_SENT_TOO_MUCH_DATA)}};
+ case QUIC_FLOW_CONTROL_INVALID_WINDOW:
+ return {true, {static_cast<uint64_t>(QUIC_FLOW_CONTROL_INVALID_WINDOW)}};
+ case QUIC_CONNECTION_IP_POOLED:
+ return {true, {static_cast<uint64_t>(QUIC_CONNECTION_IP_POOLED)}};
+ case QUIC_TOO_MANY_OUTSTANDING_SENT_PACKETS:
+ return {true,
+ {static_cast<uint64_t>(QUIC_TOO_MANY_OUTSTANDING_SENT_PACKETS)}};
+ case QUIC_TOO_MANY_OUTSTANDING_RECEIVED_PACKETS:
+ return {
+ true,
+ {static_cast<uint64_t>(QUIC_TOO_MANY_OUTSTANDING_RECEIVED_PACKETS)}};
+ case QUIC_CONNECTION_CANCELLED:
+ return {true, {static_cast<uint64_t>(QUIC_CONNECTION_CANCELLED)}};
+ case QUIC_BAD_PACKET_LOSS_RATE:
+ return {true, {static_cast<uint64_t>(QUIC_BAD_PACKET_LOSS_RATE)}};
+ case QUIC_PUBLIC_RESETS_POST_HANDSHAKE:
+ return {true, {static_cast<uint64_t>(QUIC_PUBLIC_RESETS_POST_HANDSHAKE)}};
+ case QUIC_FAILED_TO_SERIALIZE_PACKET:
+ return {true, {static_cast<uint64_t>(QUIC_FAILED_TO_SERIALIZE_PACKET)}};
+ case QUIC_TOO_MANY_RTOS:
+ return {true, {static_cast<uint64_t>(QUIC_TOO_MANY_RTOS)}};
+ case QUIC_HANDSHAKE_FAILED:
+ return {true, {static_cast<uint64_t>(QUIC_HANDSHAKE_FAILED)}};
+ case QUIC_CRYPTO_TAGS_OUT_OF_ORDER:
+ return {true, {static_cast<uint64_t>(QUIC_CRYPTO_TAGS_OUT_OF_ORDER)}};
+ case QUIC_CRYPTO_TOO_MANY_ENTRIES:
+ return {true, {static_cast<uint64_t>(QUIC_CRYPTO_TOO_MANY_ENTRIES)}};
+ case QUIC_CRYPTO_INVALID_VALUE_LENGTH:
+ return {true, {static_cast<uint64_t>(QUIC_CRYPTO_INVALID_VALUE_LENGTH)}};
+ case QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE:
+ return {true,
+ {static_cast<uint64_t>(
+ QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE)}};
+ case QUIC_INVALID_CRYPTO_MESSAGE_TYPE:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_CRYPTO_MESSAGE_TYPE)}};
+ case QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER:
+ return {true,
+ {static_cast<uint64_t>(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER)}};
+ case QUIC_INVALID_CHANNEL_ID_SIGNATURE:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_CHANNEL_ID_SIGNATURE)}};
+ case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND:
+ return {true,
+ {static_cast<uint64_t>(QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND)}};
+ case QUIC_CRYPTO_MESSAGE_PARAMETER_NO_OVERLAP:
+ return {
+ true,
+ {static_cast<uint64_t>(QUIC_CRYPTO_MESSAGE_PARAMETER_NO_OVERLAP)}};
+ case QUIC_CRYPTO_MESSAGE_INDEX_NOT_FOUND:
+ return {true,
+ {static_cast<uint64_t>(QUIC_CRYPTO_MESSAGE_INDEX_NOT_FOUND)}};
+ case QUIC_UNSUPPORTED_PROOF_DEMAND:
+ return {true, {static_cast<uint64_t>(QUIC_UNSUPPORTED_PROOF_DEMAND)}};
+ case QUIC_CRYPTO_INTERNAL_ERROR:
+ return {true, {static_cast<uint64_t>(QUIC_CRYPTO_INTERNAL_ERROR)}};
+ case QUIC_CRYPTO_VERSION_NOT_SUPPORTED:
+ return {true, {static_cast<uint64_t>(QUIC_CRYPTO_VERSION_NOT_SUPPORTED)}};
+ case QUIC_CRYPTO_NO_SUPPORT:
+ return {true, {static_cast<uint64_t>(QUIC_CRYPTO_NO_SUPPORT)}};
+ case QUIC_CRYPTO_TOO_MANY_REJECTS:
+ return {true, {static_cast<uint64_t>(QUIC_CRYPTO_TOO_MANY_REJECTS)}};
+ case QUIC_PROOF_INVALID:
+ return {true, {static_cast<uint64_t>(QUIC_PROOF_INVALID)}};
+ case QUIC_CRYPTO_DUPLICATE_TAG:
+ return {true, {static_cast<uint64_t>(QUIC_CRYPTO_DUPLICATE_TAG)}};
+ case QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT:
+ return {true,
+ {static_cast<uint64_t>(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT)}};
+ case QUIC_CRYPTO_SERVER_CONFIG_EXPIRED:
+ return {true, {static_cast<uint64_t>(QUIC_CRYPTO_SERVER_CONFIG_EXPIRED)}};
+ case QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED:
+ return {true,
+ {static_cast<uint64_t>(QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED)}};
+ case QUIC_CRYPTO_MESSAGE_WHILE_VALIDATING_CLIENT_HELLO:
+ return {true,
+ {static_cast<uint64_t>(
+ QUIC_CRYPTO_MESSAGE_WHILE_VALIDATING_CLIENT_HELLO)}};
+ case QUIC_CRYPTO_UPDATE_BEFORE_HANDSHAKE_COMPLETE:
+ return {true,
+ {static_cast<uint64_t>(
+ QUIC_CRYPTO_UPDATE_BEFORE_HANDSHAKE_COMPLETE)}};
+ case QUIC_CRYPTO_CHLO_TOO_LARGE:
+ return {true, {static_cast<uint64_t>(QUIC_CRYPTO_CHLO_TOO_LARGE)}};
+ case QUIC_VERSION_NEGOTIATION_MISMATCH:
+ return {true, {static_cast<uint64_t>(QUIC_VERSION_NEGOTIATION_MISMATCH)}};
+ case QUIC_BAD_MULTIPATH_FLAG:
+ return {true, {static_cast<uint64_t>(QUIC_BAD_MULTIPATH_FLAG)}};
+ case QUIC_MULTIPATH_PATH_DOES_NOT_EXIST:
+ return {true,
+ {static_cast<uint64_t>(QUIC_MULTIPATH_PATH_DOES_NOT_EXIST)}};
+ case QUIC_MULTIPATH_PATH_NOT_ACTIVE:
+ return {true, {static_cast<uint64_t>(QUIC_MULTIPATH_PATH_NOT_ACTIVE)}};
+ case QUIC_IP_ADDRESS_CHANGED:
+ return {true, {static_cast<uint64_t>(QUIC_IP_ADDRESS_CHANGED)}};
+ case QUIC_CONNECTION_MIGRATION_NO_MIGRATABLE_STREAMS:
+ return {true,
+ {static_cast<uint64_t>(
+ QUIC_CONNECTION_MIGRATION_NO_MIGRATABLE_STREAMS)}};
+ case QUIC_CONNECTION_MIGRATION_TOO_MANY_CHANGES:
+ return {
+ true,
+ {static_cast<uint64_t>(QUIC_CONNECTION_MIGRATION_TOO_MANY_CHANGES)}};
+ case QUIC_CONNECTION_MIGRATION_NO_NEW_NETWORK:
+ return {
+ true,
+ {static_cast<uint64_t>(QUIC_CONNECTION_MIGRATION_NO_NEW_NETWORK)}};
+ case QUIC_CONNECTION_MIGRATION_NON_MIGRATABLE_STREAM:
+ return {true,
+ {static_cast<uint64_t>(
+ QUIC_CONNECTION_MIGRATION_NON_MIGRATABLE_STREAM)}};
+ case QUIC_CONNECTION_MIGRATION_DISABLED_BY_CONFIG:
+ return {true,
+ {static_cast<uint64_t>(
+ QUIC_CONNECTION_MIGRATION_DISABLED_BY_CONFIG)}};
+ case QUIC_CONNECTION_MIGRATION_INTERNAL_ERROR:
+ return {
+ true,
+ {static_cast<uint64_t>(QUIC_CONNECTION_MIGRATION_INTERNAL_ERROR)}};
+ case QUIC_CONNECTION_MIGRATION_HANDSHAKE_UNCONFIRMED:
+ return {true,
+ {static_cast<uint64_t>(
+ QUIC_CONNECTION_MIGRATION_HANDSHAKE_UNCONFIRMED)}};
+ case QUIC_TOO_MANY_STREAM_DATA_INTERVALS:
+ return {true,
+ {static_cast<uint64_t>(QUIC_TOO_MANY_STREAM_DATA_INTERVALS)}};
+ case QUIC_STREAM_SEQUENCER_INVALID_STATE:
+ return {true,
+ {static_cast<uint64_t>(QUIC_STREAM_SEQUENCER_INVALID_STATE)}};
+ case QUIC_TOO_MANY_SESSIONS_ON_SERVER:
+ return {true, {static_cast<uint64_t>(QUIC_TOO_MANY_SESSIONS_ON_SERVER)}};
+ case QUIC_STREAM_LENGTH_OVERFLOW:
+ return {true, {static_cast<uint64_t>(QUIC_STREAM_LENGTH_OVERFLOW)}};
+ case QUIC_INVALID_MAX_DATA_FRAME_DATA:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_MAX_DATA_FRAME_DATA)}};
+ case QUIC_INVALID_MAX_STREAM_DATA_FRAME_DATA:
+ return {true,
+ {static_cast<uint64_t>(QUIC_INVALID_MAX_STREAM_DATA_FRAME_DATA)}};
+ case QUIC_MAX_STREAMS_DATA:
+ return {true, {static_cast<uint64_t>(QUIC_MAX_STREAMS_DATA)}};
+ case QUIC_STREAMS_BLOCKED_DATA:
+ return {true, {static_cast<uint64_t>(QUIC_STREAMS_BLOCKED_DATA)}};
+ case QUIC_INVALID_STREAM_BLOCKED_DATA:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_STREAM_BLOCKED_DATA)}};
+ case QUIC_INVALID_NEW_CONNECTION_ID_DATA:
+ return {true,
+ {static_cast<uint64_t>(QUIC_INVALID_NEW_CONNECTION_ID_DATA)}};
+ case QUIC_INVALID_STOP_SENDING_FRAME_DATA:
+ return {true,
+ {static_cast<uint64_t>(QUIC_INVALID_STOP_SENDING_FRAME_DATA)}};
+ case QUIC_INVALID_PATH_CHALLENGE_DATA:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_PATH_CHALLENGE_DATA)}};
+ case QUIC_INVALID_PATH_RESPONSE_DATA:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_PATH_RESPONSE_DATA)}};
+ case IETF_QUIC_PROTOCOL_VIOLATION:
+ return {true, {static_cast<uint64_t>(IETF_QUIC_PROTOCOL_VIOLATION)}};
+ case QUIC_INVALID_NEW_TOKEN:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_NEW_TOKEN)}};
+ case QUIC_DATA_RECEIVED_ON_WRITE_UNIDIRECTIONAL_STREAM:
+ return {true,
+ {static_cast<uint64_t>(
+ QUIC_DATA_RECEIVED_ON_WRITE_UNIDIRECTIONAL_STREAM)}};
+ case QUIC_TRY_TO_WRITE_DATA_ON_READ_UNIDIRECTIONAL_STREAM:
+ return {true,
+ {static_cast<uint64_t>(
+ QUIC_TRY_TO_WRITE_DATA_ON_READ_UNIDIRECTIONAL_STREAM)}};
+ case QUIC_INVALID_RETIRE_CONNECTION_ID_DATA:
+ return {true,
+ {static_cast<uint64_t>(QUIC_INVALID_RETIRE_CONNECTION_ID_DATA)}};
+ case QUIC_STREAMS_BLOCKED_ERROR:
+ return {true, {static_cast<uint64_t>(QUIC_STREAMS_BLOCKED_ERROR)}};
+ case QUIC_MAX_STREAMS_ERROR:
+ return {true, {static_cast<uint64_t>(QUIC_MAX_STREAMS_ERROR)}};
+ case QUIC_HTTP_DECODER_ERROR:
+ return {true, {static_cast<uint64_t>(QUIC_HTTP_DECODER_ERROR)}};
+ case QUIC_STALE_CONNECTION_CANCELLED:
+ return {true, {static_cast<uint64_t>(QUIC_STALE_CONNECTION_CANCELLED)}};
+ case QUIC_IETF_GQUIC_ERROR_MISSING:
+ return {true, {static_cast<uint64_t>(QUIC_IETF_GQUIC_ERROR_MISSING)}};
+ case QUIC_WINDOW_UPDATE_RECEIVED_ON_READ_UNIDIRECTIONAL_STREAM:
+ return {true,
+ {static_cast<uint64_t>(
+ QUIC_WINDOW_UPDATE_RECEIVED_ON_READ_UNIDIRECTIONAL_STREAM)}};
+ case QUIC_TOO_MANY_BUFFERED_CONTROL_FRAMES:
+ return {true,
+ {static_cast<uint64_t>(QUIC_TOO_MANY_BUFFERED_CONTROL_FRAMES)}};
+ case QUIC_LAST_ERROR:
+ return {false, {static_cast<uint64_t>(QUIC_LAST_ERROR)}};
+ }
+ // If it's an unknown code, indicate it's an application error code.
+ return {false, {NO_IETF_QUIC_ERROR}};
+}
+
+std::string QuicIetfFrameTypeString(QuicIetfFrameType t) {
+ if (IS_IETF_STREAM_FRAME(t)) {
+ return "IETF_STREAM";
+ }
+
+ switch (t) {
+ RETURN_STRING_LITERAL(IETF_PADDING);
+ RETURN_STRING_LITERAL(IETF_PING);
+ RETURN_STRING_LITERAL(IETF_ACK);
+ RETURN_STRING_LITERAL(IETF_ACK_ECN);
+ RETURN_STRING_LITERAL(IETF_RST_STREAM);
+ RETURN_STRING_LITERAL(IETF_STOP_SENDING);
+ RETURN_STRING_LITERAL(IETF_CRYPTO);
+ RETURN_STRING_LITERAL(IETF_NEW_TOKEN);
+ RETURN_STRING_LITERAL(IETF_MAX_DATA);
+ RETURN_STRING_LITERAL(IETF_MAX_STREAM_DATA);
+ RETURN_STRING_LITERAL(IETF_MAX_STREAMS_BIDIRECTIONAL);
+ RETURN_STRING_LITERAL(IETF_MAX_STREAMS_UNIDIRECTIONAL);
+ RETURN_STRING_LITERAL(IETF_BLOCKED);
+ RETURN_STRING_LITERAL(IETF_STREAM_BLOCKED);
+ RETURN_STRING_LITERAL(IETF_STREAMS_BLOCKED_BIDIRECTIONAL);
+ RETURN_STRING_LITERAL(IETF_STREAMS_BLOCKED_UNIDIRECTIONAL);
+ RETURN_STRING_LITERAL(IETF_NEW_CONNECTION_ID);
+ RETURN_STRING_LITERAL(IETF_RETIRE_CONNECTION_ID);
+ RETURN_STRING_LITERAL(IETF_PATH_CHALLENGE);
+ RETURN_STRING_LITERAL(IETF_PATH_RESPONSE);
+ RETURN_STRING_LITERAL(IETF_CONNECTION_CLOSE);
+ RETURN_STRING_LITERAL(IETF_APPLICATION_CLOSE);
+ RETURN_STRING_LITERAL(IETF_EXTENSION_MESSAGE_NO_LENGTH);
+ RETURN_STRING_LITERAL(IETF_EXTENSION_MESSAGE);
+ default:
+ return QuicStrCat("Private value (", t, ")");
+ }
+}
+std::ostream& operator<<(std::ostream& os, const QuicIetfFrameType& c) {
+ os << QuicIetfFrameTypeString(c);
+ return os;
+}
+
+std::string QuicConnectionCloseTypeString(QuicConnectionCloseType type) {
+ switch (type) {
+ RETURN_STRING_LITERAL(GOOGLE_QUIC_CONNECTION_CLOSE);
+ RETURN_STRING_LITERAL(IETF_QUIC_TRANSPORT_CONNECTION_CLOSE);
+ RETURN_STRING_LITERAL(IETF_QUIC_APPLICATION_CONNECTION_CLOSE);
+ default:
+ return QuicStrCat("Unknown: ", static_cast<int>(type));
break;
- // No default -- compiler will catch any adds/changes then.
}
+}
+std::ostream& operator<<(std::ostream& os, const QuicConnectionCloseType type) {
+ os << QuicConnectionCloseTypeString(type);
return os;
}
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 c3f70e739d4..2d893927120 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
@@ -267,6 +267,10 @@ enum QuicIetfFrameType : uint8_t {
IETF_EXTENSION_MESSAGE_NO_LENGTH = 0x20,
IETF_EXTENSION_MESSAGE = 0x21,
};
+QUIC_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
+ const QuicIetfFrameType& c);
+QUIC_EXPORT_PRIVATE std::string QuicIetfFrameTypeString(QuicIetfFrameType t);
+
// Masks for the bits that indicate the frame is a Stream frame vs the
// bits used as flags.
#define IETF_STREAM_FRAME_TYPE_MASK 0xfffffffffffffff8
@@ -298,7 +302,7 @@ const QuicVariableLengthIntegerLength kQuicDefaultLongHeaderLengthLength =
enum QuicPacketNumberLength : uint8_t {
PACKET_1BYTE_PACKET_NUMBER = 1,
PACKET_2BYTE_PACKET_NUMBER = 2,
- PACKET_3BYTE_PACKET_NUMBER = 3, // Used in version > QUIC_VERSION_44.
+ PACKET_3BYTE_PACKET_NUMBER = 3, // Used in versions 45+.
PACKET_4BYTE_PACKET_NUMBER = 4,
IETF_MAX_PACKET_NUMBER_LENGTH = 4,
// TODO(rch): Remove this when we remove QUIC_VERSION_39.
@@ -519,10 +523,28 @@ enum QuicIetfTransportErrorCodes : uint16_t {
PROTOCOL_VIOLATION = 0xA,
INVALID_MIGRATION = 0xC,
};
+QUIC_EXPORT_PRIVATE std::string QuicIetfTransportErrorCodeString(
+ QuicIetfTransportErrorCodes c);
+
QUIC_EXPORT_PRIVATE std::ostream& operator<<(
std::ostream& os,
const QuicIetfTransportErrorCodes& c);
+// Returns the mapping of the QuicErrorCode to an IETF TransportErrorCode. If
+// first element of the pair is false, it means that an IETF Application Close
+// should be done instead.
+
+struct QuicErrorCodeToIetfMapping {
+ bool is_transport_close_;
+ union {
+ uint64_t application_error_code_;
+ QuicIetfTransportErrorCodes transport_error_code_;
+ };
+};
+
+QUIC_EXPORT_PRIVATE QuicErrorCodeToIetfMapping
+QuicErrorCodeToTransportErrorCode(QuicErrorCode error);
+
// Please note, this value cannot used directly for packet serialization.
enum QuicLongHeaderType : uint8_t {
VERSION_NEGOTIATION,
@@ -624,6 +646,20 @@ enum AckResult {
PACKETS_ACKED_IN_WRONG_PACKET_NUMBER_SPACE,
};
+// There are three different forms of CONNECTION_CLOSE.
+typedef enum QuicConnectionCloseType {
+ GOOGLE_QUIC_CONNECTION_CLOSE = 0,
+ IETF_QUIC_TRANSPORT_CONNECTION_CLOSE = 1,
+ IETF_QUIC_APPLICATION_CONNECTION_CLOSE = 2
+} QuicConnectionCloseType;
+
+QUIC_EXPORT_PRIVATE std::ostream& operator<<(
+ std::ostream& os,
+ const QuicConnectionCloseType type);
+
+QUIC_EXPORT_PRIVATE std::string QuicConnectionCloseTypeString(
+ QuicConnectionCloseType type);
+
} // namespace quic
#endif // QUICHE_QUIC_CORE_QUIC_TYPES_H_
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_types_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_types_test.cc
new file mode 100644
index 00000000000..8b4df895224
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_types_test.cc
@@ -0,0 +1,40 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+
+#include <cstdint>
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+
+namespace quic {
+namespace test {
+namespace {
+
+class QuicUtilsTest : public QuicTest {};
+
+TEST_F(QuicUtilsTest, QuicIetfTransportErrorCodeString) {
+ // QuicIetfTransportErrorCode out of bound.
+ for (quic::QuicErrorCode error = quic::QUIC_ENCRYPTION_FAILURE;
+ error < quic::QUIC_LAST_ERROR;
+ error = static_cast<quic::QuicErrorCode>(error + 1)) {
+ QuicErrorCodeToIetfMapping mapping =
+ QuicErrorCodeToTransportErrorCode(error);
+ if (mapping.is_transport_close_) {
+ EXPECT_EQ(
+ QuicIetfTransportErrorCodeString(mapping.transport_error_code_),
+ QuicStrCat("Unknown Transport Error Code Value: ",
+ static_cast<uint16_t>(mapping.transport_error_code_)));
+ } else {
+ // Some QuicErrorCodes are no longer valid.
+ EXPECT_EQ(QuicIetfTransportErrorCodeString(mapping.transport_error_code_),
+ "NO_IETF_QUIC_ERROR");
+ }
+ }
+}
+
+} // namespace
+} // namespace test
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map_test.cc
index 807a95918ab..5dda2ae9de3 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map_test.cc
@@ -68,8 +68,9 @@ class QuicUnackedPacketMapTest : public QuicTestWithParam<TestParams> {
SerializedPacket CreateRetransmittablePacket(uint64_t packet_number) {
return CreateRetransmittablePacketForStream(
- packet_number, QuicUtils::GetHeadersStreamId(
- CurrentSupportedVersions()[0].transport_version));
+ packet_number, QuicUtils::GetFirstBidirectionalStreamId(
+ CurrentSupportedVersions()[0].transport_version,
+ Perspective::IS_CLIENT));
}
SerializedPacket CreateRetransmittablePacketForStream(
@@ -174,8 +175,9 @@ class QuicUnackedPacketMapTest : public QuicTestWithParam<TestParams> {
}
QuicTransmissionInfo* info = unacked_packets_.GetMutableTransmissionInfo(
QuicPacketNumber(old_packet_number));
- QuicStreamId stream_id = QuicUtils::GetHeadersStreamId(
- CurrentSupportedVersions()[0].transport_version);
+ QuicStreamId stream_id = QuicUtils::GetFirstBidirectionalStreamId(
+ CurrentSupportedVersions()[0].transport_version,
+ Perspective::IS_CLIENT);
for (const auto& frame : info->retransmittable_frames) {
if (frame.type == STREAM_FRAME) {
stream_id = frame.stream_frame.stream_id;
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_utils.cc b/chromium/net/third_party/quiche/src/quic/core/quic_utils.cc
index 40c50afc524..da2cb1a699c 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_utils.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_utils.cc
@@ -11,6 +11,7 @@
#include "net/third_party/quiche/src/quic/core/quic_connection_id.h"
#include "net/third_party/quiche/src/quic/core/quic_constants.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/core/quic_versions.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_aligned.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
@@ -400,11 +401,7 @@ bool QuicUtils::IsCryptoStreamId(QuicTransportVersion version,
// static
QuicStreamId QuicUtils::GetHeadersStreamId(QuicTransportVersion version) {
- if (version == QUIC_VERSION_99) {
- // TODO(b/130659182) Turn this into a QUIC_BUG once we've fully removed
- // the headers stream in those versions.
- return GetQuicFlag(FLAGS_quic_headers_stream_id_in_v99);
- }
+ DCHECK(!VersionUsesQpack(version));
return GetFirstBidirectionalStreamId(version, Perspective::IS_CLIENT);
}
@@ -488,6 +485,15 @@ QuicStreamId QuicUtils::GetFirstUnidirectionalStreamId(
}
// static
+QuicConnectionId QuicUtils::CreateReplacementConnectionId(
+ QuicConnectionId connection_id) {
+ const uint64_t connection_id_hash = FNV1a_64_Hash(
+ QuicStringPiece(connection_id.data(), connection_id.length()));
+ return QuicConnectionId(reinterpret_cast<const char*>(&connection_id_hash),
+ sizeof(connection_id_hash));
+}
+
+// static
QuicConnectionId QuicUtils::CreateRandomConnectionId() {
return CreateRandomConnectionId(kQuicDefaultConnectionIdLength,
QuicRandom::GetInstance());
@@ -508,18 +514,12 @@ QuicConnectionId QuicUtils::CreateRandomConnectionId(
QuicConnectionId QuicUtils::CreateRandomConnectionId(
uint8_t connection_id_length,
QuicRandom* random) {
- if (connection_id_length == 0) {
- return EmptyQuicConnectionId();
- }
- if (connection_id_length > kQuicMaxConnectionIdLength) {
- QUIC_BUG << "Tried to CreateRandomConnectionId of invalid length "
- << static_cast<int>(connection_id_length);
- connection_id_length = kQuicMaxConnectionIdLength;
+ QuicConnectionId connection_id;
+ connection_id.set_length(connection_id_length);
+ if (connection_id.length() > 0) {
+ random->RandBytes(connection_id.mutable_data(), connection_id.length());
}
- char connection_id_bytes[kQuicMaxConnectionIdLength];
- random->RandBytes(connection_id_bytes, connection_id_length);
- return QuicConnectionId(static_cast<char*>(connection_id_bytes),
- connection_id_length);
+ return connection_id;
}
// static
@@ -543,27 +543,57 @@ QuicConnectionId QuicUtils::CreateZeroConnectionId(
}
// static
-bool QuicUtils::IsConnectionIdValidForVersion(QuicConnectionId connection_id,
- QuicTransportVersion version) {
- if (VariableLengthConnectionIdAllowedForVersion(version)) {
- return true;
+bool QuicUtils::IsConnectionIdLengthValidForVersion(
+ size_t connection_id_length,
+ QuicTransportVersion transport_version) {
+ // No version of QUIC can support lengths that do not fit in an uint8_t.
+ if (connection_id_length >
+ static_cast<size_t>(std::numeric_limits<uint8_t>::max())) {
+ return false;
+ }
+ const uint8_t connection_id_length8 =
+ static_cast<uint8_t>(connection_id_length);
+ // Versions that do not support variable lengths only support length 8.
+ if (!VariableLengthConnectionIdAllowedForVersion(transport_version)) {
+ return connection_id_length8 == kQuicDefaultConnectionIdLength;
+ }
+ // Versions that do support variable length but do not have length-prefixed
+ // connection IDs use the 4-bit connection ID length encoding which can
+ // only encode values 0 and 4-18.
+ if (!VersionHasLengthPrefixedConnectionIds(transport_version)) {
+ return connection_id_length8 == 0 ||
+ (connection_id_length8 >= 4 &&
+ connection_id_length8 <= kQuicMaxConnectionId4BitLength);
}
- return connection_id.length() == kQuicDefaultConnectionIdLength;
+ return connection_id_length8 <= kQuicMaxConnectionIdWithLengthPrefixLength;
+}
+
+// static
+bool QuicUtils::IsConnectionIdValidForVersion(
+ QuicConnectionId connection_id,
+ QuicTransportVersion transport_version) {
+ return IsConnectionIdLengthValidForVersion(connection_id.length(),
+ transport_version);
}
QuicUint128 QuicUtils::GenerateStatelessResetToken(
QuicConnectionId connection_id) {
- uint64_t data_bytes[3] = {0, 0, 0};
- static_assert(sizeof(data_bytes) >= kQuicMaxConnectionIdLength,
- "kQuicMaxConnectionIdLength changed");
- memcpy(data_bytes, connection_id.data(), connection_id.length());
- // This is designed so that the common case of 64bit connection IDs
- // produces a stateless reset token that is equal to the connection ID
- // interpreted as a 64bit unsigned integer, to facilitate debugging.
- return MakeQuicUint128(
- QuicEndian::NetToHost64(sizeof(uint64_t) ^ connection_id.length() ^
- data_bytes[1] ^ data_bytes[2]),
- QuicEndian::NetToHost64(data_bytes[0]));
+ if (!GetQuicRestartFlag(quic_use_hashed_stateless_reset_tokens)) {
+ uint64_t data_bytes[3] = {0, 0, 0};
+ static_assert(sizeof(data_bytes) >= kQuicMaxConnectionIdAllVersionsLength,
+ "kQuicMaxConnectionIdAllVersionsLength changed");
+ memcpy(data_bytes, connection_id.data(), connection_id.length());
+ // This is designed so that the common case of 64bit connection IDs
+ // produces a stateless reset token that is equal to the connection ID
+ // interpreted as a 64bit unsigned integer, to facilitate debugging.
+ return MakeQuicUint128(
+ QuicEndian::NetToHost64(sizeof(uint64_t) ^ connection_id.length() ^
+ data_bytes[1] ^ data_bytes[2]),
+ QuicEndian::NetToHost64(data_bytes[0]));
+ }
+ QUIC_RESTART_FLAG_COUNT(quic_use_hashed_stateless_reset_tokens);
+ return FNV1a_128_Hash(
+ QuicStringPiece(connection_id.data(), connection_id.length()));
}
// Returns the maximum value that a stream count may have, taking into account
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_utils.h b/chromium/net/third_party/quiche/src/quic/core/quic_utils.h
index 294f52fa846..de855a0cad8 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_utils.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_utils.h
@@ -11,6 +11,7 @@
#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h"
#include "net/third_party/quiche/src/quic/core/frames/quic_frame.h"
+#include "net/third_party/quiche/src/quic/core/quic_connection_id.h"
#include "net/third_party/quiche/src/quic/core/quic_error_codes.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/core/quic_versions.h"
@@ -109,7 +110,7 @@ class QUIC_EXPORT_PRIVATE QuicUtils {
TransmissionType retransmission_type);
// Returns true if header with |first_byte| is considered as an IETF QUIC
- // packet header.
+ // packet header. This only works on the server.
static bool IsIetfPacketHeader(uint8_t first_byte);
// Returns true if header with |first_byte| is considered as an IETF QUIC
@@ -162,6 +163,12 @@ class QUIC_EXPORT_PRIVATE QuicUtils {
QuicTransportVersion version,
Perspective perspective);
+ // Generates a 64bit connection ID derived from the input connection ID.
+ // This is guaranteed to be deterministic (calling this method with two
+ // connection IDs that are equal is guaranteed to produce the same result).
+ static QuicConnectionId CreateReplacementConnectionId(
+ QuicConnectionId connection_id);
+
// Generates a random 64bit connection ID.
static QuicConnectionId CreateRandomConnectionId();
@@ -181,9 +188,15 @@ class QUIC_EXPORT_PRIVATE QuicUtils {
static bool VariableLengthConnectionIdAllowedForVersion(
QuicTransportVersion version);
+ // Returns true if the connection ID length is valid for this QUIC version.
+ static bool IsConnectionIdLengthValidForVersion(
+ size_t connection_id_length,
+ QuicTransportVersion transport_version);
+
// Returns true if the connection ID is valid for this QUIC version.
- static bool IsConnectionIdValidForVersion(QuicConnectionId connection_id,
- QuicTransportVersion version);
+ static bool IsConnectionIdValidForVersion(
+ QuicConnectionId connection_id,
+ QuicTransportVersion transport_version);
// Returns a connection ID suitable for QUIC use-cases that do not need the
// connection ID for multiplexing. If the version allows variable lengths,
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_utils_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_utils_test.cc
index d0ce7e80a6f..a2bc4030744 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_utils_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_utils_test.cc
@@ -165,6 +165,47 @@ TEST_F(QuicUtilsTest, IsIetfPacketHeader) {
EXPECT_FALSE(QuicUtils::IsIetfPacketShortHeader(first_byte));
}
+TEST_F(QuicUtilsTest, ReplacementConnectionIdIsDeterministic) {
+ // Verify that two equal connection IDs get the same replacement.
+ QuicConnectionId connection_id64a = TestConnectionId(33);
+ QuicConnectionId connection_id64b = TestConnectionId(33);
+ EXPECT_EQ(connection_id64a, connection_id64b);
+ EXPECT_EQ(QuicUtils::CreateReplacementConnectionId(connection_id64a),
+ QuicUtils::CreateReplacementConnectionId(connection_id64b));
+ QuicConnectionId connection_id72a = TestConnectionIdNineBytesLong(42);
+ QuicConnectionId connection_id72b = TestConnectionIdNineBytesLong(42);
+ EXPECT_EQ(connection_id72a, connection_id72b);
+ EXPECT_EQ(QuicUtils::CreateReplacementConnectionId(connection_id72a),
+ QuicUtils::CreateReplacementConnectionId(connection_id72b));
+}
+
+TEST_F(QuicUtilsTest, ReplacementConnectionIdLengthIsCorrect) {
+ // Verify that all lengths get replaced by kQuicDefaultConnectionIdLength.
+ const char connection_id_bytes[kQuicMaxConnectionIdAllVersionsLength] = {};
+ for (uint8_t i = 0; i < sizeof(connection_id_bytes) - 1; ++i) {
+ QuicConnectionId connection_id(connection_id_bytes, i);
+ QuicConnectionId replacement_connection_id =
+ QuicUtils::CreateReplacementConnectionId(connection_id);
+ EXPECT_EQ(kQuicDefaultConnectionIdLength,
+ replacement_connection_id.length());
+ }
+}
+
+TEST_F(QuicUtilsTest, ReplacementConnectionIdHasEntropy) {
+ // Make sure all these test connection IDs have different replacements.
+ for (uint64_t i = 0; i < 256; ++i) {
+ QuicConnectionId connection_id_i = TestConnectionId(i);
+ EXPECT_NE(connection_id_i,
+ QuicUtils::CreateReplacementConnectionId(connection_id_i));
+ for (uint64_t j = i + 1; j <= 256; ++j) {
+ QuicConnectionId connection_id_j = TestConnectionId(j);
+ EXPECT_NE(connection_id_i, connection_id_j);
+ EXPECT_NE(QuicUtils::CreateReplacementConnectionId(connection_id_i),
+ QuicUtils::CreateReplacementConnectionId(connection_id_j));
+ }
+ }
+}
+
TEST_F(QuicUtilsTest, RandomConnectionId) {
MockRandom random(33);
QuicConnectionId connection_id = QuicUtils::CreateRandomConnectionId(&random);
@@ -225,7 +266,9 @@ TEST_F(QuicUtilsTest, StatelessResetToken) {
QuicUint128 token2 = QuicUtils::GenerateStatelessResetToken(connection_id2);
EXPECT_EQ(token1a, token1b);
EXPECT_NE(token1a, token2);
- EXPECT_EQ(token1a, MakeQuicUint128(0, 1));
+ if (!GetQuicRestartFlag(quic_use_hashed_stateless_reset_tokens)) {
+ EXPECT_EQ(token1a, MakeQuicUint128(0, 1));
+ }
}
} // namespace
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 49aee67764b..6b2f60eb6ee 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,9 +15,8 @@ namespace quic {
QuicVersionManager::QuicVersionManager(
ParsedQuicVersionVector supported_versions)
: enable_version_99_(GetQuicReloadableFlag(quic_enable_version_99)),
- enable_version_48_(GetQuicReloadableFlag(quic_enable_version_48)),
+ enable_version_48_(GetQuicReloadableFlag(quic_enable_version_48_2)),
enable_version_47_(GetQuicReloadableFlag(quic_enable_version_47)),
- disable_version_44_(GetQuicReloadableFlag(quic_disable_version_44)),
disable_version_39_(GetQuicReloadableFlag(quic_disable_version_39)),
enable_tls_(GetQuicFlag(FLAGS_quic_supports_tls_handshake)),
allowed_supported_versions_(std::move(supported_versions)) {
@@ -39,15 +38,13 @@ const ParsedQuicVersionVector& QuicVersionManager::GetSupportedVersions() {
void QuicVersionManager::MaybeRefilterSupportedVersions() {
if (enable_version_99_ != GetQuicReloadableFlag(quic_enable_version_99) ||
- enable_version_48_ != GetQuicReloadableFlag(quic_enable_version_48) ||
+ enable_version_48_ != GetQuicReloadableFlag(quic_enable_version_48_2) ||
enable_version_47_ != GetQuicReloadableFlag(quic_enable_version_47) ||
- disable_version_44_ != GetQuicReloadableFlag(quic_disable_version_44) ||
disable_version_39_ != GetQuicReloadableFlag(quic_disable_version_39) ||
enable_tls_ != GetQuicFlag(FLAGS_quic_supports_tls_handshake)) {
enable_version_99_ = GetQuicReloadableFlag(quic_enable_version_99);
- enable_version_48_ = GetQuicReloadableFlag(quic_enable_version_48);
+ enable_version_48_ = GetQuicReloadableFlag(quic_enable_version_48_2);
enable_version_47_ = GetQuicReloadableFlag(quic_enable_version_47);
- disable_version_44_ = GetQuicReloadableFlag(quic_disable_version_44);
disable_version_39_ = GetQuicReloadableFlag(quic_disable_version_39);
enable_tls_ = GetQuicFlag(FLAGS_quic_supports_tls_handshake);
RefilterSupportedVersions();
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.h b/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.h
index a6b7bcbdd93..a0c2d6f2716 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
@@ -33,19 +33,17 @@ class QUIC_EXPORT_PRIVATE QuicVersionManager {
// Refilters filtered_supported_versions_.
virtual void RefilterSupportedVersions();
- const QuicTransportVersionVector& filtered_supported_versions() const {
+ const QuicTransportVersionVector& filtered_transport_versions() const {
return filtered_transport_versions_;
}
private:
// quic_enable_version_99 flag
bool enable_version_99_;
- // quic_enable_version_48 flag
+ // quic_enable_version_48_2 flag
bool enable_version_48_;
// quic_enable_version_47 flag
bool enable_version_47_;
- // quic_disable_version_44 flag
- bool disable_version_44_;
// quic_disable_version_39 flag
bool disable_version_39_;
// quic_supports_tls_handshake flag
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 886c0d3d4ef..7afd55d3033 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_version_manager_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_version_manager_test.cc
@@ -16,12 +16,11 @@ namespace {
class QuicVersionManagerTest : public QuicTest {};
TEST_F(QuicVersionManagerTest, QuicVersionManager) {
- static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 7u,
+ static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 6u,
"Supported versions out of sync");
SetQuicReloadableFlag(quic_enable_version_99, false);
- SetQuicReloadableFlag(quic_enable_version_48, false);
+ SetQuicReloadableFlag(quic_enable_version_48_2, false);
SetQuicReloadableFlag(quic_enable_version_47, false);
- SetQuicReloadableFlag(quic_disable_version_44, true);
SetQuicReloadableFlag(quic_disable_version_39, true);
QuicVersionManager manager(AllSupportedVersions());
@@ -36,29 +35,23 @@ TEST_F(QuicVersionManagerTest, QuicVersionManager) {
{QUIC_VERSION_46, QUIC_VERSION_43, QUIC_VERSION_39}),
manager.GetSupportedTransportVersions());
- SetQuicReloadableFlag(quic_disable_version_44, false);
- EXPECT_EQ(QuicTransportVersionVector({QUIC_VERSION_46, QUIC_VERSION_44,
- QUIC_VERSION_43, QUIC_VERSION_39}),
- manager.GetSupportedTransportVersions());
-
SetQuicReloadableFlag(quic_enable_version_47, true);
EXPECT_EQ(QuicTransportVersionVector({QUIC_VERSION_47, QUIC_VERSION_46,
- QUIC_VERSION_44, QUIC_VERSION_43,
- QUIC_VERSION_39}),
+ QUIC_VERSION_43, QUIC_VERSION_39}),
manager.GetSupportedTransportVersions());
- SetQuicReloadableFlag(quic_enable_version_48, true);
+ SetQuicReloadableFlag(quic_enable_version_48_2, true);
EXPECT_EQ(QuicTransportVersionVector({QUIC_VERSION_48, QUIC_VERSION_47,
- QUIC_VERSION_46, QUIC_VERSION_44,
- QUIC_VERSION_43, QUIC_VERSION_39}),
+ QUIC_VERSION_46, QUIC_VERSION_43,
+ QUIC_VERSION_39}),
manager.GetSupportedTransportVersions());
SetQuicReloadableFlag(quic_enable_version_99, true);
- EXPECT_EQ(
- QuicTransportVersionVector(
- {QUIC_VERSION_99, QUIC_VERSION_48, QUIC_VERSION_47, QUIC_VERSION_46,
- QUIC_VERSION_44, QUIC_VERSION_43, QUIC_VERSION_39}),
- manager.GetSupportedTransportVersions());
+ SetQuicReloadableFlag(quic_use_parse_public_header, true);
+ EXPECT_EQ(QuicTransportVersionVector({QUIC_VERSION_99, QUIC_VERSION_48,
+ QUIC_VERSION_47, QUIC_VERSION_46,
+ QUIC_VERSION_43, QUIC_VERSION_39}),
+ manager.GetSupportedTransportVersions());
// Ensure that all versions are now supported.
EXPECT_EQ(FilterSupportedTransportVersions(AllSupportedTransportVersions()),
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_versions.cc b/chromium/net/third_party/quiche/src/quic/core/quic_versions.cc
index 950dd1d1cd0..8281b688198 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_versions.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_versions.cc
@@ -72,23 +72,21 @@ bool ParsedQuicVersion::SendsVariableLengthPacketNumberInLongHeader() const {
}
bool ParsedQuicVersion::SupportsClientConnectionIds() const {
- if (!GetQuicRestartFlag(quic_do_not_override_connection_id)) {
- // Do not enable this feature in a production version until this flag has
- // been deprecated.
- return false;
- }
return transport_version >= QUIC_VERSION_99;
}
-bool ParsedQuicVersion::DoesNotHaveHeadersStream() const {
- return VersionLacksHeadersStream(transport_version);
+bool ParsedQuicVersion::HasLengthPrefixedConnectionIds() const {
+ return VersionHasLengthPrefixedConnectionIds(transport_version);
}
-bool VersionLacksHeadersStream(QuicTransportVersion transport_version) {
- if (GetQuicFlag(FLAGS_quic_headers_stream_id_in_v99) == 0) {
- return false;
- }
- return transport_version == QUIC_VERSION_99;
+bool ParsedQuicVersion::SupportsAntiAmplificationLimit() const {
+ return transport_version == QUIC_VERSION_99 &&
+ handshake_protocol == PROTOCOL_TLS1_3;
+}
+
+bool VersionHasLengthPrefixedConnectionIds(
+ QuicTransportVersion transport_version) {
+ return transport_version >= QUIC_VERSION_99;
}
std::ostream& operator<<(std::ostream& os, const ParsedQuicVersion& version) {
@@ -115,8 +113,6 @@ QuicVersionLabel CreateQuicVersionLabel(ParsedQuicVersion parsed_version) {
return MakeVersionLabel(proto, '0', '3', '9');
case QUIC_VERSION_43:
return MakeVersionLabel(proto, '0', '4', '3');
- case QUIC_VERSION_44:
- return MakeVersionLabel(proto, '0', '4', '4');
case QUIC_VERSION_46:
return MakeVersionLabel(proto, '0', '4', '6');
case QUIC_VERSION_47:
@@ -124,10 +120,8 @@ QuicVersionLabel CreateQuicVersionLabel(ParsedQuicVersion parsed_version) {
case QUIC_VERSION_48:
return MakeVersionLabel(proto, '0', '4', '8');
case QUIC_VERSION_99:
- if (parsed_version.handshake_protocol == PROTOCOL_TLS1_3 &&
- GetQuicFlag(FLAGS_quic_ietf_draft_version) != 0) {
- return MakeVersionLabel(0xff, 0x00, 0x00,
- GetQuicFlag(FLAGS_quic_ietf_draft_version));
+ if (parsed_version.handshake_protocol == PROTOCOL_TLS1_3) {
+ return MakeVersionLabel(0xff, 0x00, 0x00, kQuicIetfDraftVersion);
}
return MakeVersionLabel(proto, '0', '9', '9');
case QUIC_VERSION_RESERVED_FOR_NEGOTIATION:
@@ -262,21 +256,18 @@ ParsedQuicVersionVector FilterSupportedVersions(
continue;
}
if (version.transport_version == QUIC_VERSION_99) {
- if (GetQuicReloadableFlag(quic_enable_version_99)) {
+ if (GetQuicReloadableFlag(quic_enable_version_99) &&
+ GetQuicReloadableFlag(quic_use_parse_public_header)) {
filtered_versions.push_back(version);
}
} else if (version.transport_version == QUIC_VERSION_48) {
- if (GetQuicReloadableFlag(quic_enable_version_48)) {
+ if (GetQuicReloadableFlag(quic_enable_version_48_2)) {
filtered_versions.push_back(version);
}
} else if (version.transport_version == QUIC_VERSION_47) {
if (GetQuicReloadableFlag(quic_enable_version_47)) {
filtered_versions.push_back(version);
}
- } else if (version.transport_version == QUIC_VERSION_44) {
- if (!GetQuicReloadableFlag(quic_disable_version_44)) {
- filtered_versions.push_back(version);
- }
} else if (version.transport_version == QUIC_VERSION_39) {
if (!GetQuicReloadableFlag(quic_disable_version_39)) {
filtered_versions.push_back(version);
@@ -371,7 +362,6 @@ std::string QuicVersionToString(QuicTransportVersion transport_version) {
switch (transport_version) {
RETURN_STRING_LITERAL(QUIC_VERSION_39);
RETURN_STRING_LITERAL(QUIC_VERSION_43);
- RETURN_STRING_LITERAL(QUIC_VERSION_44);
RETURN_STRING_LITERAL(QUIC_VERSION_46);
RETURN_STRING_LITERAL(QUIC_VERSION_47);
RETURN_STRING_LITERAL(QUIC_VERSION_48);
@@ -418,6 +408,34 @@ std::string ParsedQuicVersionVectorToString(
return result;
}
+bool QuicVersionLabelUses4BitConnectionIdLength(
+ QuicVersionLabel version_label) {
+ // As we deprecate old versions, we still need the ability to send valid
+ // version negotiation packets for those versions. This function keeps track
+ // of the versions that ever supported the 4bit connection ID length encoding
+ // that we know about. Google QUIC 43 and earlier used a different encoding,
+ // and Google QUIC 49 will start using the new length prefixed encoding.
+ // Similarly, only IETF drafts 11 to 21 used this encoding.
+
+ // Check Q044, Q045, Q046, Q047 and Q048.
+ for (uint8_t c = '4'; c <= '8'; ++c) {
+ if (version_label == MakeVersionLabel('Q', '0', '4', c)) {
+ return true;
+ }
+ }
+ // Check T048.
+ if (version_label == MakeVersionLabel('T', '0', '4', '8')) {
+ return true;
+ }
+ // Check IETF draft versions in [11,21].
+ for (uint8_t draft_number = 11; draft_number <= 21; ++draft_number) {
+ if (version_label == MakeVersionLabel(0xff, 0x00, 0x00, draft_number)) {
+ return true;
+ }
+ }
+ return false;
+}
+
ParsedQuicVersion UnsupportedQuicVersion() {
return ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED);
}
@@ -429,46 +447,32 @@ ParsedQuicVersion QuicVersionReservedForNegotiation() {
std::string AlpnForVersion(ParsedQuicVersion parsed_version) {
if (parsed_version.handshake_protocol == PROTOCOL_TLS1_3 &&
- parsed_version.transport_version == QUIC_VERSION_99 &&
- GetQuicFlag(FLAGS_quic_ietf_draft_version) != 0) {
- return "h3-" + QuicTextUtils::Uint64ToString(
- GetQuicFlag(FLAGS_quic_ietf_draft_version));
+ parsed_version.transport_version == QUIC_VERSION_99) {
+ return "h3-" + QuicTextUtils::Uint64ToString(kQuicIetfDraftVersion);
}
- return "h3-google-" + ParsedQuicVersionToString(parsed_version);
+ return "h3-" + ParsedQuicVersionToString(parsed_version);
}
-void QuicVersionInitializeSupportForIetfDraft(int32_t draft_version) {
- if (draft_version < 0 || draft_version >= 256) {
- QUIC_LOG(FATAL) << "Invalid IETF draft version " << draft_version;
- return;
- }
-
- SetQuicFlag(FLAGS_quic_ietf_draft_version, draft_version);
-
- if (draft_version == 0) {
- return;
- }
-
+void QuicVersionInitializeSupportForIetfDraft() {
// Enable necessary flags.
SetQuicFlag(FLAGS_quic_supports_tls_handshake, true);
- SetQuicFlag(FLAGS_quic_headers_stream_id_in_v99, 60);
SetQuicReloadableFlag(quic_simplify_stop_waiting, true);
- SetQuicRestartFlag(quic_do_not_override_connection_id, true);
- SetQuicRestartFlag(quic_use_allocated_connection_ids, true);
+ SetQuicReloadableFlag(quic_use_parse_public_header, true);
SetQuicRestartFlag(quic_dispatcher_hands_chlo_extractor_one_version, true);
+ SetQuicRestartFlag(quic_use_hashed_stateless_reset_tokens, true);
}
void QuicEnableVersion(ParsedQuicVersion parsed_version) {
if (parsed_version.handshake_protocol == PROTOCOL_TLS1_3) {
SetQuicFlag(FLAGS_quic_supports_tls_handshake, true);
}
- static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 7u,
+ static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 6u,
"Supported versions out of sync");
if (parsed_version.transport_version == QUIC_VERSION_99) {
SetQuicReloadableFlag(quic_enable_version_99, true);
}
if (parsed_version.transport_version == QUIC_VERSION_48) {
- SetQuicReloadableFlag(quic_enable_version_48, true);
+ SetQuicReloadableFlag(quic_enable_version_48_2, true);
}
if (parsed_version.transport_version == QUIC_VERSION_47) {
SetQuicReloadableFlag(quic_enable_version_47, true);
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_versions.h b/chromium/net/third_party/quiche/src/quic/core/quic_versions.h
index 72bb32ca4ba..5b2a6ed35bd 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_versions.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_versions.h
@@ -97,7 +97,7 @@ enum QuicTransportVersion {
QUIC_VERSION_43 = 43, // PRIORITY frames are sent by client and accepted by
// server.
- QUIC_VERSION_44 = 44, // Use IETF header format.
+ // Version 44 used IETF header format from draft-ietf-quic-invariants-05.
// Version 45 added MESSAGE frame.
@@ -116,6 +116,9 @@ enum QuicTransportVersion {
QUIC_VERSION_RESERVED_FOR_NEGOTIATION = 999,
};
+// IETF draft version most closely approximated by TLS + v99.
+static const int kQuicIetfDraftVersion = 22;
+
// The crypto handshake protocols that can be used with QUIC.
enum HandshakeProtocol {
PROTOCOL_UNSUPPORTED,
@@ -173,8 +176,15 @@ struct QUIC_EXPORT_PRIVATE ParsedQuicVersion {
// Returns whether this version supports client connection ID.
bool SupportsClientConnectionIds() const;
- // Returns whether this version does not have the Google QUIC headers stream.
- bool DoesNotHaveHeadersStream() const;
+ // Returns whether this version supports long header 8-bit encoded
+ // connection ID lengths as described in draft-ietf-quic-invariants-06 and
+ // draft-ietf-quic-transport-22.
+ bool HasLengthPrefixedConnectionIds() const;
+
+ // Returns whether this version supports IETF style anti-amplification limit,
+ // i.e., server will send no more than FLAGS_quic_anti_amplification_factor
+ // times received bytes until address can be validated.
+ bool SupportsAntiAmplificationLimit() const;
};
QUIC_EXPORT_PRIVATE ParsedQuicVersion UnsupportedQuicVersion();
@@ -198,8 +208,8 @@ using QuicVersionLabelVector = std::vector<QuicVersionLabel>;
//
// See go/new-quic-version for more details on how to roll out new versions.
static const QuicTransportVersion kSupportedTransportVersions[] = {
- QUIC_VERSION_99, QUIC_VERSION_48, QUIC_VERSION_47, QUIC_VERSION_46,
- QUIC_VERSION_44, QUIC_VERSION_43, QUIC_VERSION_39,
+ QUIC_VERSION_99, QUIC_VERSION_48, QUIC_VERSION_47,
+ QUIC_VERSION_46, QUIC_VERSION_43, QUIC_VERSION_39,
};
// This vector contains all crypto handshake protocols that are supported.
@@ -355,7 +365,7 @@ QUIC_EXPORT_PRIVATE inline bool VersionHasIetfInvariantHeader(
// Returns true if |transport_version| supports MESSAGE frames.
QUIC_EXPORT_PRIVATE inline bool VersionSupportsMessageFrames(
QuicTransportVersion transport_version) {
- return transport_version > QUIC_VERSION_44;
+ return transport_version >= QUIC_VERSION_46;
}
// Returns true if QuicSpdyStream encodes body using HTTP/3 specification and
@@ -375,19 +385,14 @@ QUIC_EXPORT_PRIVATE inline bool VersionHasStreamType(
// * QuicSpdySession instantiates a QPACK encoder and decoder;
// * HEADERS frames (containing headers or trailers) are sent on
// request/response streams, compressed with QPACK;
-// * trailers must not contain :final-offset key.
+// * trailers must not contain :final-offset key,
+// * PUSH_PROMISE and PRIORITY frames are sent on the request stream,
+// * there is no headers stream.
// If false:
// * HEADERS frames (containing headers or trailers) are sent on the headers
// stream, compressed with HPACK;
-// * trailers must contain :final-offset key.
-//
-// TODO(123528590): Implement the following features and gate them on this
-// function as well, optionally renaming this function as appropriate:
-// * send PUSH_PROMISE frames on the request/response stream instead of the
-// headers stream;
-// * send PRIORITY frames on the request/response stream instead of the headers
-// stream;
-// * do not instantiate the headers stream object.
+// * trailers must contain :final-offset key,
+// * PUSH_PROMISE and PRIORITY frames are sent on the headers stream.
QUIC_EXPORT_PRIVATE inline bool VersionUsesQpack(
QuicTransportVersion transport_version) {
const bool uses_qpack = (transport_version == QUIC_VERSION_99);
@@ -414,11 +419,6 @@ QUIC_EXPORT_PRIVATE inline bool QuicVersionUsesCryptoFrames(
return transport_version >= QUIC_VERSION_48;
}
-// Returns whether |transport_version| does not have the
-// Google QUIC headers stream.
-QUIC_EXPORT_PRIVATE bool VersionLacksHeadersStream(
- QuicTransportVersion transport_version);
-
// Returns whether |transport_version| makes use of IETF QUIC
// frames or not.
QUIC_EXPORT_PRIVATE inline bool VersionHasIetfQuicFrames(
@@ -426,14 +426,25 @@ QUIC_EXPORT_PRIVATE inline bool VersionHasIetfQuicFrames(
return transport_version >= QUIC_VERSION_99;
}
+// Returns whether this version supports long header 8-bit encoded
+// connection ID lengths as described in draft-ietf-quic-invariants-06 and
+// draft-ietf-quic-transport-22.
+QUIC_EXPORT_PRIVATE bool VersionHasLengthPrefixedConnectionIds(
+ QuicTransportVersion transport_version);
+
+// Returns whether this version label supports long header 4-bit encoded
+// connection ID lengths as described in draft-ietf-quic-invariants-05 and
+// draft-ietf-quic-transport-21.
+QUIC_EXPORT_PRIVATE bool QuicVersionLabelUses4BitConnectionIdLength(
+ QuicVersionLabel version_label);
+
// Returns the ALPN string to use in TLS for this version of QUIC.
QUIC_EXPORT_PRIVATE std::string AlpnForVersion(
ParsedQuicVersion parsed_version);
-// Initializes support for the provided IETF draft version by setting flags
-// and the version label.
-QUIC_EXPORT_PRIVATE void QuicVersionInitializeSupportForIetfDraft(
- int32_t draft_version);
+// Initializes support for the provided IETF draft version by setting the
+// correct flags.
+QUIC_EXPORT_PRIVATE void QuicVersionInitializeSupportForIetfDraft();
// Enables the flags required to support this version of QUIC.
QUIC_EXPORT_PRIVATE void QuicEnableVersion(ParsedQuicVersion parsed_version);
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_versions_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_versions_test.cc
index 016ae5f5ca6..f5b0dd2a68a 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_versions_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_versions_test.cc
@@ -116,8 +116,6 @@ TEST_F(QuicVersionsTest, ParseQuicVersionLabel) {
ParseQuicVersionLabel(MakeVersionLabel('Q', '0', '3', '9')));
EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43),
ParseQuicVersionLabel(MakeVersionLabel('Q', '0', '4', '3')));
- EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_44),
- ParseQuicVersionLabel(MakeVersionLabel('Q', '0', '4', '4')));
EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46),
ParseQuicVersionLabel(MakeVersionLabel('Q', '0', '4', '6')));
EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_47),
@@ -130,8 +128,6 @@ TEST_F(QuicVersionsTest, ParseQuicVersionLabel) {
ParseQuicVersionLabel(MakeVersionLabel('T', '0', '3', '9')));
EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_43),
ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '3')));
- EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_44),
- ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '4')));
EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_46),
ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '6')));
EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_47),
@@ -145,8 +141,6 @@ TEST_F(QuicVersionsTest, ParseQuicVersionString) {
ParseQuicVersionString("Q039"));
EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43),
ParseQuicVersionString("Q043"));
- EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_44),
- ParseQuicVersionString("Q044"));
EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46),
ParseQuicVersionString("Q046"));
EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_47),
@@ -164,8 +158,6 @@ TEST_F(QuicVersionsTest, ParseQuicVersionString) {
ParseQuicVersionString("T039"));
EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_43),
ParseQuicVersionString("T043"));
- EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_44),
- ParseQuicVersionString("T044"));
EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_46),
ParseQuicVersionString("T046"));
EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_47),
@@ -181,9 +173,6 @@ TEST_F(QuicVersionsTest, CreateQuicVersionLabel) {
EXPECT_EQ(MakeVersionLabel('Q', '0', '4', '3'),
CreateQuicVersionLabel(
ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43)));
- EXPECT_EQ(MakeVersionLabel('Q', '0', '4', '4'),
- CreateQuicVersionLabel(
- ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_44)));
EXPECT_EQ(MakeVersionLabel('Q', '0', '4', '6'),
CreateQuicVersionLabel(
ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46)));
@@ -201,9 +190,6 @@ TEST_F(QuicVersionsTest, CreateQuicVersionLabel) {
EXPECT_EQ(MakeVersionLabel('T', '0', '4', '3'),
CreateQuicVersionLabel(
ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_43)));
- EXPECT_EQ(MakeVersionLabel('T', '0', '4', '4'),
- CreateQuicVersionLabel(
- ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_44)));
EXPECT_EQ(MakeVersionLabel('T', '0', '4', '6'),
CreateQuicVersionLabel(
ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_46)));
@@ -308,17 +294,17 @@ TEST_F(QuicVersionsTest, AllSupportedTransportVersions) {
TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsAllVersions) {
QuicTransportVersionVector all_versions = AllSupportedTransportVersions();
SetQuicReloadableFlag(quic_disable_version_39, false);
- SetQuicReloadableFlag(quic_disable_version_44, false);
SetQuicReloadableFlag(quic_enable_version_47, true);
- SetQuicReloadableFlag(quic_enable_version_48, true);
+ SetQuicReloadableFlag(quic_enable_version_48_2, true);
SetQuicReloadableFlag(quic_enable_version_99, true);
+ SetQuicReloadableFlag(quic_use_parse_public_header, true);
ParsedQuicVersionVector parsed_versions;
for (QuicTransportVersion version : all_versions) {
parsed_versions.push_back(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version));
}
QuicTransportVersionVector expected_versions = {
- QUIC_VERSION_99, QUIC_VERSION_48, QUIC_VERSION_47, QUIC_VERSION_46,
- QUIC_VERSION_44, QUIC_VERSION_43, QUIC_VERSION_39};
+ QUIC_VERSION_99, QUIC_VERSION_48, QUIC_VERSION_47,
+ QUIC_VERSION_46, QUIC_VERSION_43, QUIC_VERSION_39};
ParsedQuicVersionVector expected_parsed_versions;
for (QuicTransportVersion version : expected_versions) {
expected_parsed_versions.push_back(
@@ -332,17 +318,16 @@ TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsAllVersions) {
TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo99) {
QuicTransportVersionVector all_versions = AllSupportedTransportVersions();
SetQuicReloadableFlag(quic_disable_version_39, false);
- SetQuicReloadableFlag(quic_disable_version_44, false);
SetQuicReloadableFlag(quic_enable_version_47, true);
- SetQuicReloadableFlag(quic_enable_version_48, true);
+ SetQuicReloadableFlag(quic_enable_version_48_2, true);
SetQuicReloadableFlag(quic_enable_version_99, false);
ParsedQuicVersionVector parsed_versions;
for (QuicTransportVersion version : all_versions) {
parsed_versions.push_back(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version));
}
QuicTransportVersionVector expected_versions = {
- QUIC_VERSION_48, QUIC_VERSION_47, QUIC_VERSION_46,
- QUIC_VERSION_44, QUIC_VERSION_43, QUIC_VERSION_39};
+ QUIC_VERSION_48, QUIC_VERSION_47, QUIC_VERSION_46, QUIC_VERSION_43,
+ QUIC_VERSION_39};
ParsedQuicVersionVector expected_parsed_versions;
for (QuicTransportVersion version : expected_versions) {
expected_parsed_versions.push_back(
@@ -356,17 +341,15 @@ TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo99) {
TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo48) {
QuicTransportVersionVector all_versions = AllSupportedTransportVersions();
SetQuicReloadableFlag(quic_disable_version_39, false);
- SetQuicReloadableFlag(quic_disable_version_44, false);
SetQuicReloadableFlag(quic_enable_version_47, true);
- SetQuicReloadableFlag(quic_enable_version_48, false);
+ SetQuicReloadableFlag(quic_enable_version_48_2, false);
SetQuicReloadableFlag(quic_enable_version_99, false);
ParsedQuicVersionVector parsed_versions;
for (QuicTransportVersion version : all_versions) {
parsed_versions.push_back(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version));
}
QuicTransportVersionVector expected_versions = {
- QUIC_VERSION_47, QUIC_VERSION_46, QUIC_VERSION_44, QUIC_VERSION_43,
- QUIC_VERSION_39};
+ QUIC_VERSION_47, QUIC_VERSION_46, QUIC_VERSION_43, QUIC_VERSION_39};
ParsedQuicVersionVector expected_parsed_versions;
for (QuicTransportVersion version : expected_versions) {
expected_parsed_versions.push_back(
@@ -380,32 +363,8 @@ TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo48) {
TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo47) {
QuicTransportVersionVector all_versions = AllSupportedTransportVersions();
SetQuicReloadableFlag(quic_disable_version_39, false);
- SetQuicReloadableFlag(quic_disable_version_44, false);
SetQuicReloadableFlag(quic_enable_version_47, false);
- SetQuicReloadableFlag(quic_enable_version_48, false);
- SetQuicReloadableFlag(quic_enable_version_99, false);
- ParsedQuicVersionVector parsed_versions;
- for (QuicTransportVersion version : all_versions) {
- parsed_versions.push_back(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version));
- }
- QuicTransportVersionVector expected_versions = {
- QUIC_VERSION_46, QUIC_VERSION_44, QUIC_VERSION_43, QUIC_VERSION_39};
- ParsedQuicVersionVector expected_parsed_versions;
- for (QuicTransportVersion version : expected_versions) {
- expected_parsed_versions.push_back(
- ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version));
- }
-
- ASSERT_EQ(expected_versions, FilterSupportedTransportVersions(all_versions));
- ASSERT_EQ(expected_parsed_versions, FilterSupportedVersions(parsed_versions));
-}
-
-TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo44) {
- QuicTransportVersionVector all_versions = AllSupportedTransportVersions();
- SetQuicReloadableFlag(quic_disable_version_39, false);
- SetQuicReloadableFlag(quic_disable_version_44, true);
- SetQuicReloadableFlag(quic_enable_version_47, false);
- SetQuicReloadableFlag(quic_enable_version_48, false);
+ SetQuicReloadableFlag(quic_enable_version_48_2, false);
SetQuicReloadableFlag(quic_enable_version_99, false);
ParsedQuicVersionVector parsed_versions;
for (QuicTransportVersion version : all_versions) {
@@ -426,16 +385,15 @@ TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo44) {
TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo39) {
QuicTransportVersionVector all_versions = AllSupportedTransportVersions();
SetQuicReloadableFlag(quic_disable_version_39, true);
- SetQuicReloadableFlag(quic_disable_version_44, false);
SetQuicReloadableFlag(quic_enable_version_47, false);
- SetQuicReloadableFlag(quic_enable_version_48, false);
+ SetQuicReloadableFlag(quic_enable_version_48_2, false);
SetQuicReloadableFlag(quic_enable_version_99, false);
ParsedQuicVersionVector parsed_versions;
for (QuicTransportVersion version : all_versions) {
parsed_versions.push_back(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version));
}
- QuicTransportVersionVector expected_versions = {
- QUIC_VERSION_46, QUIC_VERSION_44, QUIC_VERSION_43};
+ QuicTransportVersionVector expected_versions = {QUIC_VERSION_46,
+ QUIC_VERSION_43};
ParsedQuicVersionVector expected_parsed_versions;
for (QuicTransportVersion version : expected_versions) {
expected_parsed_versions.push_back(
@@ -485,11 +443,10 @@ TEST_F(QuicVersionsTest, ParsedVersionsToTransportVersions) {
// yet a typo was made in doing the #defines and it was caught
// only in some test far removed from here... Better safe than sorry.
TEST_F(QuicVersionsTest, CheckVersionNumbersForTypos) {
- static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 7u,
+ static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 6u,
"Supported versions out of sync");
EXPECT_EQ(QUIC_VERSION_39, 39);
EXPECT_EQ(QUIC_VERSION_43, 43);
- EXPECT_EQ(QUIC_VERSION_44, 44);
EXPECT_EQ(QUIC_VERSION_46, 46);
EXPECT_EQ(QUIC_VERSION_47, 47);
EXPECT_EQ(QUIC_VERSION_48, 48);
@@ -508,36 +465,11 @@ TEST_F(QuicVersionsTest, AlpnForVersion) {
ParsedQuicVersion parsed_version_t099 =
ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_99);
- EXPECT_EQ("h3-google-Q047", AlpnForVersion(parsed_version_q047));
- EXPECT_EQ("h3-google-T047", AlpnForVersion(parsed_version_t047));
- EXPECT_EQ("h3-google-Q048", AlpnForVersion(parsed_version_q048));
- EXPECT_EQ("h3-google-T048", AlpnForVersion(parsed_version_t048));
- EXPECT_EQ("h3-google-T099", AlpnForVersion(parsed_version_t099));
-}
-
-TEST_F(QuicVersionsTest, InitializeSupportForIetfDraft) {
- ParsedQuicVersion parsed_version_t099 =
- ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_99);
- EXPECT_EQ(MakeVersionLabel('T', '0', '9', '9'),
- CreateQuicVersionLabel(parsed_version_t099));
- EXPECT_EQ("h3-google-T099", AlpnForVersion(parsed_version_t099));
-
- QuicVersionInitializeSupportForIetfDraft(0);
- EXPECT_EQ(MakeVersionLabel('T', '0', '9', '9'),
- CreateQuicVersionLabel(parsed_version_t099));
- EXPECT_EQ("h3-google-T099", AlpnForVersion(parsed_version_t099));
- EXPECT_FALSE(GetQuicFlag(FLAGS_quic_supports_tls_handshake));
-
- QuicVersionInitializeSupportForIetfDraft(18);
- EXPECT_TRUE(GetQuicFlag(FLAGS_quic_supports_tls_handshake));
- EXPECT_EQ(MakeVersionLabel(0xff, 0, 0, 18),
- CreateQuicVersionLabel(parsed_version_t099));
- EXPECT_EQ("h3-18", AlpnForVersion(parsed_version_t099));
-
- QuicVersionInitializeSupportForIetfDraft(0);
- EXPECT_EQ(MakeVersionLabel('T', '0', '9', '9'),
- CreateQuicVersionLabel(parsed_version_t099));
- EXPECT_EQ("h3-google-T099", AlpnForVersion(parsed_version_t099));
+ EXPECT_EQ("h3-Q047", AlpnForVersion(parsed_version_q047));
+ EXPECT_EQ("h3-T047", AlpnForVersion(parsed_version_t047));
+ EXPECT_EQ("h3-Q048", AlpnForVersion(parsed_version_q048));
+ EXPECT_EQ("h3-T048", AlpnForVersion(parsed_version_t048));
+ EXPECT_EQ("h3-22", AlpnForVersion(parsed_version_t099));
}
TEST_F(QuicVersionsTest, QuicEnableVersion) {
@@ -554,9 +486,8 @@ TEST_F(QuicVersionsTest, QuicEnableVersion) {
ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_99);
SetQuicFlag(FLAGS_quic_supports_tls_handshake, false);
SetQuicReloadableFlag(quic_disable_version_39, false);
- SetQuicReloadableFlag(quic_disable_version_44, false);
SetQuicReloadableFlag(quic_enable_version_47, false);
- SetQuicReloadableFlag(quic_enable_version_48, false);
+ SetQuicReloadableFlag(quic_enable_version_48_2, false);
SetQuicReloadableFlag(quic_enable_version_99, false);
{
@@ -564,7 +495,7 @@ TEST_F(QuicVersionsTest, QuicEnableVersion) {
QuicEnableVersion(parsed_version_q047);
EXPECT_FALSE(GetQuicFlag(FLAGS_quic_supports_tls_handshake));
EXPECT_TRUE(GetQuicReloadableFlag(quic_enable_version_47));
- EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_48));
+ EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_48_2));
EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_99));
}
@@ -573,7 +504,7 @@ TEST_F(QuicVersionsTest, QuicEnableVersion) {
QuicEnableVersion(parsed_version_t047);
EXPECT_TRUE(GetQuicFlag(FLAGS_quic_supports_tls_handshake));
EXPECT_TRUE(GetQuicReloadableFlag(quic_enable_version_47));
- EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_48));
+ EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_48_2));
EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_99));
}
@@ -582,7 +513,7 @@ TEST_F(QuicVersionsTest, QuicEnableVersion) {
QuicEnableVersion(parsed_version_q048);
EXPECT_FALSE(GetQuicFlag(FLAGS_quic_supports_tls_handshake));
EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_47));
- EXPECT_TRUE(GetQuicReloadableFlag(quic_enable_version_48));
+ EXPECT_TRUE(GetQuicReloadableFlag(quic_enable_version_48_2));
EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_99));
}
@@ -591,7 +522,7 @@ TEST_F(QuicVersionsTest, QuicEnableVersion) {
QuicEnableVersion(parsed_version_t048);
EXPECT_TRUE(GetQuicFlag(FLAGS_quic_supports_tls_handshake));
EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_47));
- EXPECT_TRUE(GetQuicReloadableFlag(quic_enable_version_48));
+ EXPECT_TRUE(GetQuicReloadableFlag(quic_enable_version_48_2));
EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_99));
}
@@ -600,7 +531,7 @@ TEST_F(QuicVersionsTest, QuicEnableVersion) {
QuicEnableVersion(parsed_version_t099);
EXPECT_TRUE(GetQuicFlag(FLAGS_quic_supports_tls_handshake));
EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_47));
- EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_48));
+ EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_48_2));
EXPECT_TRUE(GetQuicReloadableFlag(quic_enable_version_99));
}
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list.cc b/chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list.cc
index d7fe3c0e554..8e4bcf118b7 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list.cc
@@ -10,10 +10,13 @@
namespace quic {
QuicWriteBlockedList::QuicWriteBlockedList(QuicTransportVersion version)
- : priority_write_scheduler_(QuicVersionUsesCryptoFrames(version)
- ? std::numeric_limits<QuicStreamId>::max()
- : 0),
- last_priority_popped_(0) {
+ : priority_write_scheduler_(
+ QuicMakeUnique<spdy::PriorityWriteScheduler<QuicStreamId>>(
+ QuicVersionUsesCryptoFrames(version)
+ ? std::numeric_limits<QuicStreamId>::max()
+ : 0)),
+ last_priority_popped_(0),
+ scheduler_type_(spdy::WriteSchedulerType::SPDY) {
memset(batch_write_stream_id_, 0, sizeof(batch_write_stream_id_));
memset(bytes_left_for_batch_write_, 0, sizeof(bytes_left_for_batch_write_));
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list.h b/chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list.h
index eca7c1a29ab..72ebc051ca1 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list.h
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list.h
@@ -9,9 +9,14 @@
#include <cstdint>
#include "net/third_party/quiche/src/quic/core/quic_packets.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_map_util.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
+#include "net/third_party/quiche/src/spdy/core/fifo_write_scheduler.h"
+#include "net/third_party/quiche/src/spdy/core/http2_priority_write_scheduler.h"
+#include "net/third_party/quiche/src/spdy/core/lifo_write_scheduler.h"
#include "net/third_party/quiche/src/spdy/core/priority_write_scheduler.h"
namespace quic {
@@ -21,7 +26,7 @@ namespace quic {
// Crypto stream > Headers stream > Data streams by requested priority.
class QUIC_EXPORT_PRIVATE QuicWriteBlockedList {
private:
- typedef spdy::PriorityWriteScheduler<QuicStreamId> QuicPriorityWriteScheduler;
+ typedef spdy::WriteScheduler<QuicStreamId> QuicPriorityWriteScheduler;
public:
explicit QuicWriteBlockedList(QuicTransportVersion version);
@@ -30,7 +35,7 @@ class QUIC_EXPORT_PRIVATE QuicWriteBlockedList {
~QuicWriteBlockedList();
bool HasWriteBlockedDataStreams() const {
- return priority_write_scheduler_.HasReadyStreams();
+ return priority_write_scheduler_->HasReadyStreams();
}
bool HasWriteBlockedSpecialStream() const {
@@ -43,7 +48,7 @@ class QUIC_EXPORT_PRIVATE QuicWriteBlockedList {
size_t NumBlockedStreams() const {
return NumBlockedSpecialStreams() +
- priority_write_scheduler_.NumReadyStreams();
+ priority_write_scheduler_->NumReadyStreams();
}
bool ShouldYield(QuicStreamId id) const {
@@ -58,11 +63,54 @@ class QUIC_EXPORT_PRIVATE QuicWriteBlockedList {
}
}
- return priority_write_scheduler_.ShouldYield(id);
+ return priority_write_scheduler_->ShouldYield(id);
}
- // Pops the highest priorty stream, special casing crypto and headers streams.
- // Latches the most recently popped data stream for batch writing purposes.
+ // Switches write scheduler. This can only be called before any stream is
+ // registered.
+ bool SwitchWriteScheduler(spdy::WriteSchedulerType type,
+ QuicTransportVersion version) {
+ if (scheduler_type_ == type) {
+ return true;
+ }
+ if (priority_write_scheduler_->NumRegisteredStreams() != 0) {
+ QUIC_BUG << "Cannot switch scheduler with registered streams";
+ return false;
+ }
+ QUIC_DVLOG(1) << "Switching to scheduler type: "
+ << spdy::WriteSchedulerTypeToString(type);
+ switch (type) {
+ case spdy::WriteSchedulerType::LIFO:
+ priority_write_scheduler_ =
+ QuicMakeUnique<spdy::LifoWriteScheduler<QuicStreamId>>();
+ break;
+ case spdy::WriteSchedulerType::SPDY:
+ priority_write_scheduler_ =
+ QuicMakeUnique<spdy::PriorityWriteScheduler<QuicStreamId>>(
+ QuicVersionUsesCryptoFrames(version)
+ ? std::numeric_limits<QuicStreamId>::max()
+ : 0);
+ break;
+ case spdy::WriteSchedulerType::HTTP2:
+ priority_write_scheduler_ =
+ QuicMakeUnique<spdy::Http2PriorityWriteScheduler<QuicStreamId>>();
+ break;
+ case spdy::WriteSchedulerType::FIFO:
+ priority_write_scheduler_ =
+ QuicMakeUnique<spdy::FifoWriteScheduler<QuicStreamId>>();
+ break;
+ default:
+ QUIC_BUG << "Scheduler is not supported for type: "
+ << spdy::WriteSchedulerTypeToString(type);
+ return false;
+ }
+ scheduler_type_ = type;
+ return true;
+ }
+
+ // Pops the highest priority stream, special casing crypto and headers
+ // streams. Latches the most recently popped data stream for batch writing
+ // purposes.
QuicStreamId PopFront() {
QuicStreamId static_stream_id;
if (static_stream_collection_.UnblockFirstBlocked(&static_stream_id)) {
@@ -70,12 +118,16 @@ class QUIC_EXPORT_PRIVATE QuicWriteBlockedList {
}
const auto id_and_precedence =
- priority_write_scheduler_.PopNextReadyStreamAndPrecedence();
+ priority_write_scheduler_->PopNextReadyStreamAndPrecedence();
const QuicStreamId id = std::get<0>(id_and_precedence);
+ if (scheduler_type_ != spdy::WriteSchedulerType::SPDY) {
+ // No batch writing logic for non-SPDY priority write scheduler.
+ return id;
+ }
const spdy::SpdyPriority priority =
std::get<1>(id_and_precedence).spdy3_priority();
- if (!priority_write_scheduler_.HasReadyStreams()) {
+ if (!priority_write_scheduler_->HasReadyStreams()) {
// If no streams are blocked, don't bother latching. This stream will be
// the first popped for its priority anyway.
batch_write_stream_id_[priority] = 0;
@@ -92,15 +144,15 @@ class QUIC_EXPORT_PRIVATE QuicWriteBlockedList {
void RegisterStream(QuicStreamId stream_id,
bool is_static_stream,
- spdy::SpdyPriority priority) {
- DCHECK(!priority_write_scheduler_.StreamRegistered(stream_id));
+ const spdy::SpdyStreamPrecedence& precedence) {
+ DCHECK(!priority_write_scheduler_->StreamRegistered(stream_id) &&
+ PrecedenceMatchesSchedulerType(precedence));
if (is_static_stream) {
static_stream_collection_.Register(stream_id);
return;
}
- priority_write_scheduler_.RegisterStream(
- stream_id, spdy::SpdyStreamPrecedence(priority));
+ priority_write_scheduler_->RegisterStream(stream_id, precedence);
}
void UnregisterStream(QuicStreamId stream_id, bool is_static) {
@@ -108,17 +160,21 @@ class QUIC_EXPORT_PRIVATE QuicWriteBlockedList {
static_stream_collection_.Unregister(stream_id);
return;
}
- priority_write_scheduler_.UnregisterStream(stream_id);
+ priority_write_scheduler_->UnregisterStream(stream_id);
}
void UpdateStreamPriority(QuicStreamId stream_id,
- spdy::SpdyPriority new_priority) {
- DCHECK(!static_stream_collection_.IsRegistered(stream_id));
- priority_write_scheduler_.UpdateStreamPrecedence(
- stream_id, spdy::SpdyStreamPrecedence(new_priority));
+ const spdy::SpdyStreamPrecedence& new_precedence) {
+ DCHECK(!static_stream_collection_.IsRegistered(stream_id) &&
+ PrecedenceMatchesSchedulerType(new_precedence));
+ priority_write_scheduler_->UpdateStreamPrecedence(stream_id,
+ new_precedence);
}
void UpdateBytesForStream(QuicStreamId stream_id, size_t bytes) {
+ if (scheduler_type_ != spdy::WriteSchedulerType::SPDY) {
+ return;
+ }
if (batch_write_stream_id_[last_priority_popped_] == stream_id) {
// If this was the last data stream popped by PopFront, update the
// bytes remaining in its batch write.
@@ -137,9 +193,10 @@ class QUIC_EXPORT_PRIVATE QuicWriteBlockedList {
}
bool push_front =
+ scheduler_type_ == spdy::WriteSchedulerType::SPDY &&
stream_id == batch_write_stream_id_[last_priority_popped_] &&
bytes_left_for_batch_write_[last_priority_popped_] > 0;
- priority_write_scheduler_.MarkStreamReady(stream_id, push_front);
+ priority_write_scheduler_->MarkStreamReady(stream_id, push_front);
}
// Returns true if stream with |stream_id| is write blocked.
@@ -150,11 +207,29 @@ class QUIC_EXPORT_PRIVATE QuicWriteBlockedList {
}
}
- return priority_write_scheduler_.IsStreamReady(stream_id);
+ return priority_write_scheduler_->IsStreamReady(stream_id);
}
private:
- QuicPriorityWriteScheduler priority_write_scheduler_;
+ bool PrecedenceMatchesSchedulerType(
+ const spdy::SpdyStreamPrecedence& precedence) {
+ switch (scheduler_type_) {
+ case spdy::WriteSchedulerType::LIFO:
+ break;
+ case spdy::WriteSchedulerType::SPDY:
+ return precedence.is_spdy3_priority();
+ case spdy::WriteSchedulerType::HTTP2:
+ return !precedence.is_spdy3_priority();
+ case spdy::WriteSchedulerType::FIFO:
+ break;
+ default:
+ DCHECK(false);
+ return false;
+ }
+ return true;
+ }
+
+ std::unique_ptr<QuicPriorityWriteScheduler> priority_write_scheduler_;
// If performing batch writes, this will be the stream ID of the stream doing
// batch writes for this priority level. We will allow this stream to write
@@ -254,6 +329,8 @@ class QUIC_EXPORT_PRIVATE QuicWriteBlockedList {
};
StaticStreamCollection static_stream_collection_;
+
+ spdy::WriteSchedulerType scheduler_type_;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list_test.cc
index 30bb08ef010..5d4b6397232 100644
--- a/chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list_test.cc
@@ -7,6 +7,7 @@
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
+using spdy::kHttp2DefaultStreamWeight;
using spdy::kV3HighestPriority;
using spdy::kV3LowestPriority;
@@ -14,23 +15,70 @@ namespace quic {
namespace test {
namespace {
-class QuicWriteBlockedListTest : public QuicTest {
+const bool kExclusiveBit = true;
+
+class QuicWriteBlockedListTest : public QuicTestWithParam<bool> {
public:
QuicWriteBlockedListTest()
- : write_blocked_list_(AllSupportedVersions()[0].transport_version) {}
+ : write_blocked_list_(AllSupportedVersions()[0].transport_version) {
+ if (GetParam()) {
+ write_blocked_list_.SwitchWriteScheduler(
+ spdy::WriteSchedulerType::HTTP2,
+ AllSupportedVersions()[0].transport_version);
+ }
+ }
protected:
QuicWriteBlockedList write_blocked_list_;
};
-TEST_F(QuicWriteBlockedListTest, PriorityOrder) {
- // Mark streams blocked in roughly reverse priority order, and
- // verify that streams are sorted.
- write_blocked_list_.RegisterStream(40, false, kV3LowestPriority);
- write_blocked_list_.RegisterStream(23, false, kV3HighestPriority);
- write_blocked_list_.RegisterStream(17, false, kV3HighestPriority);
- write_blocked_list_.RegisterStream(1, true, kV3HighestPriority);
- write_blocked_list_.RegisterStream(3, true, kV3HighestPriority);
+INSTANTIATE_TEST_SUITE_P(Tests, QuicWriteBlockedListTest, testing::Bool());
+
+TEST_P(QuicWriteBlockedListTest, PriorityOrder) {
+ if (GetParam()) {
+ /*
+ 0
+ |
+ 23
+ |
+ 17
+ |
+ 40
+ */
+ write_blocked_list_.RegisterStream(
+ 17, false,
+ spdy::SpdyStreamPrecedence(0, kHttp2DefaultStreamWeight,
+ kExclusiveBit));
+ write_blocked_list_.RegisterStream(
+ 40, false,
+ spdy::SpdyStreamPrecedence(17, kHttp2DefaultStreamWeight,
+ kExclusiveBit));
+ write_blocked_list_.RegisterStream(
+ 23, false,
+ spdy::SpdyStreamPrecedence(0, kHttp2DefaultStreamWeight,
+ kExclusiveBit));
+ write_blocked_list_.RegisterStream(
+ 1, true,
+ spdy::SpdyStreamPrecedence(0, kHttp2DefaultStreamWeight,
+ kExclusiveBit));
+ write_blocked_list_.RegisterStream(
+ 3, true,
+ spdy::SpdyStreamPrecedence(0, kHttp2DefaultStreamWeight,
+ kExclusiveBit));
+ } else {
+ // Mark streams blocked in roughly reverse priority order, and
+ // verify that streams are sorted.
+ write_blocked_list_.RegisterStream(
+ 40, false, spdy::SpdyStreamPrecedence(kV3LowestPriority));
+ write_blocked_list_.RegisterStream(
+ 23, false, spdy::SpdyStreamPrecedence(kV3HighestPriority));
+ write_blocked_list_.RegisterStream(
+ 17, false, spdy::SpdyStreamPrecedence(kV3HighestPriority));
+ write_blocked_list_.RegisterStream(
+ 1, true, spdy::SpdyStreamPrecedence(kV3HighestPriority));
+ write_blocked_list_.RegisterStream(
+ 3, true, spdy::SpdyStreamPrecedence(kV3HighestPriority));
+ }
write_blocked_list_.AddStream(40);
EXPECT_TRUE(write_blocked_list_.IsStreamBlocked(40));
@@ -69,8 +117,16 @@ TEST_F(QuicWriteBlockedListTest, PriorityOrder) {
EXPECT_FALSE(write_blocked_list_.HasWriteBlockedDataStreams());
}
-TEST_F(QuicWriteBlockedListTest, CryptoStream) {
- write_blocked_list_.RegisterStream(1, true, kV3HighestPriority);
+TEST_P(QuicWriteBlockedListTest, CryptoStream) {
+ if (GetParam()) {
+ write_blocked_list_.RegisterStream(
+ 1, true,
+ spdy::SpdyStreamPrecedence(0, kHttp2DefaultStreamWeight,
+ kExclusiveBit));
+ } else {
+ write_blocked_list_.RegisterStream(
+ 1, true, spdy::SpdyStreamPrecedence(kV3HighestPriority));
+ }
write_blocked_list_.AddStream(1);
EXPECT_EQ(1u, write_blocked_list_.NumBlockedStreams());
@@ -80,8 +136,16 @@ TEST_F(QuicWriteBlockedListTest, CryptoStream) {
EXPECT_FALSE(write_blocked_list_.HasWriteBlockedSpecialStream());
}
-TEST_F(QuicWriteBlockedListTest, HeadersStream) {
- write_blocked_list_.RegisterStream(3, true, kV3HighestPriority);
+TEST_P(QuicWriteBlockedListTest, HeadersStream) {
+ if (GetParam()) {
+ write_blocked_list_.RegisterStream(
+ 3, true,
+ spdy::SpdyStreamPrecedence(0, kHttp2DefaultStreamWeight,
+ kExclusiveBit));
+ } else {
+ write_blocked_list_.RegisterStream(
+ 3, true, spdy::SpdyStreamPrecedence(kV3HighestPriority));
+ }
write_blocked_list_.AddStream(3);
EXPECT_EQ(1u, write_blocked_list_.NumBlockedStreams());
@@ -91,9 +155,22 @@ TEST_F(QuicWriteBlockedListTest, HeadersStream) {
EXPECT_FALSE(write_blocked_list_.HasWriteBlockedSpecialStream());
}
-TEST_F(QuicWriteBlockedListTest, VerifyHeadersStream) {
- write_blocked_list_.RegisterStream(5, false, kV3HighestPriority);
- write_blocked_list_.RegisterStream(3, true, kV3HighestPriority);
+TEST_P(QuicWriteBlockedListTest, VerifyHeadersStream) {
+ if (GetParam()) {
+ write_blocked_list_.RegisterStream(
+ 5, false,
+ spdy::SpdyStreamPrecedence(0, kHttp2DefaultStreamWeight,
+ kExclusiveBit));
+ write_blocked_list_.RegisterStream(
+ 3, true,
+ spdy::SpdyStreamPrecedence(0, kHttp2DefaultStreamWeight,
+ kExclusiveBit));
+ } else {
+ write_blocked_list_.RegisterStream(
+ 5, false, spdy::SpdyStreamPrecedence(kV3HighestPriority));
+ write_blocked_list_.RegisterStream(
+ 3, true, spdy::SpdyStreamPrecedence(kV3HighestPriority));
+ }
write_blocked_list_.AddStream(5);
write_blocked_list_.AddStream(3);
@@ -109,12 +186,20 @@ TEST_F(QuicWriteBlockedListTest, VerifyHeadersStream) {
EXPECT_FALSE(write_blocked_list_.HasWriteBlockedDataStreams());
}
-TEST_F(QuicWriteBlockedListTest, NoDuplicateEntries) {
+TEST_P(QuicWriteBlockedListTest, NoDuplicateEntries) {
// Test that QuicWriteBlockedList doesn't allow duplicate entries.
// Try to add a stream to the write blocked list multiple times at the same
// priority.
const QuicStreamId kBlockedId = 3 + 2;
- write_blocked_list_.RegisterStream(kBlockedId, false, kV3HighestPriority);
+ if (GetParam()) {
+ write_blocked_list_.RegisterStream(
+ kBlockedId, false,
+ spdy::SpdyStreamPrecedence(0, kHttp2DefaultStreamWeight,
+ kExclusiveBit));
+ } else {
+ write_blocked_list_.RegisterStream(
+ kBlockedId, false, spdy::SpdyStreamPrecedence(kV3HighestPriority));
+ }
write_blocked_list_.AddStream(kBlockedId);
write_blocked_list_.AddStream(kBlockedId);
write_blocked_list_.AddStream(kBlockedId);
@@ -129,13 +214,19 @@ TEST_F(QuicWriteBlockedListTest, NoDuplicateEntries) {
EXPECT_FALSE(write_blocked_list_.HasWriteBlockedDataStreams());
}
-TEST_F(QuicWriteBlockedListTest, BatchingWrites) {
+TEST_P(QuicWriteBlockedListTest, BatchingWrites) {
+ if (GetParam()) {
+ return;
+ }
const QuicStreamId id1 = 3 + 2;
const QuicStreamId id2 = id1 + 2;
const QuicStreamId id3 = id2 + 2;
- write_blocked_list_.RegisterStream(id1, false, kV3LowestPriority);
- write_blocked_list_.RegisterStream(id2, false, kV3LowestPriority);
- write_blocked_list_.RegisterStream(id3, false, kV3HighestPriority);
+ write_blocked_list_.RegisterStream(
+ id1, false, spdy::SpdyStreamPrecedence(kV3LowestPriority));
+ write_blocked_list_.RegisterStream(
+ id2, false, spdy::SpdyStreamPrecedence(kV3LowestPriority));
+ write_blocked_list_.RegisterStream(
+ id3, false, spdy::SpdyStreamPrecedence(kV3HighestPriority));
write_blocked_list_.AddStream(id1);
write_blocked_list_.AddStream(id2);
@@ -179,14 +270,62 @@ TEST_F(QuicWriteBlockedListTest, BatchingWrites) {
EXPECT_EQ(id1, write_blocked_list_.PopFront());
}
-TEST_F(QuicWriteBlockedListTest, Ceding) {
- write_blocked_list_.RegisterStream(15, false, kV3HighestPriority);
- write_blocked_list_.RegisterStream(16, false, kV3HighestPriority);
- write_blocked_list_.RegisterStream(5, false, 5);
- write_blocked_list_.RegisterStream(4, false, 5);
- write_blocked_list_.RegisterStream(7, false, 7);
- write_blocked_list_.RegisterStream(1, true, kV3HighestPriority);
- write_blocked_list_.RegisterStream(3, true, kV3HighestPriority);
+TEST_P(QuicWriteBlockedListTest, Ceding) {
+ if (GetParam()) {
+ /*
+ 0
+ |
+ 15
+ |
+ 16
+ |
+ 5
+ |
+ 4
+ |
+ 7
+ */
+ write_blocked_list_.RegisterStream(
+ 15, false,
+ spdy::SpdyStreamPrecedence(0, kHttp2DefaultStreamWeight,
+ kExclusiveBit));
+ write_blocked_list_.RegisterStream(
+ 16, false,
+ spdy::SpdyStreamPrecedence(15, kHttp2DefaultStreamWeight,
+ kExclusiveBit));
+ write_blocked_list_.RegisterStream(
+ 4, false,
+ spdy::SpdyStreamPrecedence(16, kHttp2DefaultStreamWeight,
+ kExclusiveBit));
+ write_blocked_list_.RegisterStream(
+ 5, false,
+ spdy::SpdyStreamPrecedence(16, kHttp2DefaultStreamWeight,
+ kExclusiveBit));
+ write_blocked_list_.RegisterStream(
+ 7, false,
+ spdy::SpdyStreamPrecedence(4, kHttp2DefaultStreamWeight,
+ kExclusiveBit));
+ write_blocked_list_.RegisterStream(
+ 1, true,
+ spdy::SpdyStreamPrecedence(0, kHttp2DefaultStreamWeight,
+ kExclusiveBit));
+ write_blocked_list_.RegisterStream(
+ 3, true,
+ spdy::SpdyStreamPrecedence(0, kHttp2DefaultStreamWeight,
+ kExclusiveBit));
+ } else {
+ write_blocked_list_.RegisterStream(
+ 15, false, spdy::SpdyStreamPrecedence(kV3HighestPriority));
+ write_blocked_list_.RegisterStream(
+ 16, false, spdy::SpdyStreamPrecedence(kV3HighestPriority));
+ write_blocked_list_.RegisterStream(5, false, spdy::SpdyStreamPrecedence(5));
+ write_blocked_list_.RegisterStream(4, false, spdy::SpdyStreamPrecedence(5));
+ write_blocked_list_.RegisterStream(7, false, spdy::SpdyStreamPrecedence(7));
+ write_blocked_list_.RegisterStream(
+ 1, true, spdy::SpdyStreamPrecedence(kV3HighestPriority));
+ write_blocked_list_.RegisterStream(
+ 3, true, spdy::SpdyStreamPrecedence(kV3HighestPriority));
+ }
// When nothing is on the list, nothing yields.
EXPECT_FALSE(write_blocked_list_.ShouldYield(5));
@@ -224,6 +363,66 @@ TEST_F(QuicWriteBlockedListTest, Ceding) {
EXPECT_FALSE(write_blocked_list_.ShouldYield(1));
}
+TEST_P(QuicWriteBlockedListTest, UpdateStreamPriority) {
+ if (!GetParam()) {
+ return;
+ }
+ /*
+ 0
+ |
+ 5
+ |
+ 7
+ |
+ 9
+ |
+ 11
+ */
+ write_blocked_list_.RegisterStream(
+ 5, false,
+ spdy::SpdyStreamPrecedence(0, kHttp2DefaultStreamWeight, kExclusiveBit));
+ write_blocked_list_.RegisterStream(
+ 7, false,
+ spdy::SpdyStreamPrecedence(5, kHttp2DefaultStreamWeight, kExclusiveBit));
+ write_blocked_list_.RegisterStream(
+ 9, false,
+ spdy::SpdyStreamPrecedence(7, kHttp2DefaultStreamWeight, kExclusiveBit));
+ write_blocked_list_.RegisterStream(
+ 11, false,
+ spdy::SpdyStreamPrecedence(9, kHttp2DefaultStreamWeight, kExclusiveBit));
+
+ write_blocked_list_.AddStream(7);
+ EXPECT_FALSE(write_blocked_list_.ShouldYield(5));
+ EXPECT_TRUE(write_blocked_list_.ShouldYield(9));
+ EXPECT_TRUE(write_blocked_list_.ShouldYield(11));
+
+ // Update 9's priority.
+ if (GetParam()) {
+ /*
+ 0
+ |
+ 5
+ / \
+ 7 9
+ |
+ 11
+ */
+ write_blocked_list_.UpdateStreamPriority(
+ 9, spdy::SpdyStreamPrecedence(5, kHttp2DefaultStreamWeight,
+ kExclusiveBit));
+ } else {
+ write_blocked_list_.UpdateStreamPriority(9, spdy::SpdyStreamPrecedence(1));
+ }
+ EXPECT_FALSE(write_blocked_list_.ShouldYield(5));
+ // Verify 9 now does not yield to 7.
+ EXPECT_FALSE(write_blocked_list_.ShouldYield(9));
+ EXPECT_FALSE(write_blocked_list_.ShouldYield(11));
+
+ write_blocked_list_.AddStream(9);
+ // Verify 11 yield to 9.
+ EXPECT_TRUE(write_blocked_list_.ShouldYield(11));
+}
+
} // namespace
} // namespace test
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.cc b/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.cc
index d6fc038639e..bb456027469 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
@@ -76,30 +76,15 @@ bool TlsClientHandshaker::CryptoConnect() {
return false;
}
- std::string alpn_string = AlpnForVersion(session()->connection()->version());
- if (alpn_string.length() > std::numeric_limits<uint8_t>::max()) {
- QUIC_BUG << "ALPN too long: '" << alpn_string << "'";
- CloseConnection(QUIC_HANDSHAKE_FAILED, "ALPN too long");
+ if (!SetAlpn()) {
+ CloseConnection(QUIC_HANDSHAKE_FAILED, "Client failed to set ALPN");
return false;
}
- const uint8_t alpn_length = alpn_string.length();
- // SSL_set_alpn_protos expects a sequence of one-byte-length-prefixed strings
- // so we copy alpn_string to a new buffer that has the length in alpn[0].
- uint8_t alpn[std::numeric_limits<uint8_t>::max() + 1];
- alpn[0] = alpn_length;
- memcpy(reinterpret_cast<char*>(alpn + 1), alpn_string.data(), alpn_length);
- if (SSL_set_alpn_protos(ssl(), alpn,
- static_cast<unsigned>(alpn_length) + 1) != 0) {
- QUIC_BUG << "Failed to set ALPN: '" << alpn_string << "'";
- CloseConnection(QUIC_HANDSHAKE_FAILED, "Failed to set ALPN");
- return false;
- }
- QUIC_DLOG(INFO) << "Client using ALPN: '" << alpn_string << "'";
// Set the Transport Parameters to send in the ClientHello
if (!SetTransportParameters()) {
CloseConnection(QUIC_HANDSHAKE_FAILED,
- "Failed to set Transport Parameters");
+ "Client failed to set Transport Parameters");
return false;
}
@@ -108,6 +93,46 @@ bool TlsClientHandshaker::CryptoConnect() {
return session()->connection()->connected();
}
+static bool IsValidAlpn(const std::string& alpn_string) {
+ return alpn_string.length() <= std::numeric_limits<uint8_t>::max();
+}
+
+bool TlsClientHandshaker::SetAlpn() {
+ std::vector<std::string> alpns = session()->GetAlpnsToOffer();
+ if (alpns.empty()) {
+ if (allow_empty_alpn_for_tests_) {
+ return true;
+ }
+
+ QUIC_BUG << "ALPN missing";
+ return false;
+ }
+ if (!std::all_of(alpns.begin(), alpns.end(), IsValidAlpn)) {
+ QUIC_BUG << "ALPN too long";
+ return false;
+ }
+
+ // SSL_set_alpn_protos expects a sequence of one-byte-length-prefixed
+ // strings.
+ uint8_t alpn[1024];
+ QuicDataWriter alpn_writer(sizeof(alpn), reinterpret_cast<char*>(alpn));
+ bool success = true;
+ for (const std::string& alpn_string : alpns) {
+ success = success && alpn_writer.WriteUInt8(alpn_string.size()) &&
+ alpn_writer.WriteStringPiece(alpn_string);
+ }
+ success =
+ success && (SSL_set_alpn_protos(ssl(), alpn, alpn_writer.length()) == 0);
+ if (!success) {
+ QUIC_BUG << "Failed to set ALPN: "
+ << QuicTextUtils::HexDump(
+ QuicStringPiece(alpn_writer.data(), alpn_writer.length()));
+ return false;
+ }
+ QUIC_DLOG(INFO) << "Client using ALPN: '" << alpns[0] << "'";
+ return true;
+}
+
bool TlsClientHandshaker::SetTransportParameters() {
TransportParameters params;
params.perspective = Perspective::IS_CLIENT;
@@ -120,7 +145,8 @@ bool TlsClientHandshaker::SetTransportParameters() {
params.google_quic_params->SetStringPiece(kUAID, user_agent_id_);
std::vector<uint8_t> param_bytes;
- return SerializeTransportParameters(params, &param_bytes) &&
+ return SerializeTransportParameters(session()->connection()->version(),
+ params, &param_bytes) &&
SSL_set_quic_transport_params(ssl(), param_bytes.data(),
param_bytes.size()) == 1;
}
@@ -132,8 +158,9 @@ bool TlsClientHandshaker::ProcessTransportParameters(
size_t param_bytes_len;
SSL_get_peer_quic_transport_params(ssl(), &param_bytes, &param_bytes_len);
if (param_bytes_len == 0 ||
- !ParseTransportParameters(param_bytes, param_bytes_len,
- Perspective::IS_SERVER, &params)) {
+ !ParseTransportParameters(session()->connection()->version(),
+ Perspective::IS_SERVER, param_bytes,
+ param_bytes_len, &params)) {
*error_details = "Unable to parse Transport Parameters";
return false;
}
@@ -197,6 +224,11 @@ CryptoMessageParser* TlsClientHandshaker::crypto_message_parser() {
return TlsHandshaker::crypto_message_parser();
}
+size_t TlsClientHandshaker::BufferSizeLimitForLevel(
+ EncryptionLevel level) const {
+ return TlsHandshaker::BufferSizeLimitForLevel(level);
+}
+
void TlsClientHandshaker::AdvanceHandshake() {
if (state_ == STATE_CONNECTION_CLOSED) {
QUIC_LOG(INFO)
@@ -204,7 +236,8 @@ void TlsClientHandshaker::AdvanceHandshake() {
return;
}
if (state_ == STATE_IDLE) {
- CloseConnection(QUIC_HANDSHAKE_FAILED, "TLS handshake failed");
+ CloseConnection(QUIC_HANDSHAKE_FAILED,
+ "Client observed TLS handshake idle failure");
return;
}
if (state_ == STATE_HANDSHAKE_COMPLETE) {
@@ -234,7 +267,8 @@ void TlsClientHandshaker::AdvanceHandshake() {
// TODO(nharper): Surface error details from the error queue when ssl_error
// is SSL_ERROR_SSL.
QUIC_LOG(WARNING) << "SSL_do_handshake failed; closing connection";
- CloseConnection(QUIC_HANDSHAKE_FAILED, "TLS handshake failed");
+ CloseConnection(QUIC_HANDSHAKE_FAILED,
+ "Client observed TLS handshake failure");
}
}
@@ -259,29 +293,38 @@ void TlsClientHandshaker::FinishHandshake() {
const uint8_t* alpn_data = nullptr;
unsigned alpn_length = 0;
SSL_get0_alpn_selected(ssl(), &alpn_data, &alpn_length);
- // TODO(b/130164908) Act on ALPN.
- if (alpn_length != 0) {
- std::string received_alpn_string(reinterpret_cast<const char*>(alpn_data),
- alpn_length);
- std::string sent_alpn_string =
- AlpnForVersion(session()->connection()->version());
- if (received_alpn_string != sent_alpn_string) {
- QUIC_LOG(ERROR) << "Client: received mismatched ALPN '"
- << received_alpn_string << "', expected '"
- << sent_alpn_string << "'";
- CloseConnection(QUIC_HANDSHAKE_FAILED, "Mismatched ALPN");
- return;
- }
- QUIC_DLOG(INFO) << "Client: server selected ALPN: '" << received_alpn_string
- << "'";
- } else {
- QUIC_DLOG(INFO) << "Client: server did not select ALPN";
+
+ if (alpn_length == 0) {
+ QUIC_DLOG(ERROR) << "Client: server did not select ALPN";
+ // TODO(b/130164908) this should send no_application_protocol
+ // instead of QUIC_HANDSHAKE_FAILED.
+ CloseConnection(QUIC_HANDSHAKE_FAILED, "Server did not select ALPN");
+ return;
+ }
+
+ std::string received_alpn_string(reinterpret_cast<const char*>(alpn_data),
+ alpn_length);
+ std::vector<std::string> offered_alpns = session()->GetAlpnsToOffer();
+ if (std::find(offered_alpns.begin(), offered_alpns.end(),
+ received_alpn_string) == offered_alpns.end()) {
+ QUIC_LOG(ERROR) << "Client: received mismatched ALPN '"
+ << received_alpn_string;
+ // TODO(b/130164908) this should send no_application_protocol
+ // instead of QUIC_HANDSHAKE_FAILED.
+ CloseConnection(QUIC_HANDSHAKE_FAILED, "Client received mismatched ALPN");
+ return;
}
+ session()->OnAlpnSelected(received_alpn_string);
+ QUIC_DLOG(INFO) << "Client: server selected ALPN: '" << received_alpn_string
+ << "'";
session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
session()->NeuterUnencryptedData();
encryption_established_ = true;
handshake_confirmed_ = true;
+ session()->OnCryptoHandshakeEvent(QuicSession::ENCRYPTION_ESTABLISHED);
+ session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED);
+ session()->connection()->OnHandshakeComplete();
}
enum ssl_verify_result_t TlsClientHandshaker::VerifyCert(uint8_t* out_alert) {
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 c22fbe9e8cc..f3e90ce9410 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
@@ -52,9 +52,14 @@ class QUIC_EXPORT_PRIVATE TlsClientHandshaker
const QuicCryptoNegotiatedParameters& crypto_negotiated_params()
const override;
CryptoMessageParser* crypto_message_parser() override;
+ size_t BufferSizeLimitForLevel(EncryptionLevel level) const override;
+
+ void AllowEmptyAlpnForTests() { allow_empty_alpn_for_tests_ = true; }
protected:
- TlsConnection* tls_connection() override { return &tls_connection_; }
+ const TlsConnection* tls_connection() const override {
+ return &tls_connection_;
+ }
void AdvanceHandshake() override;
void CloseConnection(QuicErrorCode error,
@@ -92,6 +97,7 @@ class QUIC_EXPORT_PRIVATE TlsClientHandshaker
STATE_CONNECTION_CLOSED,
} state_ = STATE_IDLE;
+ bool SetAlpn();
bool SetTransportParameters();
bool ProcessTransportParameters(std::string* error_details);
void FinishHandshake();
@@ -118,6 +124,8 @@ class QUIC_EXPORT_PRIVATE TlsClientHandshaker
QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters>
crypto_negotiated_params_;
+ bool allow_empty_alpn_for_tests_ = false;
+
TlsClientConnection tls_connection_;
};
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 db50f5abf2e..e6e59fd7b5b 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
@@ -54,6 +54,11 @@ bool TlsHandshaker::ProcessInput(QuicStringPiece input, EncryptionLevel level) {
return true;
}
+size_t TlsHandshaker::BufferSizeLimitForLevel(EncryptionLevel level) const {
+ return SSL_quic_max_handshake_flight_len(
+ ssl(), TlsConnection::BoringEncryptionLevel(level));
+}
+
const EVP_MD* TlsHandshaker::Prf() {
return EVP_get_digestbynid(
SSL_CIPHER_get_prf_nid(SSL_get_pending_cipher(ssl())));
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 b4f16e8a3d1..7d5b9bcb75f 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
@@ -50,6 +50,7 @@ class QUIC_EXPORT_PRIVATE TlsHandshaker : public TlsConnection::Delegate,
virtual const QuicCryptoNegotiatedParameters& crypto_negotiated_params()
const = 0;
virtual CryptoMessageParser* crypto_message_parser() { return this; }
+ size_t BufferSizeLimitForLevel(EncryptionLevel level) const;
protected:
virtual void AdvanceHandshake() = 0;
@@ -65,9 +66,9 @@ class QUIC_EXPORT_PRIVATE TlsHandshaker : public TlsConnection::Delegate,
std::unique_ptr<QuicDecrypter> CreateDecrypter(
const std::vector<uint8_t>& pp_secret);
- virtual TlsConnection* tls_connection() = 0;
+ virtual const TlsConnection* tls_connection() const = 0;
- SSL* ssl() { return tls_connection()->ssl(); }
+ SSL* ssl() const { return tls_connection()->ssl(); }
QuicCryptoStream* stream() { return stream_; }
QuicSession* session() { return session_; }
diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_handshaker_test.cc b/chromium/net/third_party/quiche/src/quic/core/tls_handshaker_test.cc
index f15a2667210..a298089cdd3 100644
--- a/chromium/net/third_party/quiche/src/quic/core/tls_handshaker_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/tls_handshaker_test.cc
@@ -10,6 +10,7 @@
#include "net/third_party/quiche/src/quic/core/tls_client_handshaker.h"
#include "net/third_party/quiche/src/quic/core/tls_server_handshaker.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h"
@@ -22,6 +23,8 @@ namespace test {
namespace {
using ::testing::_;
+using ::testing::ElementsAreArray;
+using ::testing::Return;
class FakeProofVerifier : public ProofVerifier {
public:
@@ -225,6 +228,7 @@ class TestQuicCryptoClientStream : public TestQuicCryptoStream {
~TestQuicCryptoClientStream() override = default;
TlsHandshaker* handshaker() const override { return handshaker_.get(); }
+ TlsClientHandshaker* client_handshaker() const { return handshaker_.get(); }
bool CryptoConnect() { return handshaker_->CryptoConnect(); }
@@ -302,6 +306,15 @@ class TlsHandshakerTest : public QuicTest {
EXPECT_FALSE(client_stream_->handshake_confirmed());
EXPECT_FALSE(server_stream_->encryption_established());
EXPECT_FALSE(server_stream_->handshake_confirmed());
+ const std::string default_alpn =
+ AlpnForVersion(client_session_.connection()->version());
+ ON_CALL(client_session_, GetAlpnsToOffer())
+ .WillByDefault(Return(std::vector<std::string>({default_alpn})));
+ ON_CALL(server_session_, SelectAlpn(_))
+ .WillByDefault(
+ [default_alpn](const std::vector<QuicStringPiece>& alpns) {
+ return std::find(alpns.begin(), alpns.end(), default_alpn);
+ });
}
MockQuicConnectionHelper conn_helper_;
@@ -317,8 +330,17 @@ class TlsHandshakerTest : public QuicTest {
};
TEST_F(TlsHandshakerTest, CryptoHandshake) {
+ EXPECT_FALSE(client_conn_->IsHandshakeConfirmed());
+ EXPECT_FALSE(server_conn_->IsHandshakeConfirmed());
+
EXPECT_CALL(*client_conn_, CloseConnection(_, _, _)).Times(0);
EXPECT_CALL(*server_conn_, CloseConnection(_, _, _)).Times(0);
+ EXPECT_CALL(client_session_,
+ OnCryptoHandshakeEvent(QuicSession::ENCRYPTION_ESTABLISHED));
+ EXPECT_CALL(client_session_,
+ OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED));
+ EXPECT_CALL(server_session_,
+ OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED));
client_stream_->CryptoConnect();
ExchangeHandshakeMessages(client_stream_, server_stream_);
@@ -326,6 +348,8 @@ TEST_F(TlsHandshakerTest, CryptoHandshake) {
EXPECT_TRUE(client_stream_->encryption_established());
EXPECT_TRUE(server_stream_->handshake_confirmed());
EXPECT_TRUE(server_stream_->encryption_established());
+ EXPECT_TRUE(client_conn_->IsHandshakeConfirmed());
+ EXPECT_FALSE(server_conn_->IsHandshakeConfirmed());
}
TEST_F(TlsHandshakerTest, HandshakeWithAsyncProofSource) {
@@ -430,6 +454,111 @@ TEST_F(TlsHandshakerTest, ServerConnectionClosedOnTlsError) {
EXPECT_FALSE(server_stream_->handshake_confirmed());
}
+TEST_F(TlsHandshakerTest, ClientNotSendingALPN) {
+ client_stream_->client_handshaker()->AllowEmptyAlpnForTests();
+ EXPECT_CALL(client_session_, GetAlpnsToOffer())
+ .WillOnce(Return(std::vector<std::string>()));
+ EXPECT_CALL(*client_conn_, CloseConnection(QUIC_HANDSHAKE_FAILED,
+ "Server did not select ALPN", _));
+ EXPECT_CALL(*server_conn_,
+ CloseConnection(QUIC_HANDSHAKE_FAILED,
+ "Server did not receive a known ALPN", _));
+ client_stream_->CryptoConnect();
+ ExchangeHandshakeMessages(client_stream_, server_stream_);
+
+ EXPECT_FALSE(client_stream_->handshake_confirmed());
+ EXPECT_FALSE(client_stream_->encryption_established());
+ EXPECT_FALSE(server_stream_->handshake_confirmed());
+ EXPECT_FALSE(server_stream_->encryption_established());
+}
+
+TEST_F(TlsHandshakerTest, ClientSendingBadALPN) {
+ static std::string kTestBadClientAlpn = "bad-client-alpn";
+ EXPECT_CALL(client_session_, GetAlpnsToOffer())
+ .WillOnce(Return(std::vector<std::string>({kTestBadClientAlpn})));
+ EXPECT_CALL(*client_conn_, CloseConnection(QUIC_HANDSHAKE_FAILED,
+ "Server did not select ALPN", _));
+ EXPECT_CALL(*server_conn_,
+ CloseConnection(QUIC_HANDSHAKE_FAILED,
+ "Server did not receive a known ALPN", _));
+ client_stream_->CryptoConnect();
+ ExchangeHandshakeMessages(client_stream_, server_stream_);
+
+ EXPECT_FALSE(client_stream_->handshake_confirmed());
+ EXPECT_FALSE(client_stream_->encryption_established());
+ EXPECT_FALSE(server_stream_->handshake_confirmed());
+ EXPECT_FALSE(server_stream_->encryption_established());
+}
+
+TEST_F(TlsHandshakerTest, ClientSendingTooManyALPNs) {
+ std::string long_alpn(250, 'A');
+ EXPECT_CALL(client_session_, GetAlpnsToOffer())
+ .WillOnce(Return(std::vector<std::string>({
+ long_alpn + "1",
+ long_alpn + "2",
+ long_alpn + "3",
+ long_alpn + "4",
+ long_alpn + "5",
+ long_alpn + "6",
+ long_alpn + "7",
+ long_alpn + "8",
+ })));
+ EXPECT_QUIC_BUG(client_stream_->CryptoConnect(), "Failed to set ALPN");
+}
+
+TEST_F(TlsHandshakerTest, ServerRequiresCustomALPN) {
+ static const std::string kTestAlpn = "An ALPN That Client Did Not Offer";
+ EXPECT_CALL(server_session_, SelectAlpn(_))
+ .WillOnce([](const std::vector<QuicStringPiece>& alpns) {
+ return std::find(alpns.cbegin(), alpns.cend(), kTestAlpn);
+ });
+ EXPECT_CALL(*client_conn_, CloseConnection(QUIC_HANDSHAKE_FAILED,
+ "Server did not select ALPN", _));
+ EXPECT_CALL(*server_conn_,
+ CloseConnection(QUIC_HANDSHAKE_FAILED,
+ "Server did not receive a known ALPN", _));
+ client_stream_->CryptoConnect();
+ ExchangeHandshakeMessages(client_stream_, server_stream_);
+
+ EXPECT_FALSE(client_stream_->handshake_confirmed());
+ EXPECT_FALSE(client_stream_->encryption_established());
+ EXPECT_FALSE(server_stream_->handshake_confirmed());
+ EXPECT_FALSE(server_stream_->encryption_established());
+}
+
+TEST_F(TlsHandshakerTest, CustomALPNNegotiation) {
+ EXPECT_CALL(*client_conn_, CloseConnection(_, _, _)).Times(0);
+ EXPECT_CALL(*server_conn_, CloseConnection(_, _, _)).Times(0);
+ EXPECT_CALL(client_session_,
+ OnCryptoHandshakeEvent(QuicSession::ENCRYPTION_ESTABLISHED));
+ EXPECT_CALL(client_session_,
+ OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED));
+ EXPECT_CALL(server_session_,
+ OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED));
+
+ static const std::string kTestAlpn = "A Custom ALPN Value";
+ static const std::vector<std::string> kTestAlpns(
+ {"foo", "bar", kTestAlpn, "something else"});
+ EXPECT_CALL(client_session_, GetAlpnsToOffer())
+ .WillRepeatedly(Return(kTestAlpns));
+ EXPECT_CALL(server_session_, SelectAlpn(_))
+ .WillOnce([](const std::vector<QuicStringPiece>& alpns) {
+ EXPECT_THAT(alpns, ElementsAreArray(kTestAlpns));
+ return std::find(alpns.cbegin(), alpns.cend(), kTestAlpn);
+ });
+ EXPECT_CALL(client_session_, OnAlpnSelected(QuicStringPiece(kTestAlpn)));
+ EXPECT_CALL(server_session_, OnAlpnSelected(QuicStringPiece(kTestAlpn)));
+ client_stream_->CryptoConnect();
+ ExchangeHandshakeMessages(client_stream_, server_stream_);
+
+ EXPECT_TRUE(client_stream_->handshake_confirmed());
+ EXPECT_TRUE(client_stream_->encryption_established());
+ EXPECT_TRUE(server_stream_->handshake_confirmed());
+ EXPECT_TRUE(server_stream_->encryption_established());
+ EXPECT_TRUE(client_conn_->IsHandshakeConfirmed());
+ EXPECT_FALSE(server_conn_->IsHandshakeConfirmed());
+}
+
} // namespace
} // namespace test
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.cc b/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.cc
index 81721041847..0b4215d3b04 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
@@ -61,7 +61,7 @@ TlsServerHandshaker::TlsServerHandshaker(QuicCryptoStream* stream,
if (!SetTransportParameters()) {
CloseConnection(QUIC_HANDSHAKE_FAILED,
- "Failed to set Transport Parameters");
+ "Server failed to set Transport Parameters");
}
}
@@ -136,6 +136,11 @@ CryptoMessageParser* TlsServerHandshaker::crypto_message_parser() {
return TlsHandshaker::crypto_message_parser();
}
+size_t TlsServerHandshaker::BufferSizeLimitForLevel(
+ EncryptionLevel level) const {
+ return TlsHandshaker::BufferSizeLimitForLevel(level);
+}
+
void TlsServerHandshaker::AdvanceHandshake() {
if (state_ == STATE_CONNECTION_CLOSED) {
QUIC_LOG(INFO) << "TlsServerHandshaker received handshake message after "
@@ -170,7 +175,8 @@ void TlsServerHandshaker::AdvanceHandshake() {
QUIC_LOG(WARNING) << "SSL_do_handshake failed; SSL_get_error returns "
<< ssl_error << ", state_ = " << state_;
ERR_print_errors_fp(stderr);
- CloseConnection(QUIC_HANDSHAKE_FAILED, "TLS handshake failed");
+ CloseConnection(QUIC_HANDSHAKE_FAILED,
+ "Server observed TLS handshake failure");
}
}
@@ -188,8 +194,9 @@ bool TlsServerHandshaker::ProcessTransportParameters(
SSL_get_peer_quic_transport_params(ssl(), &client_params_bytes,
&params_bytes_len);
if (params_bytes_len == 0 ||
- !ParseTransportParameters(client_params_bytes, params_bytes_len,
- Perspective::IS_CLIENT, &client_params)) {
+ !ParseTransportParameters(session()->connection()->version(),
+ Perspective::IS_CLIENT, client_params_bytes,
+ params_bytes_len, &client_params)) {
*error_details = "Unable to parse Transport Parameters";
return false;
}
@@ -228,7 +235,8 @@ bool TlsServerHandshaker::SetTransportParameters() {
// TODO(nharper): Provide an actual value for the stateless reset token.
server_params.stateless_reset_token.resize(16);
std::vector<uint8_t> server_params_bytes;
- if (!SerializeTransportParameters(server_params, &server_params_bytes) ||
+ if (!SerializeTransportParameters(session()->connection()->version(),
+ server_params, &server_params_bytes) ||
SSL_set_quic_transport_params(ssl(), server_params_bytes.data(),
server_params_bytes.size()) != 1) {
return false;
@@ -237,6 +245,16 @@ bool TlsServerHandshaker::SetTransportParameters() {
}
void TlsServerHandshaker::FinishHandshake() {
+ if (!valid_alpn_received_) {
+ QUIC_DLOG(ERROR)
+ << "Server: handshake finished without receiving a known ALPN";
+ // TODO(b/130164908) this should send no_application_protocol
+ // instead of QUIC_HANDSHAKE_FAILED.
+ CloseConnection(QUIC_HANDSHAKE_FAILED,
+ "Server did not receive a known ALPN");
+ return;
+ }
+
QUIC_LOG(INFO) << "Server: handshake finished";
state_ = STATE_HANDSHAKE_COMPLETE;
@@ -244,6 +262,7 @@ void TlsServerHandshaker::FinishHandshake() {
session()->NeuterUnencryptedData();
encryption_established_ = true;
handshake_confirmed_ = true;
+ session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED);
}
ssl_private_key_result_t TlsServerHandshaker::PrivateKeySign(
@@ -326,25 +345,44 @@ int TlsServerHandshaker::SelectAlpn(const uint8_t** out,
const uint8_t* in,
unsigned in_len) {
// |in| contains a sequence of 1-byte-length-prefixed values.
- // We currently simply return the first provided ALPN value.
- // TODO(b/130164908) Act on ALPN.
+ *out_len = 0;
+ *out = nullptr;
if (in_len == 0) {
- *out_len = 0;
- *out = nullptr;
- QUIC_DLOG(INFO) << "No ALPN provided";
- return SSL_TLSEXT_ERR_OK;
+ QUIC_DLOG(ERROR) << "No ALPN provided by client";
+ return SSL_TLSEXT_ERR_NOACK;
}
- const uint8_t first_alpn_length = in[0];
- if (static_cast<unsigned>(first_alpn_length) > in_len - 1) {
- QUIC_LOG(ERROR) << "Failed to parse ALPN";
- return SSL_TLSEXT_ERR_ALERT_FATAL;
+
+ CBS all_alpns;
+ CBS_init(&all_alpns, in, in_len);
+
+ std::vector<QuicStringPiece> alpns;
+ while (CBS_len(&all_alpns) > 0) {
+ CBS alpn;
+ if (!CBS_get_u8_length_prefixed(&all_alpns, &alpn)) {
+ QUIC_DLOG(ERROR) << "Failed to parse ALPN length";
+ return SSL_TLSEXT_ERR_NOACK;
+ }
+
+ const size_t alpn_length = CBS_len(&alpn);
+ if (alpn_length == 0) {
+ QUIC_DLOG(ERROR) << "Received invalid zero-length ALPN";
+ return SSL_TLSEXT_ERR_NOACK;
+ }
+
+ alpns.emplace_back(reinterpret_cast<const char*>(CBS_data(&alpn)),
+ alpn_length);
}
- *out_len = first_alpn_length;
- *out = in + 1;
- QUIC_DLOG(INFO) << "Server selecting ALPN '"
- << QuicStringPiece(reinterpret_cast<const char*>(*out),
- *out_len)
- << "'";
+
+ auto selected_alpn = session()->SelectAlpn(alpns);
+ if (selected_alpn == alpns.end()) {
+ QUIC_DLOG(ERROR) << "No known ALPN provided by client";
+ return SSL_TLSEXT_ERR_NOACK;
+ }
+
+ session()->OnAlpnSelected(*selected_alpn);
+ valid_alpn_received_ = true;
+ *out_len = selected_alpn->size();
+ *out = reinterpret_cast<const uint8_t*>(selected_alpn->data());
return SSL_TLSEXT_ERR_OK;
}
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 71fe6dd0276..829aeaf618b 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
@@ -58,9 +58,12 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker
const QuicCryptoNegotiatedParameters& crypto_negotiated_params()
const override;
CryptoMessageParser* crypto_message_parser() override;
+ size_t BufferSizeLimitForLevel(EncryptionLevel level) const override;
protected:
- TlsConnection* tls_connection() override { return &tls_connection_; }
+ const TlsConnection* tls_connection() const override {
+ return &tls_connection_;
+ }
// Called when a new message is received on the crypto stream and is available
// for the TLS stack to read.
@@ -123,6 +126,7 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker
bool encryption_established_ = false;
bool handshake_confirmed_ = false;
+ bool valid_alpn_received_ = false;
QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters>
crypto_negotiated_params_;
TlsServerConnection tls_connection_;
diff --git a/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.cc b/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.cc
index 24c3b7cc62f..a2b3b7a6abc 100644
--- a/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.cc
@@ -24,40 +24,7 @@ UberQuicStreamIdManager::UberQuicStreamIdManager(
/*unidirectional=*/true,
max_open_outgoing_unidirectional_streams,
max_open_incoming_unidirectional_streams) {}
-void UberQuicStreamIdManager::RegisterStaticStream(
- QuicStreamId id,
- bool stream_already_counted) {
- if (QuicUtils::IsBidirectionalStreamId(id)) {
- bidirectional_stream_id_manager_.RegisterStaticStream(
- id, stream_already_counted);
- return;
- }
- unidirectional_stream_id_manager_.RegisterStaticStream(
- id, stream_already_counted);
-}
-
-void UberQuicStreamIdManager::AdjustMaxOpenOutgoingUnidirectionalStreams(
- size_t max_streams) {
- unidirectional_stream_id_manager_.AdjustMaxOpenOutgoingStreams(max_streams);
-}
-void UberQuicStreamIdManager::AdjustMaxOpenOutgoingBidirectionalStreams(
- size_t max_streams) {
- bidirectional_stream_id_manager_.AdjustMaxOpenOutgoingStreams(max_streams);
-}
-
-void UberQuicStreamIdManager::ConfigureMaxOpenOutgoingBidirectionalStreams(
- size_t max_streams) {
- bidirectional_stream_id_manager_.ConfigureMaxOpenOutgoingStreams(max_streams);
-}
-void UberQuicStreamIdManager::ConfigureMaxOpenOutgoingUnidirectionalStreams(
- size_t max_streams) {
- unidirectional_stream_id_manager_.ConfigureMaxOpenOutgoingStreams(
- max_streams);
-}
-// TODO(fkastenholz): SetMax is cognizant of the number of static streams and
-// sets the maximum to be max_streams + number_of_statics. This should
-// eventually be removed from IETF QUIC.
void UberQuicStreamIdManager::SetMaxOpenOutgoingBidirectionalStreams(
size_t max_open_streams) {
bidirectional_stream_id_manager_.SetMaxOpenOutgoingStreams(max_open_streams);
diff --git a/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.h b/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.h
index 45b0d33ff46..61eaf62373b 100644
--- a/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.h
+++ b/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.h
@@ -27,35 +27,12 @@ class QUIC_EXPORT_PRIVATE UberQuicStreamIdManager {
QuicStreamCount max_open_incoming_bidirectional_streams,
QuicStreamCount max_open_incoming_unidirectional_streams);
- // Called when a stream with |stream_id| is registered as a static stream.
- // If |stream_already_counted| is true, the static stream is already counted
- // as an open stream earlier, so no need to count it again.
- void RegisterStaticStream(QuicStreamId id, bool stream_already_counted);
-
- // Sets the maximum outgoing stream count as a result of doing the transport
- // configuration negotiation. Forces the limit to max_streams, regardless of
- // static streams.
- void ConfigureMaxOpenOutgoingBidirectionalStreams(size_t max_streams);
- void ConfigureMaxOpenOutgoingUnidirectionalStreams(size_t max_streams);
-
- // Sets the limits to max_open_streams + number of static streams
- // in existence. SetMaxOpenOutgoingStreams will QUIC_BUG if it is called
- // after getting the first MAX_STREAMS frame or the transport configuration
- // was done.
- // TODO(fkastenholz): SetMax is cognizant of the number of static streams and
- // sets the maximum to be max_streams + number_of_statics. This should
- // eventually be removed from IETF QUIC.
+ // Sets the limits to max_open_streams.
void SetMaxOpenOutgoingBidirectionalStreams(size_t max_open_streams);
void SetMaxOpenOutgoingUnidirectionalStreams(size_t max_open_streams);
void SetMaxOpenIncomingBidirectionalStreams(size_t max_open_streams);
void SetMaxOpenIncomingUnidirectionalStreams(size_t max_open_streams);
- // Sets the outgoing stream count to the number of static streams + max
- // outgoing streams. Unlike SetMaxOpenOutgoingStreams, this method will
- // not QUIC_BUG if called after getting the first MAX_STREAMS frame.
- void AdjustMaxOpenOutgoingBidirectionalStreams(size_t max_streams);
- void AdjustMaxOpenOutgoingUnidirectionalStreams(size_t max_streams);
-
// Returns true if next outgoing bidirectional stream ID can be allocated.
bool CanOpenNextOutgoingBidirectionalStream();
diff --git a/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager_test.cc
index 203dbb801f5..6f5d34e4efd 100644
--- a/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager_test.cc
@@ -123,38 +123,6 @@ TEST_P(UberQuicStreamIdManagerTest, Initialization) {
}
}
-TEST_P(UberQuicStreamIdManagerTest, RegisterStaticStream) {
- QuicStreamId first_incoming_bidirectional_stream_id =
- GetParam() == Perspective::IS_SERVER
- ? GetNthClientInitiatedBidirectionalId(0)
- : GetNthServerInitiatedBidirectionalId(0);
- QuicStreamId first_incoming_unidirectional_stream_id =
- GetParam() == Perspective::IS_SERVER
- ? GetNthClientInitiatedUnidirectionalId(0)
- : GetNthServerInitiatedUnidirectionalId(0);
-
- QuicStreamCount actual_max_allowed_incoming_bidirectional_streams =
- manager_->actual_max_allowed_incoming_bidirectional_streams();
- QuicStreamCount actual_max_allowed_incoming_unidirectional_streams =
- manager_->actual_max_allowed_incoming_unidirectional_streams();
- manager_->RegisterStaticStream(first_incoming_bidirectional_stream_id,
- /*stream_already_counted = */ false);
- // Verify actual_max_allowed_incoming_bidirectional_streams increases.
- EXPECT_EQ(actual_max_allowed_incoming_bidirectional_streams + 1u,
- manager_->actual_max_allowed_incoming_bidirectional_streams());
- // Verify actual_max_allowed_incoming_unidirectional_streams does not
- // change.
- EXPECT_EQ(actual_max_allowed_incoming_unidirectional_streams,
- manager_->actual_max_allowed_incoming_unidirectional_streams());
-
- manager_->RegisterStaticStream(first_incoming_unidirectional_stream_id,
- /*stream_already_counted = */ false);
- EXPECT_EQ(actual_max_allowed_incoming_bidirectional_streams + 1u,
- manager_->actual_max_allowed_incoming_bidirectional_streams());
- EXPECT_EQ(actual_max_allowed_incoming_unidirectional_streams + 1u,
- manager_->actual_max_allowed_incoming_unidirectional_streams());
-}
-
TEST_P(UberQuicStreamIdManagerTest, SetMaxOpenOutgoingStreams) {
const size_t kNumMaxOutgoingStream = 123;
// Set the uni- and bi- directional limits to different values to ensure
diff --git a/chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager.cc b/chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager.cc
index 6df7490a85a..78cf35919d1 100644
--- a/chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager.cc
@@ -4,6 +4,7 @@
#include "net/third_party/quiche/src/quic/core/uber_received_packet_manager.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/core/quic_utils.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
@@ -77,19 +78,18 @@ void UberReceivedPacketManager::MaybeUpdateAckTimeout(
QuicPacketNumber last_received_packet_number,
QuicTime time_of_last_received_packet,
QuicTime now,
- const RttStats* rtt_stats,
- QuicTime::Delta local_max_ack_delay) {
+ const RttStats* rtt_stats) {
if (!supports_multiple_packet_number_spaces_) {
received_packet_managers_[0].MaybeUpdateAckTimeout(
should_last_packet_instigate_acks, last_received_packet_number,
- time_of_last_received_packet, now, rtt_stats, local_max_ack_delay);
+ time_of_last_received_packet, now, rtt_stats);
return;
}
received_packet_managers_[QuicUtils::GetPacketNumberSpace(
decrypted_packet_level)]
- .MaybeUpdateAckTimeout(
- should_last_packet_instigate_acks, last_received_packet_number,
- time_of_last_received_packet, now, rtt_stats, local_max_ack_delay);
+ .MaybeUpdateAckTimeout(should_last_packet_instigate_acks,
+ last_received_packet_number,
+ time_of_last_received_packet, now, rtt_stats);
}
void UberReceivedPacketManager::ResetAckStates(
@@ -112,6 +112,12 @@ void UberReceivedPacketManager::EnableMultiplePacketNumberSpacesSupport() {
"packet has been received.";
return;
}
+ // In IETF QUIC, the peer is expected to acknowledge packets in Initial and
+ // Handshake packets with minimal delay.
+ received_packet_managers_[INITIAL_DATA].set_local_max_ack_delay(
+ QuicTime::Delta::FromMilliseconds(1));
+ received_packet_managers_[HANDSHAKE_DATA].set_local_max_ack_delay(
+ QuicTime::Delta::FromMilliseconds(1));
supports_multiple_packet_number_spaces_ = true;
}
@@ -207,6 +213,23 @@ void UberReceivedPacketManager::set_max_ack_ranges(size_t max_ack_ranges) {
}
}
+QuicTime::Delta UberReceivedPacketManager::max_ack_delay() {
+ if (!supports_multiple_packet_number_spaces_) {
+ return received_packet_managers_[0].local_max_ack_delay();
+ }
+ return received_packet_managers_[APPLICATION_DATA].local_max_ack_delay();
+}
+
+void UberReceivedPacketManager::set_max_ack_delay(
+ QuicTime::Delta max_ack_delay) {
+ if (!supports_multiple_packet_number_spaces_) {
+ received_packet_managers_[0].set_local_max_ack_delay(max_ack_delay);
+ return;
+ }
+ received_packet_managers_[APPLICATION_DATA].set_local_max_ack_delay(
+ max_ack_delay);
+}
+
void UberReceivedPacketManager::set_save_timestamps(bool save_timestamps) {
for (auto& received_packet_manager : received_packet_managers_) {
received_packet_manager.set_save_timestamps(save_timestamps);
diff --git a/chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager.h b/chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager.h
index c4428041465..14ba8684f5a 100644
--- a/chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager.h
+++ b/chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager.h
@@ -48,8 +48,7 @@ class QUIC_EXPORT_PRIVATE UberReceivedPacketManager {
QuicPacketNumber last_received_packet_number,
QuicTime time_of_last_received_packet,
QuicTime now,
- const RttStats* rtt_stats,
- QuicTime::Delta local_max_ack_delay);
+ const RttStats* rtt_stats);
// Resets ACK related states, called after an ACK is successfully sent.
void ResetAckStates(EncryptionLevel encryption_level);
@@ -89,6 +88,10 @@ class QUIC_EXPORT_PRIVATE UberReceivedPacketManager {
void set_max_ack_ranges(size_t max_ack_ranges);
+ // Get and set the max ack delay to use for application data.
+ QuicTime::Delta max_ack_delay();
+ void set_max_ack_delay(QuicTime::Delta max_ack_delay);
+
void set_save_timestamps(bool save_timestamps);
private:
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 64dbb177362..9372da8e370 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
@@ -98,7 +98,7 @@ class UberReceivedPacketManagerTest : public QuicTest {
manager_->MaybeUpdateAckTimeout(
should_last_packet_instigate_acks, decrypted_packet_level,
QuicPacketNumber(last_received_packet_number), clock_.ApproximateNow(),
- clock_.ApproximateNow(), &rtt_stats_, kDelayedAckTime);
+ clock_.ApproximateNow(), &rtt_stats_);
}
void CheckAckTimeout(QuicTime time) {
@@ -378,6 +378,20 @@ TEST_F(UberReceivedPacketManagerTest, SendDelayedAfterQuiescence) {
CheckAckTimeout(ack_time);
}
+TEST_F(UberReceivedPacketManagerTest, SendDelayedMaxAckDelay) {
+ EXPECT_FALSE(HasPendingAck());
+ QuicTime::Delta max_ack_delay = QuicTime::Delta::FromMilliseconds(100);
+ manager_->set_max_ack_delay(max_ack_delay);
+ QuicTime ack_time = clock_.ApproximateNow() + max_ack_delay;
+
+ RecordPacketReceipt(1, clock_.ApproximateNow());
+ MaybeUpdateAckTimeout(kInstigateAck, 1);
+ CheckAckTimeout(ack_time);
+ // Simulate delayed ack alarm firing.
+ clock_.AdvanceTime(max_ack_delay);
+ CheckAckTimeout(clock_.ApproximateNow());
+}
+
TEST_F(UberReceivedPacketManagerTest, SendDelayedAckDecimation) {
EXPECT_FALSE(HasPendingAck());
UberReceivedPacketManagerPeer::SetAckMode(manager_.get(), ACK_DECIMATION);
@@ -765,7 +779,12 @@ TEST_F(UberReceivedPacketManagerTest, AckSendingDifferentPacketNumberSpaces) {
MaybeUpdateAckTimeout(kInstigateAck, ENCRYPTION_HANDSHAKE, 3);
EXPECT_TRUE(HasPendingAck());
// Delayed ack is scheduled.
- CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime);
+ CheckAckTimeout(clock_.ApproximateNow() +
+ QuicTime::Delta::FromMilliseconds(1));
+ // Send delayed handshake data ACK.
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
+ CheckAckTimeout(clock_.ApproximateNow());
+ EXPECT_FALSE(HasPendingAck());
RecordPacketReceipt(ENCRYPTION_FORWARD_SECURE, 3);
MaybeUpdateAckTimeout(kInstigateAck, ENCRYPTION_FORWARD_SECURE, 3);
@@ -777,12 +796,6 @@ TEST_F(UberReceivedPacketManagerTest, AckSendingDifferentPacketNumberSpaces) {
MaybeUpdateAckTimeout(kInstigateAck, ENCRYPTION_FORWARD_SECURE, 2);
// Application data ACK should be sent immediately.
CheckAckTimeout(clock_.ApproximateNow());
- // Delayed ACK of handshake data is pending.
- CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime);
-
- // Send delayed handshake data ACK.
- clock_.AdvanceTime(kDelayedAckTime);
- CheckAckTimeout(clock_.ApproximateNow());
EXPECT_FALSE(HasPendingAck());
}
diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/quic_default_proof_providers.h b/chromium/net/third_party/quiche/src/quic/platform/api/quic_default_proof_providers.h
index 6f3b636372f..98907096137 100644
--- a/chromium/net/third_party/quiche/src/quic/platform/api/quic_default_proof_providers.h
+++ b/chromium/net/third_party/quiche/src/quic/platform/api/quic_default_proof_providers.h
@@ -13,11 +13,12 @@
namespace quic {
-// Provides a default proof verifier. The verifier has to do a good faith
-// attempt at verifying the certificate against a reasonable root store, and not
-// just always return success.
-inline std::unique_ptr<ProofVerifier> CreateDefaultProofVerifier() {
- return CreateDefaultProofVerifierImpl();
+// Provides a default proof verifier that can verify a cert chain for |host|.
+// The verifier has to do a good faith attempt at verifying the certificate
+// against a reasonable root store, and not just always return success.
+inline std::unique_ptr<ProofVerifier> CreateDefaultProofVerifier(
+ const std::string& host) {
+ return CreateDefaultProofVerifierImpl(host);
}
// Provides a default proof source for CLI-based tools. The actual certificates
diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/quic_logging.h b/chromium/net/third_party/quiche/src/quic/platform/api/quic_logging.h
index ba48dc12b76..ce706e53ec8 100644
--- a/chromium/net/third_party/quiche/src/quic/platform/api/quic_logging.h
+++ b/chromium/net/third_party/quiche/src/quic/platform/api/quic_logging.h
@@ -25,6 +25,7 @@
#define QUIC_LOG_IF(severity, condition) QUIC_LOG_IF_IMPL(severity, condition)
#define QUIC_PREDICT_FALSE(x) QUIC_PREDICT_FALSE_IMPL(x)
+#define QUIC_PREDICT_TRUE(x) QUIC_PREDICT_TRUE_IMPL(x)
// This is a noop in release build.
#define QUIC_NOTREACHED() QUIC_NOTREACHED_IMPL()
diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/quic_mutex.h b/chromium/net/third_party/quiche/src/quic/platform/api/quic_mutex.h
index 162863a06b0..d35c6602aeb 100644
--- a/chromium/net/third_party/quiche/src/quic/platform/api/quic_mutex.h
+++ b/chromium/net/third_party/quiche/src/quic/platform/api/quic_mutex.h
@@ -7,31 +7,42 @@
#include "net/quic/platform/impl/quic_mutex_impl.h"
+#define QUIC_EXCLUSIVE_LOCKS_REQUIRED QUIC_EXCLUSIVE_LOCKS_REQUIRED_IMPL
+#define QUIC_GUARDED_BY QUIC_GUARDED_BY_IMPL
+#define QUIC_LOCKABLE QUIC_LOCKABLE_IMPL
+#define QUIC_LOCKS_EXCLUDED QUIC_LOCKS_EXCLUDED_IMPL
+#define QUIC_SHARED_LOCKS_REQUIRED QUIC_SHARED_LOCKS_REQUIRED_IMPL
+#define QUIC_EXCLUSIVE_LOCK_FUNCTION QUIC_EXCLUSIVE_LOCK_FUNCTION_IMPL
+#define QUIC_UNLOCK_FUNCTION QUIC_UNLOCK_FUNCTION_IMPL
+#define QUIC_SHARED_LOCK_FUNCTION QUIC_SHARED_LOCK_FUNCTION_IMPL
+#define QUIC_SCOPED_LOCKABLE QUIC_SCOPED_LOCKABLE_IMPL
+#define QUIC_ASSERT_SHARED_LOCK QUIC_ASSERT_SHARED_LOCK_IMPL
+
namespace quic {
// A class representing a non-reentrant mutex in QUIC.
-class LOCKABLE QUIC_EXPORT_PRIVATE QuicMutex {
+class QUIC_LOCKABLE QUIC_EXPORT_PRIVATE QuicMutex {
public:
QuicMutex() = default;
QuicMutex(const QuicMutex&) = delete;
QuicMutex& operator=(const QuicMutex&) = delete;
// Block until this Mutex is free, then acquire it exclusively.
- void WriterLock() EXCLUSIVE_LOCK_FUNCTION();
+ void WriterLock() QUIC_EXCLUSIVE_LOCK_FUNCTION();
// Release this Mutex. Caller must hold it exclusively.
- void WriterUnlock() UNLOCK_FUNCTION();
+ void WriterUnlock() QUIC_UNLOCK_FUNCTION();
// Block until this Mutex is free or shared, then acquire a share of it.
- void ReaderLock() SHARED_LOCK_FUNCTION();
+ void ReaderLock() QUIC_SHARED_LOCK_FUNCTION();
// Release this Mutex. Caller could hold it in shared mode.
- void ReaderUnlock() UNLOCK_FUNCTION();
+ void ReaderUnlock() QUIC_UNLOCK_FUNCTION();
// Returns immediately if current thread holds the Mutex in at least shared
// mode. Otherwise, may report an error (typically by crashing with a
// diagnostic), or may return immediately.
- void AssertReaderHeld() const ASSERT_SHARED_LOCK();
+ void AssertReaderHeld() const QUIC_ASSERT_SHARED_LOCK();
private:
QuicLockImpl impl_;
@@ -39,13 +50,13 @@ class LOCKABLE QUIC_EXPORT_PRIVATE QuicMutex {
// A helper class that acquires the given QuicMutex shared lock while the
// QuicReaderMutexLock is in scope.
-class SCOPED_LOCKABLE QUIC_EXPORT_PRIVATE QuicReaderMutexLock {
+class QUIC_SCOPED_LOCKABLE QUIC_EXPORT_PRIVATE QuicReaderMutexLock {
public:
- explicit QuicReaderMutexLock(QuicMutex* lock) SHARED_LOCK_FUNCTION(lock);
+ explicit QuicReaderMutexLock(QuicMutex* lock) QUIC_SHARED_LOCK_FUNCTION(lock);
QuicReaderMutexLock(const QuicReaderMutexLock&) = delete;
QuicReaderMutexLock& operator=(const QuicReaderMutexLock&) = delete;
- ~QuicReaderMutexLock() UNLOCK_FUNCTION();
+ ~QuicReaderMutexLock() QUIC_UNLOCK_FUNCTION();
private:
QuicMutex* const lock_;
@@ -53,13 +64,14 @@ class SCOPED_LOCKABLE QUIC_EXPORT_PRIVATE QuicReaderMutexLock {
// A helper class that acquires the given QuicMutex exclusive lock while the
// QuicWriterMutexLock is in scope.
-class SCOPED_LOCKABLE QUIC_EXPORT_PRIVATE QuicWriterMutexLock {
+class QUIC_SCOPED_LOCKABLE QUIC_EXPORT_PRIVATE QuicWriterMutexLock {
public:
- explicit QuicWriterMutexLock(QuicMutex* lock) EXCLUSIVE_LOCK_FUNCTION(lock);
+ explicit QuicWriterMutexLock(QuicMutex* lock)
+ QUIC_EXCLUSIVE_LOCK_FUNCTION(lock);
QuicWriterMutexLock(const QuicWriterMutexLock&) = delete;
QuicWriterMutexLock& operator=(const QuicWriterMutexLock&) = delete;
- ~QuicWriterMutexLock() UNLOCK_FUNCTION();
+ ~QuicWriterMutexLock() QUIC_UNLOCK_FUNCTION();
private:
QuicMutex* const lock_;
diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/quic_pcc_sender.h b/chromium/net/third_party/quiche/src/quic/platform/api/quic_pcc_sender.h
index add66827181..03db5b3645c 100644
--- a/chromium/net/third_party/quiche/src/quic/platform/api/quic_pcc_sender.h
+++ b/chromium/net/third_party/quiche/src/quic/platform/api/quic_pcc_sender.h
@@ -11,7 +11,7 @@ namespace quic {
class SendAlgorithmInterface;
// Interface for creating a PCC SendAlgorithmInterface
-SendAlgorithmInterface* CreatePccSender(
+inline SendAlgorithmInterface* CreatePccSender(
const QuicClock* clock,
const RttStats* rtt_stats,
const QuicUnackedPacketMap* unacked_packets,
diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/quic_port_utils.h b/chromium/net/third_party/quiche/src/quic/platform/api/quic_port_utils.h
index aa85fc5a765..685be0a75bd 100644
--- a/chromium/net/third_party/quiche/src/quic/platform/api/quic_port_utils.h
+++ b/chromium/net/third_party/quiche/src/quic/platform/api/quic_port_utils.h
@@ -10,13 +10,14 @@
namespace quic {
// Returns a UDP port that is currently unused. Check-fails if none are
-// available.
-inline int QuicPickUnusedPortOrDie() {
- return QuicPickUnusedPortOrDieImpl();
+// available. May return 0 in which case the bind() call will cause the OS
+// to use an unused port.
+inline int QuicPickServerPortForTestsOrDie() {
+ return QuicPickServerPortForTestsOrDieImpl();
}
// Indicates that a specified port previously returned by
-// QuicPickUnusedPortOrDie is no longer used.
+// QuicPickServerPortForTestsOrDie is no longer used.
inline void QuicRecyclePort(int port) {
return QuicRecyclePortImpl(port);
}
diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/quic_text_utils.h b/chromium/net/third_party/quiche/src/quic/platform/api/quic_text_utils.h
index 8db44cef75e..1fa3c72ab16 100644
--- a/chromium/net/third_party/quiche/src/quic/platform/api/quic_text_utils.h
+++ b/chromium/net/third_party/quiche/src/quic/platform/api/quic_text_utils.h
@@ -109,6 +109,11 @@ class QuicTextUtils {
return QuicTextUtilsImpl::ContainsUpperCase(data);
}
+ // Returns true if |data| contains only decimal digits.
+ static bool IsAllDigits(QuicStringPiece data) {
+ return QuicTextUtilsImpl::IsAllDigits(data);
+ }
+
// Splits |data| into a vector of pieces delimited by |delim|.
static std::vector<QuicStringPiece> Split(QuicStringPiece data, char delim) {
return QuicTextUtilsImpl::Split(data, delim);
diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/quic_text_utils_test.cc b/chromium/net/third_party/quiche/src/quic/platform/api/quic_text_utils_test.cc
index 9b156d05ddf..af4e81d7092 100644
--- a/chromium/net/third_party/quiche/src/quic/platform/api/quic_text_utils_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/platform/api/quic_text_utils_test.cc
@@ -201,6 +201,11 @@ TEST_F(QuicTextUtilsTest, Split) {
QuicTextUtils::Split("a:b:c", ':'));
EXPECT_EQ(std::vector<QuicStringPiece>({"a:b:c"}),
QuicTextUtils::Split("a:b:c", ','));
+ // Leading and trailing whitespace is preserved.
+ EXPECT_EQ(std::vector<QuicStringPiece>({"a", "b", "c"}),
+ QuicTextUtils::Split("a,b,c", ','));
+ EXPECT_EQ(std::vector<QuicStringPiece>({" a", "b ", " c "}),
+ QuicTextUtils::Split(" a:b : c ", ':'));
}
} // namespace test
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/icmp_reachable.cc b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/icmp_reachable.cc
new file mode 100644
index 00000000000..7779a8b212f
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/icmp_reachable.cc
@@ -0,0 +1,212 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/qbone/bonnet/icmp_reachable.h"
+
+#include <netinet/ip6.h>
+
+#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_endian.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_mutex.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
+#include "net/third_party/quiche/src/quic/qbone/platform/icmp_packet.h"
+
+namespace quic {
+namespace {
+
+constexpr int kEpollFlags = EPOLLIN | EPOLLET;
+constexpr size_t kMtu = 1280;
+
+constexpr size_t kIPv6AddrSize = sizeof(in6_addr);
+
+} // namespace
+
+const char kUnknownSource[] = "UNKNOWN";
+const char kNoSource[] = "N/A";
+
+IcmpReachable::IcmpReachable(QuicIpAddress source,
+ QuicIpAddress destination,
+ absl::Duration timeout,
+ KernelInterface* kernel,
+ QuicEpollServer* epoll_server,
+ StatsInterface* stats)
+ : timeout_(timeout),
+ cb_(this),
+ kernel_(kernel),
+ epoll_server_(epoll_server),
+ stats_(stats),
+ send_fd_(0),
+ recv_fd_(0) {
+ src_.sin6_family = AF_INET6;
+ dst_.sin6_family = AF_INET6;
+
+ memcpy(&src_.sin6_addr, source.ToPackedString().data(), kIPv6AddrSize);
+ memcpy(&dst_.sin6_addr, destination.ToPackedString().data(), kIPv6AddrSize);
+}
+
+IcmpReachable::~IcmpReachable() {
+ if (send_fd_ > 0) {
+ kernel_->close(send_fd_);
+ }
+ if (recv_fd_ > 0) {
+ if (!epoll_server_->ShutdownCalled()) {
+ epoll_server_->UnregisterFD(recv_fd_);
+ }
+
+ kernel_->close(recv_fd_);
+ }
+}
+
+bool IcmpReachable::Init() {
+ send_fd_ = kernel_->socket(PF_INET6, SOCK_RAW | SOCK_NONBLOCK, IPPROTO_RAW);
+ if (send_fd_ < 0) {
+ QUIC_LOG(ERROR) << "Unable to open socket: " << errno;
+ return false;
+ }
+
+ if (kernel_->bind(send_fd_, reinterpret_cast<struct sockaddr*>(&src_),
+ sizeof(sockaddr_in6)) < 0) {
+ QUIC_LOG(ERROR) << "Unable to bind socket: " << errno;
+ return false;
+ }
+
+ recv_fd_ =
+ kernel_->socket(PF_INET6, SOCK_RAW | SOCK_NONBLOCK, IPPROTO_ICMPV6);
+ if (recv_fd_ < 0) {
+ QUIC_LOG(ERROR) << "Unable to open socket: " << errno;
+ return false;
+ }
+
+ if (kernel_->bind(recv_fd_, reinterpret_cast<struct sockaddr*>(&src_),
+ sizeof(sockaddr_in6)) < 0) {
+ QUIC_LOG(ERROR) << "Unable to bind socket: " << errno;
+ return false;
+ }
+
+ icmp6_filter filter;
+ ICMP6_FILTER_SETBLOCKALL(&filter);
+ ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filter);
+ if (kernel_->setsockopt(recv_fd_, SOL_ICMPV6, ICMP6_FILTER, &filter,
+ sizeof(filter)) < 0) {
+ QUIC_LOG(ERROR) << "Unable to set ICMP6 filter.";
+ return false;
+ }
+
+ epoll_server_->RegisterFD(recv_fd_, &cb_, kEpollFlags);
+ epoll_server_->RegisterAlarm(0, this);
+
+ epoll_server_->set_timeout_in_us(50000);
+
+ QuicWriterMutexLock mu(&header_lock_);
+ icmp_header_.icmp6_type = ICMP6_ECHO_REQUEST;
+ icmp_header_.icmp6_code = 0;
+
+ QuicRandom::GetInstance()->RandBytes(&icmp_header_.icmp6_id,
+ sizeof(uint16_t));
+
+ return true;
+}
+
+bool IcmpReachable::OnEvent(int fd) {
+ char buffer[kMtu];
+
+ sockaddr_in6 source_addr{};
+ socklen_t source_addr_len = sizeof(source_addr);
+
+ ssize_t size = kernel_->recvfrom(fd, &buffer, kMtu, 0,
+ reinterpret_cast<sockaddr*>(&source_addr),
+ &source_addr_len);
+
+ if (size < 0) {
+ if (errno != EAGAIN && errno != EWOULDBLOCK) {
+ stats_->OnReadError(errno);
+ }
+ return false;
+ }
+
+ QUIC_VLOG(2) << QuicTextUtils::HexDump(QuicStringPiece(buffer, size));
+
+ auto* header = reinterpret_cast<const icmp6_hdr*>(&buffer);
+ QuicWriterMutexLock mu(&header_lock_);
+ if (header->icmp6_data32[0] != icmp_header_.icmp6_data32[0]) {
+ QUIC_VLOG(2) << "Unexpected response. id: " << header->icmp6_id
+ << " seq: " << header->icmp6_seq
+ << " Expected id: " << icmp_header_.icmp6_id
+ << " seq: " << icmp_header_.icmp6_seq;
+ return true;
+ }
+ end_ = absl::Now();
+ QUIC_VLOG(1) << "Received ping response in "
+ << absl::ToInt64Microseconds(end_ - start_) << "us.";
+
+ string source;
+ QuicIpAddress source_ip;
+ if (!source_ip.FromPackedString(
+ reinterpret_cast<char*>(&source_addr.sin6_addr), sizeof(in6_addr))) {
+ QUIC_LOG(WARNING) << "Unable to parse source address.";
+ source = kUnknownSource;
+ } else {
+ source = source_ip.ToString();
+ }
+ stats_->OnEvent({Status::REACHABLE, end_ - start_, source});
+ return true;
+}
+
+int64 /* allow-non-std-int */ IcmpReachable::OnAlarm() {
+ EpollAlarm::OnAlarm();
+
+ QuicWriterMutexLock mu(&header_lock_);
+
+ if (end_ < start_) {
+ QUIC_VLOG(1) << "Timed out on sequence: " << icmp_header_.icmp6_seq;
+ stats_->OnEvent({Status::UNREACHABLE, absl::ZeroDuration(), kNoSource});
+ }
+
+ icmp_header_.icmp6_seq++;
+ CreateIcmpPacket(src_.sin6_addr, dst_.sin6_addr, icmp_header_, "",
+ [this](QuicStringPiece packet) {
+ QUIC_VLOG(2) << QuicTextUtils::HexDump(packet);
+
+ ssize_t size = kernel_->sendto(
+ send_fd_, packet.data(), packet.size(), 0,
+ reinterpret_cast<struct sockaddr*>(&dst_),
+ sizeof(sockaddr_in6));
+
+ if (size < packet.size()) {
+ stats_->OnWriteError(errno);
+ }
+ start_ = absl::Now();
+ });
+
+ return absl::ToUnixMicros(absl::Now() + timeout_);
+}
+
+QuicStringPiece IcmpReachable::StatusName(IcmpReachable::Status status) {
+ switch (status) {
+ case REACHABLE:
+ return "REACHABLE";
+ case UNREACHABLE:
+ return "UNREACHABLE";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+void IcmpReachable::EpollCallback::OnEvent(int fd, QuicEpollEvent* event) {
+ bool can_read_more = reachable_->OnEvent(fd);
+ if (can_read_more) {
+ event->out_ready_mask |= EPOLLIN;
+ }
+}
+
+void IcmpReachable::EpollCallback::OnShutdown(QuicEpollServer* eps, int fd) {
+ eps->UnregisterFD(fd);
+}
+
+string IcmpReachable::EpollCallback::Name() const {
+ return "ICMP Reachable";
+}
+
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/icmp_reachable.h b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/icmp_reachable.h
new file mode 100644
index 00000000000..b4ce4c13966
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/icmp_reachable.h
@@ -0,0 +1,140 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_QBONE_BONNET_ICMP_REACHABLE_H_
+#define QUICHE_QUIC_QBONE_BONNET_ICMP_REACHABLE_H_
+
+#include <netinet/icmp6.h>
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_mutex.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
+#include "net/third_party/quiche/src/quic/qbone/bonnet/icmp_reachable_interface.h"
+#include "net/third_party/quiche/src/quic/qbone/platform/kernel_interface.h"
+
+namespace quic {
+
+extern const char kUnknownSource[];
+extern const char kNoSource[];
+
+// IcmpReachable schedules itself with an EpollServer, periodically sending
+// ICMPv6 Echo Requests to the given |destination| on the interface that the
+// given |source| is bound to. Echo Requests are sent once every |timeout|.
+// On Echo Replies, timeouts, and I/O errors, the given |stats| object will
+// be called back with details of the event.
+class IcmpReachable : public IcmpReachableInterface {
+ public:
+ enum Status { REACHABLE, UNREACHABLE };
+
+ struct ReachableEvent {
+ Status status;
+ absl::Duration response_time;
+ string source;
+ };
+
+ class StatsInterface {
+ public:
+ StatsInterface() = default;
+
+ StatsInterface(const StatsInterface&) = delete;
+ StatsInterface& operator=(const StatsInterface&) = delete;
+
+ StatsInterface(StatsInterface&&) = delete;
+ StatsInterface& operator=(StatsInterface&&) = delete;
+
+ virtual ~StatsInterface() = default;
+
+ virtual void OnEvent(ReachableEvent event) = 0;
+
+ virtual void OnReadError(int error) = 0;
+
+ virtual void OnWriteError(int error) = 0;
+ };
+
+ // |source| is the IPv6 address bound to the interface that IcmpReachable will
+ // send Echo Requests on.
+ // |destination| is the IPv6 address of the destination of the Echo Requests.
+ // |timeout| is the duration IcmpReachable will wait between Echo Requests.
+ // If no Echo Response is received by the next Echo Request, it will
+ // be considered a timeout.
+ // |kernel| is not owned, but should outlive this instance.
+ // |epoll_server| is not owned, but should outlive this instance.
+ // IcmpReachable's Init() must be called from within the Epoll
+ // Server's thread.
+ // |stats| is not owned, but should outlive this instance. It will be called
+ // back on Echo Replies, timeouts, and I/O errors.
+ IcmpReachable(QuicIpAddress source,
+ QuicIpAddress destination,
+ absl::Duration timeout,
+ KernelInterface* kernel,
+ QuicEpollServer* epoll_server,
+ StatsInterface* stats);
+
+ ~IcmpReachable() override;
+
+ // Initializes this reachability probe. Must be called from within the
+ // |epoll_server|'s thread.
+ bool Init() QUIC_LOCKS_EXCLUDED(header_lock_) override;
+
+ int64 /* allow-non-std-int */ OnAlarm()
+ QUIC_LOCKS_EXCLUDED(header_lock_) override;
+
+ static QuicStringPiece StatusName(Status status);
+
+ private:
+ class EpollCallback : public QuicEpollCallbackInterface {
+ public:
+ explicit EpollCallback(IcmpReachable* reachable) : reachable_(reachable) {}
+
+ EpollCallback(const EpollCallback&) = delete;
+ EpollCallback& operator=(const EpollCallback&) = delete;
+
+ EpollCallback(EpollCallback&&) = delete;
+ EpollCallback& operator=(EpollCallback&&) = delete;
+
+ void OnRegistration(QuicEpollServer* eps,
+ int fd,
+ int event_mask) override{};
+
+ void OnModification(int fd, int event_mask) override{};
+
+ void OnEvent(int fd, QuicEpollEvent* event) override;
+
+ void OnUnregistration(int fd, bool replaced) override{};
+
+ void OnShutdown(QuicEpollServer* eps, int fd) override;
+
+ string Name() const override;
+
+ private:
+ IcmpReachable* reachable_;
+ };
+
+ bool OnEvent(int fd) QUIC_LOCKS_EXCLUDED(header_lock_);
+
+ const absl::Duration timeout_;
+
+ EpollCallback cb_;
+
+ sockaddr_in6 src_{};
+ sockaddr_in6 dst_{};
+
+ KernelInterface* kernel_;
+ QuicEpollServer* epoll_server_;
+
+ StatsInterface* stats_;
+
+ int send_fd_;
+ int recv_fd_;
+
+ QuicMutex header_lock_;
+ icmp6_hdr icmp_header_ QUIC_GUARDED_BY(header_lock_){};
+
+ absl::Time start_ = absl::InfinitePast();
+ absl::Time end_ = absl::InfinitePast();
+};
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_QBONE_BONNET_ICMP_REACHABLE_H_
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/icmp_reachable_interface.h b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/icmp_reachable_interface.h
new file mode 100644
index 00000000000..e766a89ba3f
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/icmp_reachable_interface.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_QBONE_BONNET_ICMP_REACHABLE_INTERFACE_H_
+#define QUICHE_QUIC_QBONE_BONNET_ICMP_REACHABLE_INTERFACE_H_
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_epoll.h"
+
+namespace quic {
+
+class IcmpReachableInterface : public QuicEpollAlarmBase {
+ public:
+ IcmpReachableInterface() = default;
+
+ IcmpReachableInterface(const IcmpReachableInterface&) = delete;
+ IcmpReachableInterface& operator=(const IcmpReachableInterface&) = delete;
+
+ IcmpReachableInterface(IcmpReachableInterface&&) = delete;
+ IcmpReachableInterface& operator=(IcmpReachableInterface&&) = delete;
+
+ // Initializes this reachability probe.
+ virtual bool Init() = 0;
+};
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_QBONE_BONNET_ICMP_REACHABLE_INTERFACE_H_
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/icmp_reachable_test.cc b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/icmp_reachable_test.cc
new file mode 100644
index 00000000000..303f0e280b7
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/icmp_reachable_test.cc
@@ -0,0 +1,266 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/qbone/bonnet/icmp_reachable.h"
+
+#include <netinet/ip6.h>
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_epoll.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+#include "net/third_party/quiche/src/quic/qbone/platform/mock_kernel.h"
+
+namespace quic {
+namespace {
+
+using ::testing::_;
+using ::testing::InSequence;
+using ::testing::Invoke;
+using ::testing::Return;
+using ::testing::StrictMock;
+
+constexpr char kSourceAddress[] = "fe80:1:2:3:4::1";
+constexpr char kDestinationAddress[] = "fe80:4:3:2:1::1";
+
+constexpr int kFakeWriteFd = 0;
+
+icmp6_hdr GetHeaderFromPacket(const void* buf, size_t len) {
+ CHECK_GE(len, sizeof(ip6_hdr) + sizeof(icmp6_hdr));
+
+ auto* buffer = reinterpret_cast<const char*>(buf);
+ return *reinterpret_cast<const icmp6_hdr*>(&buffer[sizeof(ip6_hdr)]);
+}
+
+class StatsInterface : public IcmpReachable::StatsInterface {
+ public:
+ void OnEvent(IcmpReachable::ReachableEvent event) override {
+ switch (event.status) {
+ case IcmpReachable::REACHABLE: {
+ reachable_count_++;
+ break;
+ }
+ case IcmpReachable::UNREACHABLE: {
+ unreachable_count_++;
+ break;
+ }
+ }
+ current_source_ = event.source;
+ }
+
+ void OnReadError(int error) override { read_errors_[error]++; }
+
+ void OnWriteError(int error) override { write_errors_[error]++; }
+
+ bool HasWriteErrors() { return !write_errors_.empty(); }
+
+ int WriteErrorCount(int error) { return write_errors_[error]; }
+
+ bool HasReadErrors() { return !read_errors_.empty(); }
+
+ int ReadErrorCount(int error) { return read_errors_[error]; }
+
+ int reachable_count() { return reachable_count_; }
+
+ int unreachable_count() { return unreachable_count_; }
+
+ string current_source() { return current_source_; }
+
+ private:
+ int reachable_count_ = 0;
+ int unreachable_count_ = 0;
+
+ string current_source_{};
+
+ QuicUnorderedMap<int, int> read_errors_;
+ QuicUnorderedMap<int, int> write_errors_;
+};
+
+class IcmpReachableTest : public QuicTest {
+ public:
+ IcmpReachableTest() {
+ CHECK(source_.FromString(kSourceAddress));
+ CHECK(destination_.FromString(kDestinationAddress));
+
+ int pipe_fds[2];
+ CHECK(pipe(pipe_fds) >= 0) << "pipe() failed";
+
+ read_fd_ = pipe_fds[0];
+ read_src_fd_ = pipe_fds[1];
+ }
+
+ void SetFdExpectations() {
+ InSequence seq;
+ EXPECT_CALL(kernel_, socket(_, _, _)).WillOnce(Return(kFakeWriteFd));
+ EXPECT_CALL(kernel_, bind(kFakeWriteFd, _, _)).WillOnce(Return(0));
+
+ EXPECT_CALL(kernel_, socket(_, _, _)).WillOnce(Return(read_fd_));
+ EXPECT_CALL(kernel_, bind(read_fd_, _, _)).WillOnce(Return(0));
+
+ EXPECT_CALL(kernel_, setsockopt(read_fd_, SOL_ICMPV6, ICMP6_FILTER, _, _));
+
+ EXPECT_CALL(kernel_, close(read_fd_)).WillOnce(Invoke([](int fd) {
+ return close(fd);
+ }));
+ }
+
+ protected:
+ QuicIpAddress source_;
+ QuicIpAddress destination_;
+
+ int read_fd_;
+ int read_src_fd_;
+
+ StrictMock<MockKernel> kernel_;
+ QuicEpollServer epoll_server_;
+ StatsInterface stats_;
+};
+
+TEST_F(IcmpReachableTest, SendsPings) {
+ IcmpReachable reachable(source_, destination_, absl::Seconds(0), &kernel_,
+ &epoll_server_, &stats_);
+
+ SetFdExpectations();
+ ASSERT_TRUE(reachable.Init());
+
+ EXPECT_CALL(kernel_, sendto(kFakeWriteFd, _, _, _, _, _))
+ .WillOnce(Invoke([](int sockfd, const void* buf, size_t len, int flags,
+ const struct sockaddr* dest_addr, socklen_t addrlen) {
+ auto icmp_header = GetHeaderFromPacket(buf, len);
+ EXPECT_EQ(icmp_header.icmp6_type, ICMP6_ECHO_REQUEST);
+ EXPECT_EQ(icmp_header.icmp6_seq, 1);
+ return len;
+ }));
+
+ epoll_server_.WaitForEventsAndExecuteCallbacks();
+ EXPECT_FALSE(stats_.HasWriteErrors());
+
+ epoll_server_.Shutdown();
+}
+
+TEST_F(IcmpReachableTest, HandlesUnreachableEvents) {
+ IcmpReachable reachable(source_, destination_, absl::Seconds(0), &kernel_,
+ &epoll_server_, &stats_);
+
+ SetFdExpectations();
+ ASSERT_TRUE(reachable.Init());
+
+ EXPECT_CALL(kernel_, sendto(kFakeWriteFd, _, _, _, _, _))
+ .Times(2)
+ .WillRepeatedly(Invoke([](int sockfd, const void* buf, size_t len,
+ int flags, const struct sockaddr* dest_addr,
+ socklen_t addrlen) { return len; }));
+
+ epoll_server_.WaitForEventsAndExecuteCallbacks();
+ EXPECT_EQ(stats_.unreachable_count(), 0);
+
+ epoll_server_.WaitForEventsAndExecuteCallbacks();
+ EXPECT_FALSE(stats_.HasWriteErrors());
+ EXPECT_EQ(stats_.unreachable_count(), 1);
+ EXPECT_EQ(stats_.current_source(), kNoSource);
+
+ epoll_server_.Shutdown();
+}
+
+TEST_F(IcmpReachableTest, HandlesReachableEvents) {
+ IcmpReachable reachable(source_, destination_, absl::Seconds(0), &kernel_,
+ &epoll_server_, &stats_);
+
+ SetFdExpectations();
+ ASSERT_TRUE(reachable.Init());
+
+ icmp6_hdr last_request_hdr{};
+ EXPECT_CALL(kernel_, sendto(kFakeWriteFd, _, _, _, _, _))
+ .Times(2)
+ .WillRepeatedly(
+ Invoke([&last_request_hdr](
+ int sockfd, const void* buf, size_t len, int flags,
+ const struct sockaddr* dest_addr, socklen_t addrlen) {
+ last_request_hdr = GetHeaderFromPacket(buf, len);
+ return len;
+ }));
+
+ sockaddr_in6 source_addr{};
+ string packed_source = source_.ToPackedString();
+ memcpy(&source_addr.sin6_addr, packed_source.data(), packed_source.size());
+
+ EXPECT_CALL(kernel_, recvfrom(read_fd_, _, _, _, _, _))
+ .WillOnce(
+ Invoke([&source_addr](int sockfd, void* buf, size_t len, int flags,
+ struct sockaddr* src_addr, socklen_t* addrlen) {
+ *reinterpret_cast<sockaddr_in6*>(src_addr) = source_addr;
+ return read(sockfd, buf, len);
+ }));
+
+ epoll_server_.WaitForEventsAndExecuteCallbacks();
+ EXPECT_EQ(stats_.reachable_count(), 0);
+
+ icmp6_hdr response = last_request_hdr;
+ response.icmp6_type = ICMP6_ECHO_REPLY;
+
+ write(read_src_fd_, reinterpret_cast<const void*>(&response),
+ sizeof(icmp6_hdr));
+
+ epoll_server_.WaitForEventsAndExecuteCallbacks();
+ EXPECT_FALSE(stats_.HasReadErrors());
+ EXPECT_FALSE(stats_.HasWriteErrors());
+ EXPECT_EQ(stats_.reachable_count(), 1);
+ EXPECT_EQ(stats_.current_source(), source_.ToString());
+
+ epoll_server_.Shutdown();
+}
+
+TEST_F(IcmpReachableTest, HandlesWriteErrors) {
+ IcmpReachable reachable(source_, destination_, absl::Seconds(0), &kernel_,
+ &epoll_server_, &stats_);
+
+ SetFdExpectations();
+ ASSERT_TRUE(reachable.Init());
+
+ EXPECT_CALL(kernel_, sendto(kFakeWriteFd, _, _, _, _, _))
+ .WillOnce(Invoke([](int sockfd, const void* buf, size_t len, int flags,
+ const struct sockaddr* dest_addr, socklen_t addrlen) {
+ errno = EAGAIN;
+ return 0;
+ }));
+
+ epoll_server_.WaitForEventsAndExecuteCallbacks();
+ EXPECT_EQ(stats_.WriteErrorCount(EAGAIN), 1);
+
+ epoll_server_.Shutdown();
+}
+
+TEST_F(IcmpReachableTest, HandlesReadErrors) {
+ IcmpReachable reachable(source_, destination_, absl::Seconds(0), &kernel_,
+ &epoll_server_, &stats_);
+
+ SetFdExpectations();
+ ASSERT_TRUE(reachable.Init());
+
+ EXPECT_CALL(kernel_, sendto(kFakeWriteFd, _, _, _, _, _))
+ .WillOnce(Invoke([](int sockfd, const void* buf, size_t len, int flags,
+ const struct sockaddr* dest_addr,
+ socklen_t addrlen) { return len; }));
+
+ EXPECT_CALL(kernel_, recvfrom(read_fd_, _, _, _, _, _))
+ .WillOnce(Invoke([](int sockfd, void* buf, size_t len, int flags,
+ struct sockaddr* src_addr, socklen_t* addrlen) {
+ errno = EIO;
+ return -1;
+ }));
+
+ icmp6_hdr response{};
+
+ write(read_src_fd_, reinterpret_cast<const void*>(&response),
+ sizeof(icmp6_hdr));
+
+ epoll_server_.WaitForEventsAndExecuteCallbacks();
+ EXPECT_EQ(stats_.reachable_count(), 0);
+ EXPECT_EQ(stats_.ReadErrorCount(EIO), 1);
+
+ epoll_server_.Shutdown();
+}
+
+} // namespace
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/mock_icmp_reachable.h b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/mock_icmp_reachable.h
new file mode 100644
index 00000000000..092845eba7d
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/mock_icmp_reachable.h
@@ -0,0 +1,20 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_QBONE_BONNET_MOCK_ICMP_REACHABLE_H_
+#define QUICHE_QUIC_QBONE_BONNET_MOCK_ICMP_REACHABLE_H_
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+#include "net/third_party/quiche/src/quic/qbone/bonnet/icmp_reachable_interface.h"
+
+namespace quic {
+
+class MockIcmpReachable : public IcmpReachableInterface {
+ public:
+ MOCK_METHOD0(Init, bool());
+};
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_QBONE_BONNET_MOCK_ICMP_REACHABLE_H_
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/mock_tun_device.h b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/mock_tun_device.h
new file mode 100644
index 00000000000..37e852af515
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/mock_tun_device.h
@@ -0,0 +1,26 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_QBONE_BONNET_MOCK_TUN_DEVICE_H_
+#define QUICHE_QUIC_QBONE_BONNET_MOCK_TUN_DEVICE_H_
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+#include "net/third_party/quiche/src/quic/qbone/bonnet/tun_device_interface.h"
+
+namespace quic {
+
+class MockTunDevice : public TunDeviceInterface {
+ public:
+ MOCK_METHOD0(Init, bool());
+
+ MOCK_METHOD0(Up, bool());
+
+ MOCK_METHOD0(Down, bool());
+
+ MOCK_CONST_METHOD0(GetFileDescriptor, int());
+};
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_QBONE_BONNET_MOCK_TUN_DEVICE_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
new file mode 100644
index 00000000000..6c0a8a55ed8
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device.cc
@@ -0,0 +1,201 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/qbone/bonnet/tun_device.h"
+
+#include <fcntl.h>
+#include <linux/if_tun.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
+#include "net/third_party/quiche/src/quic/qbone/platform/kernel_interface.h"
+
+namespace quic {
+
+const char kTapTunDevicePath[] = "/dev/net/tun";
+const int kInvalidFd = -1;
+
+TunDevice::TunDevice(const string& interface_name,
+ int mtu,
+ bool persist,
+ KernelInterface* kernel)
+ : interface_name_(interface_name),
+ mtu_(mtu),
+ persist_(persist),
+ file_descriptor_(kInvalidFd),
+ kernel_(*kernel) {}
+
+TunDevice::~TunDevice() {
+ Down();
+ CleanUpFileDescriptor();
+}
+
+bool TunDevice::Init() {
+ if (interface_name_.empty() || interface_name_.size() >= IFNAMSIZ) {
+ QUIC_BUG << "interface_name must be nonempty and shorter than " << IFNAMSIZ;
+ return false;
+ }
+
+ if (!OpenDevice()) {
+ return false;
+ }
+
+ if (!ConfigureInterface()) {
+ return false;
+ }
+
+ return true;
+}
+
+// TODO(pengg): might be better to use netlink socket, once we have a library to
+// use
+bool TunDevice::Up() {
+ if (!is_interface_up_) {
+ struct ifreq if_request;
+ memset(&if_request, 0, sizeof(if_request));
+ // copy does not zero-terminate the result string, but we've memset the
+ // entire struct.
+ interface_name_.copy(if_request.ifr_name, IFNAMSIZ);
+ if_request.ifr_flags = IFF_UP;
+
+ is_interface_up_ =
+ NetdeviceIoctl(SIOCSIFFLAGS, reinterpret_cast<void*>(&if_request));
+ return is_interface_up_;
+ } else {
+ return true;
+ }
+}
+
+// TODO(pengg): might be better to use netlink socket, once we have a library to
+// use
+bool TunDevice::Down() {
+ if (is_interface_up_) {
+ struct ifreq if_request;
+ memset(&if_request, 0, sizeof(if_request));
+ // copy does not zero-terminate the result string, but we've memset the
+ // entire struct.
+ interface_name_.copy(if_request.ifr_name, IFNAMSIZ);
+ if_request.ifr_flags = 0;
+
+ is_interface_up_ =
+ !NetdeviceIoctl(SIOCSIFFLAGS, reinterpret_cast<void*>(&if_request));
+ return !is_interface_up_;
+ } else {
+ return true;
+ }
+}
+
+int TunDevice::GetFileDescriptor() const {
+ return file_descriptor_;
+}
+
+bool TunDevice::OpenDevice() {
+ struct ifreq if_request;
+ memset(&if_request, 0, sizeof(if_request));
+ // copy does not zero-terminate the result string, but we've memset the entire
+ // struct.
+ interface_name_.copy(if_request.ifr_name, IFNAMSIZ);
+
+ // Always set IFF_MULTI_QUEUE since a persistent device does not allow this
+ // flag to be flipped when re-opening it. The only way to flip this flag is to
+ // 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;
+
+ // TODO(pengg): port MakeCleanup to quic/platform? This makes the call to
+ // CleanUpFileDescriptor nicer and less error-prone.
+ // 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.
+ int fd = kernel_.open(kTapTunDevicePath, O_RDWR);
+ if (fd < 0) {
+ QUIC_PLOG(WARNING) << "Failed to open " << kTapTunDevicePath;
+ CleanUpFileDescriptor();
+ return false;
+ }
+ file_descriptor_ = fd;
+ if (!CheckFeatures(fd)) {
+ CleanUpFileDescriptor();
+ return false;
+ }
+
+ if (kernel_.ioctl(fd, TUNSETIFF, reinterpret_cast<void*>(&if_request)) != 0) {
+ QUIC_PLOG(WARNING) << "Failed to TUNSETIFF on fd(" << fd << ")";
+ CleanUpFileDescriptor();
+ return false;
+ }
+
+ if (kernel_.ioctl(
+ fd, TUNSETPERSIST,
+ persist_ ? reinterpret_cast<void*>(&if_request) : nullptr) != 0) {
+ QUIC_PLOG(WARNING) << "Failed to TUNSETPERSIST on fd(" << fd << ")";
+ CleanUpFileDescriptor();
+ return false;
+ }
+
+ return true;
+}
+
+// TODO(pengg): might be better to use netlink socket, once we have a library to
+// use
+bool TunDevice::ConfigureInterface() {
+ struct ifreq if_request;
+ memset(&if_request, 0, sizeof(if_request));
+ // copy does not zero-terminate the result string, but we've memset the entire
+ // struct.
+ interface_name_.copy(if_request.ifr_name, IFNAMSIZ);
+ if_request.ifr_mtu = mtu_;
+
+ if (!NetdeviceIoctl(SIOCSIFMTU, reinterpret_cast<void*>(&if_request))) {
+ CleanUpFileDescriptor();
+ return false;
+ }
+
+ return true;
+}
+
+bool TunDevice::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";
+ return false;
+ }
+ unsigned int required_features = IFF_TUN | IFF_NO_PI;
+ if ((required_features & actual_features) != required_features) {
+ QUIC_LOG(WARNING)
+ << "Required feature does not exist. required_features: 0x" << std::hex
+ << required_features << " vs actual_features: 0x" << std::hex
+ << actual_features;
+ return false;
+ }
+ return true;
+}
+
+bool TunDevice::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.";
+ return false;
+ }
+
+ if (kernel_.ioctl(fd, request, argp) != 0) {
+ QUIC_PLOG(WARNING) << "Failed ioctl request: " << request;
+ kernel_.close(fd);
+ return false;
+ }
+ kernel_.close(fd);
+ return true;
+}
+
+void TunDevice::CleanUpFileDescriptor() {
+ if (file_descriptor_ != kInvalidFd) {
+ kernel_.close(file_descriptor_);
+ file_descriptor_ = kInvalidFd;
+ }
+}
+
+} // namespace quic
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
new file mode 100644
index 00000000000..1828b81a1b0
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device.h
@@ -0,0 +1,82 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_QBONE_BONNET_TUN_DEVICE_H_
+#define QUICHE_QUIC_QBONE_BONNET_TUN_DEVICE_H_
+
+#include <string>
+#include <vector>
+
+#include "net/third_party/quiche/src/quic/qbone/bonnet/tun_device_interface.h"
+#include "net/third_party/quiche/src/quic/qbone/platform/kernel_interface.h"
+
+namespace quic {
+
+class TunDevice : 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
+ // program that owns it. The routing rule that routes packets to this
+ // interface should be defined somewhere else.
+ //
+ // Standard read/write system calls can be used to receive/send packets
+ // from/to this interface. The file descriptor is owned by this class.
+ //
+ // If persist is set to true, the device won't be deleted even after
+ // destructing. The device will be picked up when initializing this class with
+ // the same interface_name on the next time.
+ //
+ // Persisting the device is useful if one wants to keep the routing rules
+ // since once a tun device is destroyed by the kernel, all the associated
+ // routing rules go away.
+ //
+ // The caller should own kernel and make sure it outlives this.
+ TunDevice(const string& interface_name,
+ int mtu,
+ bool persist,
+ KernelInterface* kernel);
+
+ ~TunDevice() override;
+
+ // Actually creates/reopens and configures the device.
+ bool Init() override;
+
+ // Marks the interface up to start receiving packets.
+ bool Up() override;
+
+ // Marks the interface down to stop receiving packets.
+ bool Down() override;
+
+ // Gets the file descriptor that can be used to send/receive packets.
+ // This returns -1 when the TUN device is in an invalid state.
+ int GetFileDescriptor() const override;
+
+ private:
+ // Creates or reopens the tun device.
+ bool OpenDevice();
+
+ // Configure the interface.
+ bool ConfigureInterface();
+
+ // Checks if the required kernel features exists.
+ bool CheckFeatures(int tun_device_fd);
+
+ // Closes the opened file descriptor and makes sure the file descriptor
+ // is no longer available from GetFileDescriptor;
+ void CleanUpFileDescriptor();
+
+ // Opens a socket and makes netdevice ioctl call
+ bool NetdeviceIoctl(int request, void* argp);
+
+ const string interface_name_;
+ const int mtu_;
+ const bool persist_;
+ int file_descriptor_;
+ KernelInterface& kernel_;
+ bool is_interface_up_ = false;
+};
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_QBONE_BONNET_TUN_DEVICE_H_
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
new file mode 100644
index 00000000000..e99c547ee7c
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_interface.h
@@ -0,0 +1,33 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_QBONE_BONNET_TUN_DEVICE_INTERFACE_H_
+#define QUICHE_QUIC_QBONE_BONNET_TUN_DEVICE_INTERFACE_H_
+
+#include <vector>
+
+namespace quic {
+
+// An interface with methods for interacting with a TUN device.
+class TunDeviceInterface {
+ public:
+ virtual ~TunDeviceInterface() {}
+
+ // Actually creates/reopens and configures the device.
+ virtual bool Init() = 0;
+
+ // Marks the interface up to start receiving packets.
+ virtual bool Up() = 0;
+
+ // Marks the interface down to stop receiving packets.
+ virtual bool Down() = 0;
+
+ // Gets the file descriptor that can be used to send/receive packets.
+ // This returns -1 when the TUN device is in an invalid state.
+ virtual int GetFileDescriptor() const = 0;
+};
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_QBONE_BONNET_TUN_DEVICE_INTERFACE_H_
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
new file mode 100644
index 00000000000..1d246a21dc6
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger.cc
@@ -0,0 +1,82 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger.h"
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h"
+
+namespace quic {
+
+TunDevicePacketExchanger::TunDevicePacketExchanger(
+ int fd,
+ size_t mtu,
+ KernelInterface* kernel,
+ QbonePacketExchanger::Visitor* visitor,
+ size_t max_pending_packets, StatsInterface* stats)
+ : QbonePacketExchanger(visitor, max_pending_packets),
+ fd_(fd),
+ mtu_(mtu),
+ kernel_(kernel),
+ stats_(stats) {}
+
+bool TunDevicePacketExchanger::WritePacket(const char* packet,
+ size_t size,
+ bool* blocked,
+ string* error) {
+ *blocked = false;
+ if (fd_ < 0) {
+ *error = QuicStrCat("Invalid file descriptor of the TUN device: ", fd_);
+ stats_->OnWriteError(error);
+ return false;
+ }
+
+ int result = kernel_->write(fd_, packet, size);
+ if (result == -1) {
+ if (errno == EWOULDBLOCK || errno == EAGAIN) {
+ // The tunnel is blocked. Note that this does not mean the receive buffer
+ // of a TCP connection is filled. This simply means the TUN device itself
+ // is blocked on handing packets to the rest part of the kernel.
+ *error = QuicStrCat("Write to the TUN device was blocked: ", errno);
+ *blocked = true;
+ stats_->OnWriteError(error);
+ }
+ return false;
+ }
+ stats_->OnPacketWritten();
+
+ return true;
+}
+
+std::unique_ptr<QuicData> TunDevicePacketExchanger::ReadPacket(bool* blocked,
+ string* error) {
+ *blocked = false;
+ if (fd_ < 0) {
+ *error = QuicStrCat("Invalid file descriptor of the TUN device: ", fd_);
+ stats_->OnReadError(error);
+ return nullptr;
+ }
+ // Reading on a TUN device returns a packet at a time. If the packet is longer
+ // than the buffer, it's truncated.
+ auto read_buffer = QuicMakeUnique<char[]>(mtu_);
+ int result = kernel_->read(fd_, read_buffer.get(), mtu_);
+ // Note that 0 means end of file, but we're talking about a TUN device - there
+ // is no end of file. Therefore 0 also indicates error.
+ if (result <= 0) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ *error = QuicStrCat("Read from the TUN device was blocked: ", errno);
+ *blocked = true;
+ stats_->OnReadError(error);
+ }
+ return nullptr;
+ }
+ stats_->OnPacketRead();
+ return QuicMakeUnique<QuicData>(read_buffer.release(), result, true);
+}
+
+int TunDevicePacketExchanger::file_descriptor() const {
+ return fd_;
+}
+
+} // 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
new file mode 100644
index 00000000000..12d9efa714a
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger.h
@@ -0,0 +1,72 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_QBONE_BONNET_TUN_DEVICE_PACKET_EXCHANGER_H_
+#define QUICHE_QUIC_QBONE_BONNET_TUN_DEVICE_PACKET_EXCHANGER_H_
+
+#include "net/third_party/quiche/src/quic/core/quic_packets.h"
+#include "net/third_party/quiche/src/quic/qbone/platform/kernel_interface.h"
+#include "net/third_party/quiche/src/quic/qbone/qbone_client_interface.h"
+#include "net/third_party/quiche/src/quic/qbone/qbone_packet_exchanger.h"
+
+namespace quic {
+
+class TunDevicePacketExchanger : public QbonePacketExchanger {
+ public:
+ class StatsInterface {
+ public:
+ StatsInterface() = default;
+
+ StatsInterface(const StatsInterface&) = delete;
+ StatsInterface& operator=(const StatsInterface&) = delete;
+
+ StatsInterface(StatsInterface&&) = delete;
+ StatsInterface& operator=(StatsInterface&&) = delete;
+
+ virtual ~StatsInterface() = default;
+
+ virtual void OnPacketRead() = 0;
+ virtual void OnPacketWritten() = 0;
+ virtual void OnReadError(string* error) = 0;
+ virtual void OnWriteError(string* error) = 0;
+ };
+
+ // |fd| is a open file descriptor on a TUN device that's opened for both read
+ // and write.
+ // |mtu| is the mtu of the TUN device.
+ // |kernel| is not owned but should out live objects of this class.
+ // |visitor| is not owned but should out live objects of this class.
+ // |max_pending_packets| controls the number of packets to be queued should
+ // 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(int fd,
+ size_t mtu,
+ KernelInterface* kernel,
+ QbonePacketExchanger::Visitor* visitor,
+ size_t max_pending_packets,
+ StatsInterface* stats);
+
+ int file_descriptor() const;
+
+ private:
+ // From QbonePacketExchanger.
+ std::unique_ptr<QuicData> ReadPacket(bool* blocked, string* error) override;
+
+ // From QbonePacketExchanger.
+ bool WritePacket(const char* packet,
+ size_t size,
+ bool* blocked,
+ string* error) override;
+
+ int fd_ = -1;
+ size_t mtu_;
+ KernelInterface* kernel_;
+
+ StatsInterface* stats_;
+};
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_QBONE_BONNET_TUN_DEVICE_PACKET_EXCHANGER_H_
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
new file mode 100644
index 00000000000..026ec26da5e
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger_test.cc
@@ -0,0 +1,128 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger.h"
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+#include "net/third_party/quiche/src/quic/qbone/mock_qbone_client.h"
+#include "net/third_party/quiche/src/quic/qbone/platform/mock_kernel.h"
+
+namespace quic {
+namespace {
+
+const size_t kMtu = 1000;
+const size_t kMaxPendingPackets = 5;
+const int kFd = 15;
+
+using ::testing::_;
+using ::testing::Invoke;
+using ::testing::StrEq;
+using ::testing::StrictMock;
+
+class MockVisitor : public QbonePacketExchanger::Visitor {
+ public:
+ MOCK_METHOD1(OnReadError, void(const string&));
+ MOCK_METHOD1(OnWriteError, void(const string&));
+};
+
+class MockStatsInterface : public TunDevicePacketExchanger::StatsInterface {
+ public:
+ MOCK_METHOD0(OnPacketRead, void());
+ MOCK_METHOD0(OnPacketWritten, void());
+
+ MOCK_METHOD1(OnReadError, void(string*));
+ MOCK_METHOD1(OnWriteError, void(string*));
+};
+
+class TunDevicePacketExchangerTest : public QuicTest {
+ protected:
+ TunDevicePacketExchangerTest()
+ : exchanger_(kFd,
+ kMtu,
+ &mock_kernel_,
+ &mock_visitor_,
+ kMaxPendingPackets,
+ &mock_stats_) {}
+
+ ~TunDevicePacketExchangerTest() override {}
+
+ MockKernel mock_kernel_;
+ StrictMock<MockVisitor> mock_visitor_;
+ StrictMock<MockQboneClient> mock_client_;
+ StrictMock<MockStatsInterface> mock_stats_;
+ TunDevicePacketExchanger exchanger_;
+};
+
+TEST_F(TunDevicePacketExchangerTest, WritePacketReturnsFalseOnError) {
+ string packet = "fake packet";
+ EXPECT_CALL(mock_kernel_, write(kFd, _, packet.size()))
+ .WillOnce(Invoke([](int fd, const void* buf, size_t count) {
+ errno = ECOMM;
+ return -1;
+ }));
+
+ EXPECT_CALL(mock_visitor_, OnWriteError(_));
+ exchanger_.WritePacketToNetwork(packet.data(), packet.size());
+}
+
+TEST_F(TunDevicePacketExchangerTest,
+ WritePacketReturnFalseAndBlockedOnBlockedTunnel) {
+ string packet = "fake packet";
+ EXPECT_CALL(mock_kernel_, write(kFd, _, packet.size()))
+ .WillOnce(Invoke([](int fd, const void* buf, size_t count) {
+ errno = EAGAIN;
+ return -1;
+ }));
+
+ EXPECT_CALL(mock_stats_, OnWriteError(_)).Times(1);
+ exchanger_.WritePacketToNetwork(packet.data(), packet.size());
+}
+
+TEST_F(TunDevicePacketExchangerTest, WritePacketReturnsTrueOnSuccessfulWrite) {
+ string packet = "fake packet";
+ EXPECT_CALL(mock_kernel_, write(kFd, _, packet.size()))
+ .WillOnce(Invoke([packet](int fd, const void* buf, size_t count) {
+ EXPECT_THAT(reinterpret_cast<const char*>(buf), StrEq(packet));
+ return count;
+ }));
+
+ EXPECT_CALL(mock_stats_, OnPacketWritten()).Times(1);
+ exchanger_.WritePacketToNetwork(packet.data(), packet.size());
+}
+
+TEST_F(TunDevicePacketExchangerTest, ReadPacketReturnsNullOnError) {
+ EXPECT_CALL(mock_kernel_, read(kFd, _, kMtu))
+ .WillOnce(Invoke([](int fd, void* buf, size_t count) {
+ errno = ECOMM;
+ return -1;
+ }));
+ EXPECT_CALL(mock_visitor_, OnReadError(_));
+ exchanger_.ReadAndDeliverPacket(&mock_client_);
+}
+
+TEST_F(TunDevicePacketExchangerTest, ReadPacketReturnsNullOnBlockedRead) {
+ EXPECT_CALL(mock_kernel_, read(kFd, _, kMtu))
+ .WillOnce(Invoke([](int fd, void* buf, size_t count) {
+ errno = EAGAIN;
+ return -1;
+ }));
+ EXPECT_CALL(mock_stats_, OnReadError(_)).Times(1);
+ EXPECT_FALSE(exchanger_.ReadAndDeliverPacket(&mock_client_));
+}
+
+TEST_F(TunDevicePacketExchangerTest,
+ ReadPacketReturnsThePacketOnSuccessfulRead) {
+ string packet = "fake_packet";
+ EXPECT_CALL(mock_kernel_, read(kFd, _, kMtu))
+ .WillOnce(Invoke([packet](int fd, void* buf, size_t count) {
+ memcpy(buf, packet.data(), packet.size());
+ return packet.size();
+ }));
+ EXPECT_CALL(mock_client_, ProcessPacketFromNetwork(StrEq(packet)));
+ EXPECT_CALL(mock_stats_, OnPacketRead()).Times(1);
+ EXPECT_TRUE(exchanger_.ReadAndDeliverPacket(&mock_client_));
+}
+
+} // namespace
+} // namespace quic
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
new file mode 100644
index 00000000000..e9ae4d336e7
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_test.cc
@@ -0,0 +1,208 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/qbone/bonnet/tun_device.h"
+
+#include <linux/if.h>
+#include <linux/if_tun.h>
+#include <sys/ioctl.h>
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+#include "net/third_party/quiche/src/quic/qbone/platform/mock_kernel.h"
+
+namespace quic {
+namespace {
+
+using ::testing::_;
+using ::testing::AnyNumber;
+using ::testing::Invoke;
+using ::testing::Return;
+using ::testing::StrEq;
+using ::testing::Unused;
+
+const char kDeviceName[] = "tun0";
+const int kSupportedFeatures =
+ IFF_TUN | IFF_TAP | IFF_MULTI_QUEUE | IFF_ONE_QUEUE | IFF_NO_PI;
+
+// Quite a bit of EXPECT_CALL().Times(AnyNumber()).WillRepeatedly() are used to
+// make sure we can correctly set common expectations and override the
+// expectation with later call to EXPECT_CALL(). ON_CALL cannot be used here
+// since when EPXECT_CALL overrides ON_CALL, it ignores the parameter matcher
+// which results in unexpected call even if ON_CALL exists.
+class TunDeviceTest : public QuicTest {
+ protected:
+ void SetUp() override {
+ EXPECT_CALL(mock_kernel_, socket(AF_INET6, _, _))
+ .Times(AnyNumber())
+ .WillRepeatedly(Invoke([this](Unused, Unused, Unused) {
+ EXPECT_CALL(mock_kernel_, close(next_fd_)).WillOnce(Return(0));
+ return next_fd_++;
+ }));
+ }
+
+ // Set the expectations for calling Init().
+ void SetInitExpectations(int mtu, bool persist) {
+ EXPECT_CALL(mock_kernel_, open(StrEq("/dev/net/tun"), _))
+ .Times(AnyNumber())
+ .WillRepeatedly(Invoke([this](Unused, Unused) {
+ EXPECT_CALL(mock_kernel_, close(next_fd_)).WillOnce(Return(0));
+ return next_fd_++;
+ }));
+ EXPECT_CALL(mock_kernel_, ioctl(_, TUNGETFEATURES, _))
+ .Times(AnyNumber())
+ .WillRepeatedly(Invoke([](Unused, Unused, void* argp) {
+ auto* actual_flags = reinterpret_cast<int*>(argp);
+ *actual_flags = kSupportedFeatures;
+ return 0;
+ }));
+ EXPECT_CALL(mock_kernel_, ioctl(_, TUNSETIFF, _))
+ .Times(AnyNumber())
+ .WillRepeatedly(Invoke([](Unused, Unused, void* argp) {
+ auto* ifr = reinterpret_cast<struct ifreq*>(argp);
+ EXPECT_EQ(IFF_TUN | IFF_MULTI_QUEUE | IFF_NO_PI, ifr->ifr_flags);
+ EXPECT_THAT(ifr->ifr_name, StrEq(kDeviceName));
+ return 0;
+ }));
+ EXPECT_CALL(mock_kernel_, ioctl(_, TUNSETPERSIST, _))
+ .Times(AnyNumber())
+ .WillRepeatedly(Invoke([persist](Unused, Unused, void* argp) {
+ auto* ifr = reinterpret_cast<struct ifreq*>(argp);
+ if (persist) {
+ EXPECT_THAT(ifr->ifr_name, StrEq(kDeviceName));
+ } else {
+ EXPECT_EQ(nullptr, ifr);
+ }
+ return 0;
+ }));
+ EXPECT_CALL(mock_kernel_, ioctl(_, SIOCSIFMTU, _))
+ .Times(AnyNumber())
+ .WillRepeatedly(Invoke([mtu](Unused, Unused, void* argp) {
+ auto* ifr = reinterpret_cast<struct ifreq*>(argp);
+ EXPECT_EQ(mtu, ifr->ifr_mtu);
+ EXPECT_THAT(ifr->ifr_name, StrEq(kDeviceName));
+ return 0;
+ }));
+ }
+
+ // Expect that Up() will be called. Force the call to fail when fail == true.
+ void ExpectUp(bool fail) {
+ EXPECT_CALL(mock_kernel_, ioctl(_, SIOCSIFFLAGS, _))
+ .WillOnce(Invoke([fail](Unused, Unused, void* argp) {
+ auto* ifr = reinterpret_cast<struct ifreq*>(argp);
+ EXPECT_TRUE(ifr->ifr_flags & IFF_UP);
+ EXPECT_THAT(ifr->ifr_name, StrEq(kDeviceName));
+ if (fail) {
+ return -1;
+ } else {
+ return 0;
+ }
+ }));
+ }
+
+ // Expect that Down() will be called *after* the interface is up. Force the
+ // call to fail when fail == true.
+ void ExpectDown(bool fail) {
+ EXPECT_CALL(mock_kernel_, ioctl(_, SIOCSIFFLAGS, _))
+ .WillOnce(Invoke([fail](Unused, Unused, void* argp) {
+ auto* ifr = reinterpret_cast<struct ifreq*>(argp);
+ EXPECT_FALSE(ifr->ifr_flags & IFF_UP);
+ EXPECT_THAT(ifr->ifr_name, StrEq(kDeviceName));
+ if (fail) {
+ return -1;
+ } else {
+ return 0;
+ }
+ }));
+ }
+
+ MockKernel mock_kernel_;
+ int next_fd_ = 100;
+};
+
+// A TunDevice can be initialized and up
+TEST_F(TunDeviceTest, BasicWorkFlow) {
+ SetInitExpectations(/* mtu = */ 1500, /* persist = */ false);
+ TunDevice tun_device(kDeviceName, 1500, false, &mock_kernel_);
+ EXPECT_TRUE(tun_device.Init());
+ EXPECT_GT(tun_device.GetFileDescriptor(), -1);
+
+ ExpectUp(/* fail = */ false);
+ EXPECT_TRUE(tun_device.Up());
+ ExpectDown(/* fail = */ false);
+}
+
+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, &mock_kernel_);
+ EXPECT_FALSE(tun_device.Init());
+ EXPECT_EQ(tun_device.GetFileDescriptor(), -1);
+}
+
+TEST_F(TunDeviceTest, FailToCheckFeature) {
+ SetInitExpectations(/* mtu = */ 1500, /* persist = */ false);
+ EXPECT_CALL(mock_kernel_, ioctl(_, TUNGETFEATURES, _)).WillOnce(Return(-1));
+ TunDevice tun_device(kDeviceName, 1500, false, &mock_kernel_);
+ EXPECT_FALSE(tun_device.Init());
+ EXPECT_EQ(tun_device.GetFileDescriptor(), -1);
+}
+
+TEST_F(TunDeviceTest, TooFewFeature) {
+ SetInitExpectations(/* mtu = */ 1500, /* persist = */ false);
+ EXPECT_CALL(mock_kernel_, ioctl(_, TUNGETFEATURES, _))
+ .WillOnce(Invoke([](Unused, Unused, void* argp) {
+ int* actual_features = reinterpret_cast<int*>(argp);
+ *actual_features = IFF_TUN | IFF_ONE_QUEUE;
+ return 0;
+ }));
+ TunDevice tun_device(kDeviceName, 1500, false, &mock_kernel_);
+ EXPECT_FALSE(tun_device.Init());
+ EXPECT_EQ(tun_device.GetFileDescriptor(), -1);
+}
+
+TEST_F(TunDeviceTest, FailToSetFlag) {
+ SetInitExpectations(/* mtu = */ 1500, /* persist = */ true);
+ EXPECT_CALL(mock_kernel_, ioctl(_, TUNSETIFF, _)).WillOnce(Return(-1));
+ TunDevice tun_device(kDeviceName, 1500, true, &mock_kernel_);
+ EXPECT_FALSE(tun_device.Init());
+ EXPECT_EQ(tun_device.GetFileDescriptor(), -1);
+}
+
+TEST_F(TunDeviceTest, FailToPersistDevice) {
+ SetInitExpectations(/* mtu = */ 1500, /* persist = */ true);
+ EXPECT_CALL(mock_kernel_, ioctl(_, TUNSETPERSIST, _)).WillOnce(Return(-1));
+ TunDevice tun_device(kDeviceName, 1500, true, &mock_kernel_);
+ EXPECT_FALSE(tun_device.Init());
+ EXPECT_EQ(tun_device.GetFileDescriptor(), -1);
+}
+
+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, &mock_kernel_);
+ EXPECT_FALSE(tun_device.Init());
+ EXPECT_EQ(tun_device.GetFileDescriptor(), -1);
+}
+
+TEST_F(TunDeviceTest, FailToSetMtu) {
+ SetInitExpectations(/* mtu = */ 1500, /* persist = */ true);
+ EXPECT_CALL(mock_kernel_, ioctl(_, SIOCSIFMTU, _)).WillOnce(Return(-1));
+ TunDevice tun_device(kDeviceName, 1500, true, &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, &mock_kernel_);
+ EXPECT_TRUE(tun_device.Init());
+ EXPECT_GT(tun_device.GetFileDescriptor(), -1);
+
+ ExpectUp(/* fail = */ true);
+ EXPECT_FALSE(tun_device.Up());
+}
+
+} // namespace
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/mock_qbone_client.h b/chromium/net/third_party/quiche/src/quic/qbone/mock_qbone_client.h
new file mode 100644
index 00000000000..37df26d5f49
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/mock_qbone_client.h
@@ -0,0 +1,20 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_QBONE_MOCK_QBONE_CLIENT_H_
+#define QUICHE_QUIC_QBONE_MOCK_QBONE_CLIENT_H_
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+#include "net/third_party/quiche/src/quic/qbone/qbone_client_interface.h"
+
+namespace quic {
+
+class MockQboneClient : public QboneClientInterface {
+ public:
+ MOCK_METHOD1(ProcessPacketFromNetwork, void(QuicStringPiece packet));
+};
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_QBONE_MOCK_QBONE_CLIENT_H_
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/mock_qbone_server_session.h b/chromium/net/third_party/quiche/src/quic/qbone/mock_qbone_server_session.h
new file mode 100644
index 00000000000..652c017f64c
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/mock_qbone_server_session.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_QBONE_MOCK_QBONE_SERVER_SESSION_H_
+#define QUICHE_QUIC_QBONE_MOCK_QBONE_SERVER_SESSION_H_
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+#include "net/third_party/quiche/src/quic/qbone/qbone_server_session.h"
+
+namespace quic {
+
+class MockQboneServerSession : public QboneServerSession {
+ public:
+ explicit MockQboneServerSession(QuicConnection* connection)
+ : QboneServerSession(CurrentSupportedVersions(),
+ connection,
+ /*owner=*/nullptr,
+ /*config=*/{},
+ /*quic_crypto_server_config=*/nullptr,
+ /*compressed_certs_cache=*/nullptr,
+ /*writer=*/nullptr,
+ /*self_ip=*/QuicIpAddress::Loopback6(),
+ /*client_ip=*/QuicIpAddress::Loopback6(),
+ /*client_ip_subnet_length=*/0,
+ /*handler=*/nullptr) {}
+
+ MOCK_METHOD1(SendClientRequest, bool(const QboneClientRequest&));
+
+ MOCK_METHOD1(ProcessPacketFromNetwork, void(QuicStringPiece));
+ MOCK_METHOD1(ProcessPacketFromPeer, void(QuicStringPiece));
+};
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_QBONE_MOCK_QBONE_SERVER_SESSION_H_
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
new file mode 100644
index 00000000000..8ba3916b951
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/platform/icmp_packet.cc
@@ -0,0 +1,84 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/qbone/platform/icmp_packet.h"
+
+#include <netinet/ip6.h>
+#include "net/third_party/quiche/src/quic/platform/api/quic_endian.h"
+#include "net/third_party/quiche/src/quic/qbone/platform/internet_checksum.h"
+
+namespace quic {
+namespace {
+
+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;
+constexpr size_t kICMPv6BodyMaxSize =
+ kIPv6MinPacketSize - kIPv6HeaderSize - kICMPv6HeaderSize;
+
+struct ICMPv6Packet {
+ ip6_hdr ip_header;
+ icmp6_hdr icmp_header;
+ uint8_t body[kICMPv6BodyMaxSize];
+};
+
+// pseudo header as described in RFC 2460 Section 8.1 (excluding addresses)
+struct IPv6PseudoHeader {
+ uint32_t payload_size{};
+ uint8_t zeros[3] = {0, 0, 0};
+ uint8_t next_header = IPPROTO_ICMPV6;
+};
+
+} // namespace
+
+void CreateIcmpPacket(in6_addr src,
+ in6_addr dst,
+ const icmp6_hdr& icmp_header,
+ QuicStringPiece body,
+ const std::function<void(QuicStringPiece)>& cb) {
+ const size_t body_size = std::min(body.size(), kICMPv6BodyMaxSize);
+ const size_t payload_size = kICMPv6HeaderSize + body_size;
+
+ ICMPv6Packet icmp_packet{};
+ // Set version to 6.
+ icmp_packet.ip_header.ip6_vfc = 0x6 << 4;
+ // Set the payload size, protocol and TTL.
+ icmp_packet.ip_header.ip6_plen = QuicEndian::HostToNet16(payload_size);
+ icmp_packet.ip_header.ip6_nxt = IPPROTO_ICMPV6;
+ icmp_packet.ip_header.ip6_hops = kIcmpTtl;
+ // Set the source address to the specified self IP.
+ icmp_packet.ip_header.ip6_src = src;
+ icmp_packet.ip_header.ip6_dst = dst;
+
+ icmp_packet.icmp_header = icmp_header;
+ // Per RFC 4443 Section 2.3, set checksum field to 0 prior to computing it
+ icmp_packet.icmp_header.icmp6_cksum = 0;
+
+ IPv6PseudoHeader pseudo_header{};
+ pseudo_header.payload_size = QuicEndian::HostToNet32(payload_size);
+
+ InternetChecksum checksum;
+ // Pseudoheader.
+ checksum.Update(icmp_packet.ip_header.ip6_src.s6_addr, kIPv6AddressSize);
+ checksum.Update(icmp_packet.ip_header.ip6_dst.s6_addr, kIPv6AddressSize);
+ checksum.Update(reinterpret_cast<char*>(&pseudo_header),
+ sizeof(pseudo_header));
+ // ICMP header.
+ checksum.Update(reinterpret_cast<const char*>(&icmp_packet.icmp_header),
+ sizeof(icmp_packet.icmp_header));
+ // Body.
+ checksum.Update(body.data(), body_size);
+ icmp_packet.icmp_header.icmp6_cksum = checksum.Value();
+
+ memcpy(icmp_packet.body, body.data(), body_size);
+
+ const char* packet = reinterpret_cast<char*>(&icmp_packet);
+ const size_t packet_size = offsetof(ICMPv6Packet, body) + body_size;
+
+ cb(QuicStringPiece(packet, packet_size));
+}
+
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/platform/icmp_packet.h b/chromium/net/third_party/quiche/src/quic/qbone/platform/icmp_packet.h
new file mode 100644
index 00000000000..ae440d2901a
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/platform/icmp_packet.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_QBONE_PLATFORM_ICMP_PACKET_H_
+#define QUICHE_QUIC_QBONE_PLATFORM_ICMP_PACKET_H_
+
+#include <netinet/icmp6.h>
+#include <netinet/in.h>
+
+#include <functional>
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
+
+namespace quic {
+
+// Creates an ICMPv6 packet, returning a packed string representation of the
+// packet to |cb|. The resulting packet is given to a callback because it's
+// stack allocated inside CreateIcmpPacket.
+void CreateIcmpPacket(in6_addr src,
+ in6_addr dst,
+ const icmp6_hdr& icmp_header,
+ quic::QuicStringPiece body,
+ const std::function<void(quic::QuicStringPiece)>& cb);
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_QBONE_PLATFORM_ICMP_PACKET_H_
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
new file mode 100644
index 00000000000..1aeabe08570
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/platform/icmp_packet_test.cc
@@ -0,0 +1,127 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/qbone/platform/icmp_packet.h"
+
+#include <netinet/ip6.h>
+
+#include <cstdint>
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
+
+namespace quic {
+namespace {
+
+constexpr char kReferenceSourceAddress[] = "fe80:1:2:3:4::1";
+constexpr char kReferenceDestinationAddress[] = "fe80:4:3:2:1::1";
+
+// clang-format off
+constexpr uint8_t kReferenceICMPMessageBody[] {
+ 0xd2, 0x61, 0x29, 0x5b, 0x00, 0x00, 0x00, 0x00,
+ 0x0d, 0x59, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37
+};
+
+constexpr uint8_t kReferenceICMPPacket[] = {
+ // START IPv6 Header
+ // IPv6 with zero TOS and flow label.
+ 0x60, 0x00, 0x00, 0x00,
+ // Payload is 64 bytes
+ 0x00, 0x40,
+ // Next header is 58
+ 0x3a,
+ // Hop limit is 64
+ 0x40,
+ // 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,
+ // Destination address of fe80:4:3:2:1::1
+ 0xfe, 0x80, 0x00, 0x04, 0x00, 0x03, 0x00, 0x02,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ // END IPv6 Header
+ // START ICMPv6 Header
+ // Echo Request, zero code
+ 0x80, 0x00,
+ // Checksum
+ 0xec, 0x00,
+ // Identifier
+ 0xcb, 0x82,
+ // Sequence Number
+ 0x00, 0x01,
+ // END ICMPv6 Header
+ // Message body
+ 0xd2, 0x61, 0x29, 0x5b, 0x00, 0x00, 0x00, 0x00,
+ 0x0d, 0x59, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37
+};
+// clang-format on
+
+} // namespace
+
+TEST(IcmpPacketTest, CreatedPacketMatchesReference) {
+ QuicIpAddress src;
+ ASSERT_TRUE(src.FromString(kReferenceSourceAddress));
+ in6_addr src_addr;
+ memcpy(src_addr.s6_addr, src.ToPackedString().data(), sizeof(in6_addr));
+
+ QuicIpAddress dst;
+ ASSERT_TRUE(dst.FromString(kReferenceDestinationAddress));
+ in6_addr dst_addr;
+ memcpy(dst_addr.s6_addr, dst.ToPackedString().data(), sizeof(in6_addr));
+
+ icmp6_hdr icmp_header{};
+ icmp_header.icmp6_type = ICMP6_ECHO_REQUEST;
+ icmp_header.icmp6_id = 0x82cb;
+ icmp_header.icmp6_seq = 0x0100;
+
+ QuicStringPiece message_body = QuicStringPiece(
+ reinterpret_cast<const char*>(kReferenceICMPMessageBody), 56);
+ QuicStringPiece expected_packet =
+ QuicStringPiece(reinterpret_cast<const char*>(kReferenceICMPPacket), 104);
+ CreateIcmpPacket(src_addr, dst_addr, icmp_header, message_body,
+ [&expected_packet](QuicStringPiece packet) {
+ QUIC_LOG(INFO) << QuicTextUtils::HexDump(packet);
+ ASSERT_EQ(packet, expected_packet);
+ });
+}
+
+TEST(IcmpPacketTest, NonZeroChecksumIsIgnored) {
+ QuicIpAddress src;
+ ASSERT_TRUE(src.FromString(kReferenceSourceAddress));
+ in6_addr src_addr;
+ memcpy(src_addr.s6_addr, src.ToPackedString().data(), sizeof(in6_addr));
+
+ QuicIpAddress dst;
+ ASSERT_TRUE(dst.FromString(kReferenceDestinationAddress));
+ in6_addr dst_addr;
+ memcpy(dst_addr.s6_addr, dst.ToPackedString().data(), sizeof(in6_addr));
+
+ icmp6_hdr icmp_header{};
+ icmp_header.icmp6_type = ICMP6_ECHO_REQUEST;
+ icmp_header.icmp6_id = 0x82cb;
+ icmp_header.icmp6_seq = 0x0100;
+ // Set the checksum to a bogus value
+ icmp_header.icmp6_cksum = 0x1234;
+
+ QuicStringPiece message_body = QuicStringPiece(
+ reinterpret_cast<const char*>(kReferenceICMPMessageBody), 56);
+ QuicStringPiece expected_packet =
+ QuicStringPiece(reinterpret_cast<const char*>(kReferenceICMPPacket), 104);
+ CreateIcmpPacket(src_addr, dst_addr, icmp_header, message_body,
+ [&expected_packet](QuicStringPiece packet) {
+ QUIC_LOG(INFO) << QuicTextUtils::HexDump(packet);
+ ASSERT_EQ(packet, expected_packet);
+ });
+}
+
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/platform/internet_checksum.cc b/chromium/net/third_party/quiche/src/quic/qbone/platform/internet_checksum.cc
new file mode 100644
index 00000000000..9cbe227abdc
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/platform/internet_checksum.cc
@@ -0,0 +1,32 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/qbone/platform/internet_checksum.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_endian.h"
+
+namespace quic {
+
+void InternetChecksum::Update(const char* data, size_t size) {
+ const char* current;
+ for (current = data; current + 1 < data + size; current += 2) {
+ accumulator_ += *reinterpret_cast<const uint16_t*>(current);
+ }
+ if (current < data + size) {
+ accumulator_ += *reinterpret_cast<const uint8_t*>(current);
+ }
+}
+
+void InternetChecksum::Update(const uint8_t* data, size_t size) {
+ Update(reinterpret_cast<const char*>(data), size);
+}
+
+uint16_t InternetChecksum::Value() const {
+ uint32_t total = accumulator_;
+ while (total & 0xffff0000u) {
+ total = (total >> 16u) + (total & 0xffffu);
+ }
+ return ~static_cast<uint16_t>(total);
+}
+
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/platform/internet_checksum.h b/chromium/net/third_party/quiche/src/quic/qbone/platform/internet_checksum.h
new file mode 100644
index 00000000000..85d24155f29
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/platform/internet_checksum.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_QBONE_PLATFORM_INTERNET_CHECKSUM_H_
+#define QUICHE_QUIC_QBONE_PLATFORM_INTERNET_CHECKSUM_H_
+
+#include <cstddef>
+#include <cstdint>
+
+namespace quic {
+
+// Incrementally compute an Internet header checksum as described in RFC 1071.
+class InternetChecksum {
+ public:
+ // Update the checksum with the specified data. Note that while the checksum
+ // is commutative, the data has to be supplied in the units of two-byte words.
+ // If there is an extra byte at the end, the function has to be called on it
+ // last.
+ void Update(const char* data, size_t size);
+
+ void Update(const uint8_t* data, size_t size);
+
+ uint16_t Value() const;
+
+ private:
+ uint32_t accumulator_ = 0;
+};
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_QBONE_PLATFORM_INTERNET_CHECKSUM_H_
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/platform/internet_checksum_test.cc b/chromium/net/third_party/quiche/src/quic/qbone/platform/internet_checksum_test.cc
new file mode 100644
index 00000000000..a4736e2c183
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/platform/internet_checksum_test.cc
@@ -0,0 +1,67 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/qbone/platform/internet_checksum.h"
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+
+namespace quic {
+namespace {
+
+// From the Numerical Example described in RFC 1071
+// https://tools.ietf.org/html/rfc1071#section-3
+TEST(InternetChecksumTest, MatchesRFC1071Example) {
+ uint8_t data[] = {0x00, 0x01, 0xf2, 0x03, 0xf4, 0xf5, 0xf6, 0xf7};
+
+ InternetChecksum checksum;
+ checksum.Update(data, 8);
+ uint16_t result = checksum.Value();
+ auto* result_bytes = reinterpret_cast<uint8_t*>(&result);
+ ASSERT_EQ(0x22, result_bytes[0]);
+ ASSERT_EQ(0x0d, result_bytes[1]);
+}
+
+// Same as above, except 7 bytes. Should behave as if there was an 8th byte
+// that equals 0.
+TEST(InternetChecksumTest, MatchesRFC1071ExampleWithOddByteCount) {
+ uint8_t data[] = {0x00, 0x01, 0xf2, 0x03, 0xf4, 0xf5, 0xf6};
+
+ InternetChecksum checksum;
+ checksum.Update(data, 7);
+ uint16_t result = checksum.Value();
+ auto* result_bytes = reinterpret_cast<uint8_t*>(&result);
+ ASSERT_EQ(0x23, result_bytes[0]);
+ ASSERT_EQ(0x04, result_bytes[1]);
+}
+
+// From the example described at:
+// http://www.cs.berkeley.edu/~kfall/EE122/lec06/tsld023.htm
+TEST(InternetChecksumTest, MatchesBerkleyExample) {
+ uint8_t data[] = {0xe3, 0x4f, 0x23, 0x96, 0x44, 0x27, 0x99, 0xf3};
+
+ InternetChecksum checksum;
+ checksum.Update(data, 8);
+ uint16_t result = checksum.Value();
+ auto* result_bytes = reinterpret_cast<uint8_t*>(&result);
+ ASSERT_EQ(0x1a, result_bytes[0]);
+ ASSERT_EQ(0xff, result_bytes[1]);
+}
+
+TEST(InternetChecksumTest, ChecksumRequiringMultipleCarriesInLittleEndian) {
+ uint8_t data[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x02, 0x00};
+
+ // Data will accumulate to 0x0002FFFF
+ // Summing lower and upper halves gives 0x00010001
+ // Second sum of lower and upper halves gives 0x0002
+ // One's complement gives 0xfffd, or [0xfd, 0xff] in network byte order
+ InternetChecksum checksum;
+ checksum.Update(data, 8);
+ uint16_t result = checksum.Value();
+ auto* result_bytes = reinterpret_cast<uint8_t*>(&result);
+ EXPECT_EQ(0xfd, result_bytes[0]);
+ EXPECT_EQ(0xff, result_bytes[1]);
+}
+
+} // namespace
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/platform/ip_range.cc b/chromium/net/third_party/quiche/src/quic/qbone/platform/ip_range.cc
new file mode 100644
index 00000000000..15ebb726b86
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/platform/ip_range.cc
@@ -0,0 +1,101 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/qbone/platform/ip_range.h"
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_endian.h"
+
+namespace quic {
+
+namespace {
+
+constexpr size_t kIPv4Size = 32;
+constexpr size_t kIPv6Size = 128;
+
+QuicIpAddress TruncateToLength(const QuicIpAddress& input,
+ size_t* prefix_length) {
+ QuicIpAddress output;
+ if (input.IsIPv4()) {
+ if (*prefix_length > kIPv4Size) {
+ *prefix_length = kIPv4Size;
+ return input;
+ }
+ uint32_t raw_address =
+ *reinterpret_cast<const uint32_t*>(input.ToPackedString().data());
+ raw_address = QuicEndian::NetToHost32(raw_address);
+ raw_address &= ~0U << (kIPv4Size - *prefix_length);
+ raw_address = QuicEndian::HostToNet32(raw_address);
+ output.FromPackedString(reinterpret_cast<const char*>(&raw_address),
+ sizeof(raw_address));
+ return output;
+ }
+ if (input.IsIPv6()) {
+ if (*prefix_length > kIPv6Size) {
+ *prefix_length = kIPv6Size;
+ return input;
+ }
+ uint64_t raw_address[2];
+ memcpy(raw_address, input.ToPackedString().data(), sizeof(raw_address));
+ // raw_address[0] holds higher 8 bytes in big endian and raw_address[1]
+ // holds lower 8 bytes. Converting each to little endian for us to mask bits
+ // out.
+ // The endianess between raw_address[0] and raw_address[1] is handled
+ // explicitly by handling lower and higher bytes separately.
+ raw_address[0] = QuicEndian::NetToHost64(raw_address[0]);
+ raw_address[1] = QuicEndian::NetToHost64(raw_address[1]);
+ if (*prefix_length <= kIPv6Size / 2) {
+ raw_address[0] &= ~uint64_t{0} << (kIPv6Size / 2 - *prefix_length);
+ raw_address[1] = 0;
+ } else {
+ raw_address[1] &= ~uint64_t{0} << (kIPv6Size - *prefix_length);
+ }
+ raw_address[0] = QuicEndian::HostToNet64(raw_address[0]);
+ raw_address[1] = QuicEndian::HostToNet64(raw_address[1]);
+ output.FromPackedString(reinterpret_cast<const char*>(raw_address),
+ sizeof(raw_address));
+ return output;
+ }
+ return output;
+}
+
+} // namespace
+
+IpRange::IpRange(const QuicIpAddress& prefix, size_t prefix_length)
+ : prefix_(prefix), prefix_length_(prefix_length) {
+ prefix_ = TruncateToLength(prefix_, &prefix_length_);
+}
+
+bool IpRange::operator==(IpRange other) const {
+ return prefix_ == other.prefix_ && prefix_length_ == other.prefix_length_;
+}
+
+bool IpRange::operator!=(IpRange other) const {
+ return !(*this == other);
+}
+
+bool IpRange::FromString(const string& range) {
+ size_t slash_pos = range.find('/');
+ if (slash_pos == string::npos) {
+ return false;
+ }
+ QuicIpAddress prefix;
+ bool success = prefix.FromString(range.substr(0, slash_pos));
+ if (!success) {
+ return false;
+ }
+ uint64_t num_processed = 0;
+ size_t prefix_length = std::stoi(range.substr(slash_pos + 1), &num_processed);
+ if (num_processed + 1 + slash_pos != range.length()) {
+ return false;
+ }
+ prefix_ = TruncateToLength(prefix, &prefix_length);
+ prefix_length_ = prefix_length;
+ return true;
+}
+
+QuicIpAddress IpRange::FirstAddressInRange() {
+ return prefix();
+}
+
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/platform/ip_range.h b/chromium/net/third_party/quiche/src/quic/qbone/platform/ip_range.h
new file mode 100644
index 00000000000..545c32c6cb9
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/platform/ip_range.h
@@ -0,0 +1,60 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_QBONE_PLATFORM_IP_RANGE_H_
+#define QUICHE_QUIC_QBONE_PLATFORM_IP_RANGE_H_
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h"
+
+namespace quic {
+
+class IpRange {
+ public:
+ // Default constructor to have an uninitialized IpRange.
+ IpRange() : prefix_length_(0) {}
+
+ // prefix will be automatically truncated to prefix_length, so that any bit
+ // after prefix_length are zero.
+ IpRange(const QuicIpAddress& prefix, size_t prefix_length);
+
+ bool operator==(IpRange other) const;
+ bool operator!=(IpRange other) const;
+
+ // Parses range that looks like "10.0.0.1/8". Tailing bits will be set to zero
+ // after prefix_length. Return false if the parsing failed.
+ bool FromString(const string& range);
+
+ // Returns the string representation of this object.
+ string ToString() const {
+ if (IsInitialized()) {
+ return absl::StrCat(prefix_.ToString(), "/", prefix_length_);
+ }
+ return "(uninitialized)";
+ }
+
+ // Whether this object is initialized.
+ bool IsInitialized() const { return prefix_.IsInitialized(); }
+
+ // Returns the first available IP address in this IpRange. The resulting
+ // address will be uninitialized if there is no available address.
+ QuicIpAddress FirstAddressInRange();
+
+ // The address family of this IpRange.
+ IpAddressFamily address_family() const { return prefix_.address_family(); }
+
+ // The subnet's prefix address.
+ QuicIpAddress prefix() const { return prefix_; }
+
+ // The subnet's prefix length.
+ size_t prefix_length() const { return prefix_length_; }
+
+ private:
+ QuicIpAddress prefix_;
+ size_t prefix_length_;
+};
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_QBONE_PLATFORM_IP_RANGE_H_
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/platform/ip_range_test.cc b/chromium/net/third_party/quiche/src/quic/qbone/platform/ip_range_test.cc
new file mode 100644
index 00000000000..bac5c963af8
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/platform/ip_range_test.cc
@@ -0,0 +1,65 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/qbone/platform/ip_range.h"
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+
+namespace quic {
+namespace {
+
+TEST(IpRangeTest, TruncateWorksIPv4) {
+ QuicIpAddress before_truncate;
+ before_truncate.FromString("255.255.255.255");
+ EXPECT_EQ("128.0.0.0/1", IpRange(before_truncate, 1).ToString());
+ EXPECT_EQ("192.0.0.0/2", IpRange(before_truncate, 2).ToString());
+ EXPECT_EQ("255.224.0.0/11", IpRange(before_truncate, 11).ToString());
+ EXPECT_EQ("255.255.255.224/27", IpRange(before_truncate, 27).ToString());
+ EXPECT_EQ("255.255.255.254/31", IpRange(before_truncate, 31).ToString());
+ EXPECT_EQ("255.255.255.255/32", IpRange(before_truncate, 32).ToString());
+ EXPECT_EQ("255.255.255.255/32", IpRange(before_truncate, 33).ToString());
+}
+
+TEST(IpRangeTest, TruncateWorksIPv6) {
+ QuicIpAddress before_truncate;
+ before_truncate.FromString("ffff:ffff:ffff:ffff:f903::5");
+ EXPECT_EQ("fe00::/7", IpRange(before_truncate, 7).ToString());
+ EXPECT_EQ("ffff:ffff:ffff::/48", IpRange(before_truncate, 48).ToString());
+ EXPECT_EQ("ffff:ffff:ffff:ffff::/64",
+ IpRange(before_truncate, 64).ToString());
+ EXPECT_EQ("ffff:ffff:ffff:ffff:8000::/65",
+ IpRange(before_truncate, 65).ToString());
+ EXPECT_EQ("ffff:ffff:ffff:ffff:f903::4/127",
+ IpRange(before_truncate, 127).ToString());
+}
+
+TEST(IpRangeTest, FromStringWorksIPv4) {
+ IpRange range;
+ ASSERT_TRUE(range.FromString("127.0.3.249/26"));
+ EXPECT_EQ("127.0.3.192/26", range.ToString());
+}
+
+TEST(IpRangeTest, FromStringWorksIPv6) {
+ IpRange range;
+ ASSERT_TRUE(range.FromString("ff01:8f21:77f9::/33"));
+ EXPECT_EQ("ff01:8f21::/33", range.ToString());
+}
+
+TEST(IpRangeTest, FirstAddressWorksIPv6) {
+ IpRange range;
+ ASSERT_TRUE(range.FromString("ffff:ffff::/64"));
+ QuicIpAddress first_address = range.FirstAddressInRange();
+ EXPECT_EQ("ffff:ffff::", first_address.ToString());
+}
+
+TEST(IpRangeTest, FirstAddressWorksIPv4) {
+ IpRange range;
+ ASSERT_TRUE(range.FromString("10.0.0.0/24"));
+ QuicIpAddress first_address = range.FirstAddressInRange();
+ EXPECT_EQ("10.0.0.0", first_address.ToString());
+}
+
+} // namespace
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/platform/kernel_interface.h b/chromium/net/third_party/quiche/src/quic/qbone/platform/kernel_interface.h
new file mode 100644
index 00000000000..c96b6e67d0d
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/platform/kernel_interface.h
@@ -0,0 +1,169 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_QBONE_PLATFORM_KERNEL_INTERFACE_H_
+#define QUICHE_QUIC_QBONE_PLATFORM_KERNEL_INTERFACE_H_
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <type_traits>
+#include <utility>
+
+namespace quic {
+
+// A wrapper for making syscalls to the kernel, so that syscalls can be
+// mocked during testing.
+class KernelInterface {
+ public:
+ virtual ~KernelInterface() {}
+ virtual int bind(int fd, const struct sockaddr* addr, socklen_t addr_len) = 0;
+ virtual int close(int fd) = 0;
+ virtual int ioctl(int fd, int request, void* argp) = 0;
+ virtual int open(const char* pathname, int flags) = 0;
+ virtual ssize_t read(int fd, void* buf, size_t count) = 0;
+ virtual ssize_t recvfrom(int sockfd,
+ void* buf,
+ size_t len,
+ int flags,
+ struct sockaddr* src_addr,
+ socklen_t* addrlen) = 0;
+ virtual ssize_t sendmsg(int sockfd, const struct msghdr* msg, int flags) = 0;
+ virtual ssize_t sendto(int sockfd,
+ const void* buf,
+ size_t len,
+ int flags,
+ const struct sockaddr* dest_addr,
+ socklen_t addrlen) = 0;
+ virtual int socket(int domain, int type, int protocol) = 0;
+ virtual int setsockopt(int fd,
+ int level,
+ int optname,
+ const void* optval,
+ socklen_t optlen) = 0;
+ virtual ssize_t write(int fd, const void* buf, size_t count) = 0;
+};
+
+// It is unfortunate to have R here, but std::result_of cannot be used.
+template <typename F, typename R, typename... Params>
+auto SyscallRetryOnError(R r, F f, Params&&... params)
+ -> decltype(f(std::forward<Params>(params)...)) {
+ static_assert(
+ std::is_same<decltype(f(std::forward<Params>(params)...)), R>::value,
+ "Return type does not match");
+ decltype(f(std::forward<Params>(params)...)) result;
+ do {
+ result = f(std::forward<Params>(params)...);
+ } while (result == r && errno == EINTR);
+ return result;
+}
+
+template <typename F, typename... Params>
+auto SyscallRetry(F f, Params&&... params)
+ -> decltype(f(std::forward<Params>(params)...)) {
+ return SyscallRetryOnError(-1, f, std::forward<Params>(params)...);
+}
+
+template <typename Runner>
+class ParametrizedKernel final : public KernelInterface {
+ public:
+ static_assert(std::is_trivially_destructible<Runner>::value,
+ "Runner is used as static, must be trivially destructible");
+
+ ~ParametrizedKernel() override {}
+
+ int bind(int fd, const struct sockaddr* addr, socklen_t addr_len) override {
+ static Runner syscall("bind");
+ return syscall.Retry(&::bind, fd, addr, addr_len);
+ }
+ int close(int fd) override {
+ static Runner syscall("close");
+ return syscall.Retry(&::close, fd);
+ }
+ int ioctl(int fd, int request, void* argp) override {
+ static Runner syscall("ioctl");
+ return syscall.Retry(&::ioctl, fd, request, argp);
+ }
+ int open(const char* pathname, int flags) override {
+ static Runner syscall("open");
+ return syscall.Retry(&::open, pathname, flags);
+ }
+ ssize_t read(int fd, void* buf, size_t count) override {
+ static Runner syscall("read");
+ return syscall.Run(&::read, fd, buf, count);
+ }
+ ssize_t recvfrom(int sockfd,
+ void* buf,
+ size_t len,
+ int flags,
+ struct sockaddr* src_addr,
+ socklen_t* addrlen) override {
+ static Runner syscall("recvfrom");
+ return syscall.RetryOnError(&::recvfrom, static_cast<ssize_t>(-1), sockfd,
+ buf, len, flags, src_addr, addrlen);
+ }
+ ssize_t sendmsg(int sockfd, const struct msghdr* msg, int flags) override {
+ static Runner syscall("sendmsg");
+ return syscall.RetryOnError(&::sendmsg, static_cast<ssize_t>(-1), sockfd,
+ msg, flags);
+ }
+ ssize_t sendto(int sockfd,
+ const void* buf,
+ size_t len,
+ int flags,
+ const struct sockaddr* dest_addr,
+ socklen_t addrlen) override {
+ static Runner syscall("sendto");
+ return syscall.RetryOnError(&::sendto, static_cast<ssize_t>(-1), sockfd,
+ buf, len, flags, dest_addr, addrlen);
+ }
+ int socket(int domain, int type, int protocol) override {
+ static Runner syscall("socket");
+ return syscall.Retry(&::socket, domain, type, protocol);
+ }
+ int setsockopt(int fd,
+ int level,
+ int optname,
+ const void* optval,
+ socklen_t optlen) override {
+ static Runner syscall("setsockopt");
+ return syscall.Retry(&::setsockopt, fd, level, optname, optval, optlen);
+ }
+ ssize_t write(int fd, const void* buf, size_t count) override {
+ static Runner syscall("write");
+ return syscall.Run(&::write, fd, buf, count);
+ }
+};
+
+class DefaultKernelRunner {
+ public:
+ explicit DefaultKernelRunner(const char* name) {}
+
+ template <typename F, typename R, typename... Params>
+ static auto RetryOnError(F f, R r, Params&&... params)
+ -> decltype(f(std::forward<Params>(params)...)) {
+ return SyscallRetryOnError(r, f, std::forward<Params>(params)...);
+ }
+
+ template <typename F, typename... Params>
+ static auto Retry(F f, Params&&... params)
+ -> decltype(f(std::forward<Params>(params)...)) {
+ return SyscallRetry(f, std::forward<Params>(params)...);
+ }
+
+ template <typename F, typename... Params>
+ static auto Run(F f, Params&&... params)
+ -> decltype(f(std::forward<Params>(params)...)) {
+ return f(std::forward<Params>(params)...);
+ }
+};
+
+using Kernel = ParametrizedKernel<DefaultKernelRunner>;
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_QBONE_PLATFORM_KERNEL_INTERFACE_H_
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/platform/mock_kernel.h b/chromium/net/third_party/quiche/src/quic/qbone/platform/mock_kernel.h
new file mode 100644
index 00000000000..c01aad1708b
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/platform/mock_kernel.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_QBONE_PLATFORM_MOCK_KERNEL_H_
+#define QUICHE_QUIC_QBONE_PLATFORM_MOCK_KERNEL_H_
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+#include "net/third_party/quiche/src/quic/qbone/platform/kernel_interface.h"
+
+namespace quic {
+
+class MockKernel : public KernelInterface {
+ public:
+ MockKernel() {}
+
+ MOCK_METHOD3(bind,
+ int(int fd, const struct sockaddr* addr, socklen_t addr_len));
+ MOCK_METHOD1(close, int(int fd));
+ MOCK_METHOD3(ioctl, int(int fd, int request, void* argp));
+ MOCK_METHOD2(open, int(const char* pathname, int flags));
+ MOCK_METHOD3(read, ssize_t(int fd, void* buf, size_t count));
+ MOCK_METHOD6(recvfrom,
+ ssize_t(int sockfd,
+ void* buf,
+ size_t len,
+ int flags,
+ struct sockaddr* src_addr,
+ socklen_t* addrlen));
+ MOCK_METHOD3(sendmsg,
+ ssize_t(int sockfd, const struct msghdr* msg, int flags));
+ MOCK_METHOD6(sendto,
+ ssize_t(int sockfd,
+ const void* buf,
+ size_t len,
+ int flags,
+ const struct sockaddr* dest_addr,
+ socklen_t addrlen));
+ MOCK_METHOD3(socket, int(int domain, int type, int protocol));
+ MOCK_METHOD5(setsockopt, int(int, int, int, const void*, socklen_t));
+ MOCK_METHOD3(write, ssize_t(int fd, const void* buf, size_t count));
+};
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_QBONE_PLATFORM_MOCK_KERNEL_H_
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/platform/mock_netlink.h b/chromium/net/third_party/quiche/src/quic/qbone/platform/mock_netlink.h
new file mode 100644
index 00000000000..5c1e7bc2fde
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/platform/mock_netlink.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_QBONE_PLATFORM_MOCK_NETLINK_H_
+#define QUICHE_QUIC_QBONE_PLATFORM_MOCK_NETLINK_H_
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+#include "net/third_party/quiche/src/quic/qbone/platform/netlink_interface.h"
+
+namespace quic {
+
+class MockNetlink : public NetlinkInterface {
+ public:
+ MOCK_METHOD2(GetLinkInfo, bool(const string&, LinkInfo*));
+
+ MOCK_METHOD4(GetAddresses,
+ bool(int, uint8_t, std::vector<AddressInfo>*, int*));
+
+ MOCK_METHOD7(ChangeLocalAddress,
+ bool(uint32_t,
+ Verb,
+ const QuicIpAddress&,
+ uint8_t,
+ uint8_t,
+ uint8_t,
+ const std::vector<struct rtattr*>&));
+
+ MOCK_METHOD1(GetRouteInfo, bool(std::vector<RoutingRule>*));
+
+ MOCK_METHOD6(
+ ChangeRoute,
+ bool(Verb, uint32_t, const IpRange&, uint8_t, QuicIpAddress, int32_t));
+
+ MOCK_METHOD1(GetRuleInfo, bool(std::vector<IpRule>*));
+
+ MOCK_METHOD3(ChangeRule, bool(Verb, uint32_t, IpRange));
+
+ MOCK_METHOD2(Send, bool(struct iovec*, size_t));
+
+ MOCK_METHOD2(Recv, bool(uint32_t, NetlinkParserInterface*));
+};
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_QBONE_PLATFORM_MOCK_NETLINK_H_
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
new file mode 100644
index 00000000000..1a4270e6644
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/platform/netlink.cc
@@ -0,0 +1,828 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/qbone/platform/netlink.h"
+
+#include <linux/fib_rules.h>
+
+#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_fallthrough.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h"
+#include "net/quic/platform/impl/quic_ip_address_impl.h"
+#include "net/third_party/quiche/src/quic/qbone/platform/rtnetlink_message.h"
+
+namespace quic {
+
+Netlink::Netlink(KernelInterface* kernel) : kernel_(kernel) {
+ seq_ = QuicRandom::GetInstance()->RandUint64();
+}
+
+Netlink::~Netlink() {
+ CloseSocket();
+}
+
+void Netlink::ResetRecvBuf(size_t size) {
+ if (size != 0) {
+ recvbuf_ = QuicMakeUnique<char[]>(size);
+ } else {
+ recvbuf_ = nullptr;
+ }
+ recvbuf_length_ = size;
+}
+
+bool Netlink::OpenSocket() {
+ if (socket_fd_ >= 0) {
+ return true;
+ }
+
+ socket_fd_ = kernel_->socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+
+ if (socket_fd_ < 0) {
+ QUIC_PLOG(ERROR) << "can't open netlink socket";
+ return false;
+ }
+
+ QUIC_LOG(INFO) << "Opened a new netlink socket fd = " << socket_fd_;
+
+ // bind a local address to the socket
+ sockaddr_nl myaddr;
+ memset(&myaddr, 0, sizeof(myaddr));
+ myaddr.nl_family = AF_NETLINK;
+ if (kernel_->bind(socket_fd_, reinterpret_cast<struct sockaddr*>(&myaddr),
+ sizeof(myaddr)) < 0) {
+ QUIC_LOG(INFO) << "can't bind address to socket";
+ CloseSocket();
+ return false;
+ }
+
+ return true;
+}
+
+void Netlink::CloseSocket() {
+ if (socket_fd_ >= 0) {
+ QUIC_LOG(INFO) << "Closing netlink socket fd = " << socket_fd_;
+ kernel_->close(socket_fd_);
+ }
+ ResetRecvBuf(0);
+ socket_fd_ = -1;
+}
+
+namespace {
+
+class LinkInfoParser : public NetlinkParserInterface {
+ public:
+ LinkInfoParser(string interface_name, Netlink::LinkInfo* link_info)
+ : interface_name_(std::move(interface_name)), link_info_(link_info) {}
+
+ void Run(struct nlmsghdr* netlink_message) override {
+ if (netlink_message->nlmsg_type != RTM_NEWLINK) {
+ QUIC_LOG(INFO) << QuicStrCat(
+ "Unexpected nlmsg_type: ", netlink_message->nlmsg_type,
+ " expected: ", RTM_NEWLINK);
+ return;
+ }
+
+ struct ifinfomsg* interface_info =
+ reinterpret_cast<struct ifinfomsg*>(NLMSG_DATA(netlink_message));
+
+ // make sure interface_info is what we asked for.
+ if (interface_info->ifi_family != AF_UNSPEC) {
+ QUIC_LOG(INFO) << QuicStrCat(
+ "Unexpected ifi_family: ", interface_info->ifi_family,
+ " expected: ", AF_UNSPEC);
+ return;
+ }
+
+ char hardware_address[kHwAddrSize];
+ size_t hardware_address_length = 0;
+ char broadcast_address[kHwAddrSize];
+ size_t broadcast_address_length = 0;
+ string name;
+
+ // loop through the attributes
+ struct rtattr* rta;
+ int payload_length = IFLA_PAYLOAD(netlink_message);
+ for (rta = IFLA_RTA(interface_info); RTA_OK(rta, payload_length);
+ rta = RTA_NEXT(rta, payload_length)) {
+ int attribute_length;
+ switch (rta->rta_type) {
+ case IFLA_ADDRESS: {
+ attribute_length = RTA_PAYLOAD(rta);
+ if (attribute_length > kHwAddrSize) {
+ QUIC_VLOG(2) << "IFLA_ADDRESS too long: " << attribute_length;
+ break;
+ }
+ memmove(hardware_address, RTA_DATA(rta), attribute_length);
+ hardware_address_length = attribute_length;
+ break;
+ }
+ case IFLA_BROADCAST: {
+ attribute_length = RTA_PAYLOAD(rta);
+ if (attribute_length > kHwAddrSize) {
+ QUIC_VLOG(2) << "IFLA_BROADCAST too long: " << attribute_length;
+ break;
+ }
+ memmove(broadcast_address, RTA_DATA(rta), attribute_length);
+ broadcast_address_length = attribute_length;
+ break;
+ }
+ case IFLA_IFNAME: {
+ name =
+ string(reinterpret_cast<char*>(RTA_DATA(rta)), RTA_PAYLOAD(rta));
+ // The name maybe a 0 terminated c string.
+ name = name.substr(0, name.find('\0'));
+ break;
+ }
+ }
+ }
+
+ QUIC_VLOG(2) << "interface name: " << name
+ << ", index: " << interface_info->ifi_index;
+
+ if (name == interface_name_) {
+ link_info_->index = interface_info->ifi_index;
+ link_info_->type = interface_info->ifi_type;
+ link_info_->hardware_address_length = hardware_address_length;
+ if (hardware_address_length > 0) {
+ memmove(&link_info_->hardware_address, hardware_address,
+ hardware_address_length);
+ }
+ link_info_->broadcast_address_length = broadcast_address_length;
+ if (broadcast_address_length > 0) {
+ memmove(&link_info_->broadcast_address, broadcast_address,
+ broadcast_address_length);
+ }
+ found_link_ = true;
+ }
+ }
+
+ bool found_link() { return found_link_; }
+
+ private:
+ const string interface_name_;
+ Netlink::LinkInfo* const link_info_;
+ bool found_link_ = false;
+};
+
+} // namespace
+
+bool Netlink::GetLinkInfo(const string& interface_name, LinkInfo* link_info) {
+ auto message = LinkMessage::New(RtnetlinkMessage::Operation::GET,
+ NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST,
+ seq_, getpid(), nullptr);
+
+ if (!Send(message.BuildIoVec().get(), message.IoVecSize())) {
+ QUIC_LOG(ERROR) << "send failed.";
+ return false;
+ }
+
+ // Pass the parser to the receive routine. It may be called multiple times
+ // since there may be multiple reply packets each with multiple reply
+ // messages.
+ LinkInfoParser parser(interface_name, link_info);
+ if (!Recv(seq_++, &parser)) {
+ QUIC_LOG(ERROR) << "recv failed.";
+ return false;
+ }
+
+ return parser.found_link();
+}
+
+namespace {
+
+class LocalAddressParser : public NetlinkParserInterface {
+ public:
+ LocalAddressParser(int interface_index,
+ uint8_t unwanted_flags,
+ std::vector<Netlink::AddressInfo>* local_addresses,
+ int* num_ipv6_nodad_dadfailed_addresses)
+ : interface_index_(interface_index),
+ unwanted_flags_(unwanted_flags),
+ local_addresses_(local_addresses),
+ num_ipv6_nodad_dadfailed_addresses_(
+ num_ipv6_nodad_dadfailed_addresses) {}
+
+ void Run(struct nlmsghdr* netlink_message) override {
+ // each nlmsg contains a header and multiple address attributes.
+ if (netlink_message->nlmsg_type != RTM_NEWADDR) {
+ QUIC_LOG(INFO) << "Unexpected nlmsg_type: " << netlink_message->nlmsg_type
+ << " expected: " << RTM_NEWADDR;
+ return;
+ }
+
+ struct ifaddrmsg* interface_address =
+ reinterpret_cast<struct ifaddrmsg*>(NLMSG_DATA(netlink_message));
+
+ // Make sure this is for an address family we're interested in.
+ if (interface_address->ifa_family != AF_INET &&
+ interface_address->ifa_family != AF_INET6) {
+ QUIC_VLOG(2) << QuicStrCat("uninteresting ifa family: ",
+ interface_address->ifa_family);
+ return;
+ }
+
+ // Keep track of addresses with both 'nodad' and 'dadfailed', this really
+ // should't be possible and is likely a kernel bug.
+ if (num_ipv6_nodad_dadfailed_addresses_ != nullptr &&
+ (interface_address->ifa_flags & IFA_F_NODAD) &&
+ (interface_address->ifa_flags & IFA_F_DADFAILED)) {
+ ++(*num_ipv6_nodad_dadfailed_addresses_);
+ }
+
+ uint8_t unwanted_flags = interface_address->ifa_flags & unwanted_flags_;
+ if (unwanted_flags != 0) {
+ QUIC_VLOG(2) << QuicStrCat("unwanted ifa flags: ", unwanted_flags);
+ return;
+ }
+
+ // loop through the attributes
+ struct rtattr* rta;
+ int payload_length = IFA_PAYLOAD(netlink_message);
+ Netlink::AddressInfo address_info;
+ for (rta = IFA_RTA(interface_address); RTA_OK(rta, payload_length);
+ rta = RTA_NEXT(rta, payload_length)) {
+ // There's quite a lot of confusion in Linux over the use of IFA_LOCAL and
+ // IFA_ADDRESS (source and destination address). For broadcast links, such
+ // as Ethernet, they are identical (see <linux/if_addr.h>), but the kernel
+ // sometimes uses only one or the other. We'll return both so that the
+ // caller can decide which to use.
+ if (rta->rta_type != IFA_LOCAL && rta->rta_type != IFA_ADDRESS) {
+ QUIC_VLOG(2) << "Ignoring uninteresting rta_type: " << rta->rta_type;
+ continue;
+ }
+
+ switch (interface_address->ifa_family) {
+ case AF_INET:
+ QUIC_FALLTHROUGH_INTENDED;
+ case AF_INET6:
+ // QuicIpAddress knows how to parse ip from raw bytes as long as they
+ // are in network byte order.
+ if (RTA_PAYLOAD(rta) == sizeof(struct in_addr) ||
+ RTA_PAYLOAD(rta) == sizeof(struct in6_addr)) {
+ auto* raw_ip = reinterpret_cast<char*>(RTA_DATA(rta));
+ if (rta->rta_type == IFA_LOCAL) {
+ address_info.local_address.FromPackedString(raw_ip,
+ RTA_PAYLOAD(rta));
+ } else {
+ address_info.interface_address.FromPackedString(raw_ip,
+ RTA_PAYLOAD(rta));
+ }
+ }
+ break;
+ default:
+ QUIC_LOG(ERROR) << QuicStrCat("Unknown address family: ",
+ interface_address->ifa_family);
+ }
+ }
+
+ QUIC_VLOG(2) << "local_address: " << address_info.local_address.ToString()
+ << " interface_address: "
+ << address_info.interface_address.ToString()
+ << " index: " << interface_address->ifa_index;
+ if (interface_address->ifa_index != interface_index_) {
+ return;
+ }
+
+ address_info.prefix_length = interface_address->ifa_prefixlen;
+ address_info.scope = interface_address->ifa_scope;
+ if (address_info.local_address.IsInitialized() ||
+ address_info.interface_address.IsInitialized()) {
+ local_addresses_->push_back(address_info);
+ }
+ }
+
+ private:
+ const int interface_index_;
+ const uint8_t unwanted_flags_;
+ std::vector<Netlink::AddressInfo>* const local_addresses_;
+ int* const num_ipv6_nodad_dadfailed_addresses_;
+};
+
+} // namespace
+
+bool Netlink::GetAddresses(int interface_index,
+ uint8_t unwanted_flags,
+ std::vector<AddressInfo>* addresses,
+ int* num_ipv6_nodad_dadfailed_addresses) {
+ // the message doesn't contain the index, we'll have to do the filtering while
+ // parsing the reply. This is because NLM_F_MATCH, which only returns entries
+ // that matches the request criteria, is not yet implemented (see man 3
+ // netlink).
+ auto message = AddressMessage::New(RtnetlinkMessage::Operation::GET,
+ NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST,
+ seq_, getpid(), nullptr);
+
+ // the send routine returns the socket to listen on.
+ if (!Send(message.BuildIoVec().get(), message.IoVecSize())) {
+ QUIC_LOG(ERROR) << "send failed.";
+ return false;
+ }
+
+ addresses->clear();
+ if (num_ipv6_nodad_dadfailed_addresses != nullptr) {
+ *num_ipv6_nodad_dadfailed_addresses = 0;
+ }
+
+ LocalAddressParser parser(interface_index, unwanted_flags, addresses,
+ num_ipv6_nodad_dadfailed_addresses);
+ // Pass the parser to the receive routine. It may be called multiple times
+ // since there may be multiple reply packets each with multiple reply
+ // messages.
+ if (!Recv(seq_++, &parser)) {
+ QUIC_LOG(ERROR) << "recv failed";
+ return false;
+ }
+ return true;
+}
+
+namespace {
+
+class UnknownParser : public NetlinkParserInterface {
+ public:
+ void Run(struct nlmsghdr* netlink_message) override {
+ QUIC_LOG(INFO) << "nlmsg reply type: " << netlink_message->nlmsg_type;
+ }
+};
+
+} // namespace
+
+bool Netlink::ChangeLocalAddress(
+ uint32_t interface_index,
+ Verb verb,
+ const QuicIpAddress& address,
+ uint8_t prefix_length,
+ uint8_t ifa_flags,
+ uint8_t ifa_scope,
+ const std::vector<struct rtattr*>& additional_attributes) {
+ if (verb == Verb::kReplace) {
+ return false;
+ }
+ auto operation = verb == Verb::kAdd ? RtnetlinkMessage::Operation::NEW
+ : RtnetlinkMessage::Operation::DEL;
+ uint8_t address_family;
+ if (address.address_family() == IpAddressFamily::IP_V4) {
+ address_family = AF_INET;
+ } else if (address.address_family() == IpAddressFamily::IP_V6) {
+ address_family = AF_INET6;
+ } else {
+ return false;
+ }
+
+ struct ifaddrmsg address_header = {address_family, prefix_length, ifa_flags,
+ ifa_scope, interface_index};
+
+ auto message = AddressMessage::New(operation, NLM_F_REQUEST | NLM_F_ACK, seq_,
+ getpid(), &address_header);
+
+ for (const auto& attribute : additional_attributes) {
+ if (attribute->rta_type == IFA_LOCAL) {
+ continue;
+ }
+ message.AppendAttribute(attribute->rta_type, RTA_DATA(attribute),
+ RTA_PAYLOAD(attribute));
+ }
+
+ message.AppendAttribute(IFA_LOCAL, address.ToPackedString().c_str(),
+ address.ToPackedString().size());
+
+ if (!Send(message.BuildIoVec().get(), message.IoVecSize())) {
+ QUIC_LOG(ERROR) << "send failed";
+ return false;
+ }
+
+ UnknownParser parser;
+ if (!Recv(seq_++, &parser)) {
+ QUIC_LOG(ERROR) << "receive failed.";
+ return false;
+ }
+ return true;
+}
+
+namespace {
+
+class RoutingRuleParser : public NetlinkParserInterface {
+ public:
+ explicit RoutingRuleParser(std::vector<Netlink::RoutingRule>* routing_rules)
+ : routing_rules_(routing_rules) {}
+
+ void Run(struct nlmsghdr* netlink_message) override {
+ if (netlink_message->nlmsg_type != RTM_NEWROUTE) {
+ QUIC_LOG(WARNING) << QuicStrCat(
+ "Unexpected nlmsg_type: ", netlink_message->nlmsg_type,
+ " expected: ", RTM_NEWROUTE);
+ return;
+ }
+
+ auto* route = reinterpret_cast<struct rtmsg*>(NLMSG_DATA(netlink_message));
+ int payload_length = RTM_PAYLOAD(netlink_message);
+
+ if (route->rtm_family != AF_INET && route->rtm_family != AF_INET6) {
+ QUIC_VLOG(2) << QuicStrCat("Uninteresting family: ", route->rtm_family);
+ return;
+ }
+
+ Netlink::RoutingRule rule;
+ rule.scope = route->rtm_scope;
+ rule.table = route->rtm_table;
+
+ struct rtattr* rta;
+ for (rta = RTM_RTA(route); RTA_OK(rta, payload_length);
+ rta = RTA_NEXT(rta, payload_length)) {
+ switch (rta->rta_type) {
+ case RTA_TABLE: {
+ rule.table = *reinterpret_cast<uint32_t*>(RTA_DATA(rta));
+ break;
+ }
+ case RTA_DST: {
+ QuicIpAddress destination;
+ destination.FromPackedString(reinterpret_cast<char*> RTA_DATA(rta),
+ RTA_PAYLOAD(rta));
+ rule.destination_subnet = IpRange(destination, route->rtm_dst_len);
+ break;
+ }
+ case RTA_PREFSRC: {
+ QuicIpAddress preferred_source;
+ rule.preferred_source.FromPackedString(
+ reinterpret_cast<char*> RTA_DATA(rta), RTA_PAYLOAD(rta));
+ break;
+ }
+ case RTA_OIF: {
+ rule.out_interface = *reinterpret_cast<int*>(RTA_DATA(rta));
+ break;
+ }
+ default: {
+ QUIC_VLOG(2) << QuicStrCat("Uninteresting attribute: ",
+ rta->rta_type);
+ }
+ }
+ }
+ routing_rules_->push_back(rule);
+ }
+
+ private:
+ std::vector<Netlink::RoutingRule>* routing_rules_;
+};
+
+} // namespace
+
+bool Netlink::GetRouteInfo(std::vector<Netlink::RoutingRule>* routing_rules) {
+ rtmsg route_message{};
+ // Only manipulate main routing table.
+ route_message.rtm_table = RT_TABLE_MAIN;
+
+ auto message = RouteMessage::New(RtnetlinkMessage::Operation::GET,
+ NLM_F_REQUEST | NLM_F_ROOT | NLM_F_MATCH,
+ seq_, getpid(), &route_message);
+
+ if (!Send(message.BuildIoVec().get(), message.IoVecSize())) {
+ QUIC_LOG(ERROR) << "send failed";
+ return false;
+ }
+
+ RoutingRuleParser parser(routing_rules);
+ if (!Recv(seq_++, &parser)) {
+ QUIC_LOG(ERROR) << "recv failed";
+ return false;
+ }
+
+ return true;
+}
+
+bool Netlink::ChangeRoute(Netlink::Verb verb,
+ uint32_t table,
+ const IpRange& destination_subnet,
+ uint8_t scope,
+ QuicIpAddress preferred_source,
+ int32_t interface_index) {
+ if (!destination_subnet.prefix().IsInitialized()) {
+ return false;
+ }
+ if (destination_subnet.address_family() != IpAddressFamily::IP_V4 &&
+ destination_subnet.address_family() != IpAddressFamily::IP_V6) {
+ return false;
+ }
+ if (preferred_source.IsInitialized() &&
+ preferred_source.address_family() !=
+ destination_subnet.address_family()) {
+ return false;
+ }
+
+ RtnetlinkMessage::Operation operation;
+ uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
+ switch (verb) {
+ case Verb::kAdd:
+ operation = RtnetlinkMessage::Operation::NEW;
+ // Setting NLM_F_EXCL so that an existing entry for this subnet will fail
+ // the request. NLM_F_CREATE is necessary to indicate this is trying to
+ // create a new entry - simply having RTM_NEWROUTE is not enough even the
+ // name suggests so.
+ flags |= NLM_F_EXCL | NLM_F_CREATE;
+ break;
+ case Verb::kRemove:
+ operation = RtnetlinkMessage::Operation::DEL;
+ break;
+ case Verb::kReplace:
+ operation = RtnetlinkMessage::Operation::NEW;
+ // Setting NLM_F_REPLACE to tell the kernel that existing entry for this
+ // subnet should be replaced.
+ flags |= NLM_F_REPLACE | NLM_F_CREATE;
+ break;
+ }
+
+ struct rtmsg route_message;
+ memset(&route_message, 0, sizeof(route_message));
+ route_message.rtm_family =
+ destination_subnet.address_family() == IpAddressFamily::IP_V4 ? AF_INET
+ : AF_INET6;
+ // rtm_dst_len and rtm_src_len are actually the subnet prefix lengths. Poor
+ // naming.
+ route_message.rtm_dst_len = destination_subnet.prefix_length();
+ // 0 means no source subnet for this rule.
+ route_message.rtm_src_len = 0;
+ // Only program the main table. Other tables are intended for the kernel to
+ // manage.
+ route_message.rtm_table = RT_TABLE_MAIN;
+ // Use RTPROT_UNSPEC to match all the different protocol. Rules added by
+ // kernel have RTPROT_KERNEL. Rules added by the root user have RTPROT_STATIC
+ // instead.
+ route_message.rtm_protocol =
+ verb == Verb::kRemove ? RTPROT_UNSPEC : RTPROT_STATIC;
+ route_message.rtm_scope = scope;
+ // Only add unicast routing rule.
+ route_message.rtm_type = RTN_UNICAST;
+ auto message =
+ RouteMessage::New(operation, flags, seq_, getpid(), &route_message);
+
+ message.AppendAttribute(RTA_TABLE, &table, sizeof(table));
+
+ // RTA_OIF is the target interface for this rule.
+ message.AppendAttribute(RTA_OIF, &interface_index, sizeof(interface_index));
+ // The actual destination subnet must be truncated of all the tailing zeros.
+ message.AppendAttribute(
+ RTA_DST,
+ reinterpret_cast<const void*>(
+ destination_subnet.prefix().ToPackedString().c_str()),
+ destination_subnet.prefix().ToPackedString().size());
+ // This is the source address to use in the IP packet should this routing rule
+ // is used.
+ if (preferred_source.IsInitialized()) {
+ message.AppendAttribute(RTA_PREFSRC,
+ reinterpret_cast<const void*>(
+ preferred_source.ToPackedString().c_str()),
+ preferred_source.ToPackedString().size());
+ }
+
+ if (!Send(message.BuildIoVec().get(), message.IoVecSize())) {
+ QUIC_LOG(ERROR) << "send failed";
+ return false;
+ }
+
+ UnknownParser parser;
+ if (!Recv(seq_++, &parser)) {
+ QUIC_LOG(ERROR) << "receive failed.";
+ return false;
+ }
+ return true;
+}
+
+namespace {
+
+class IpRuleParser : public NetlinkParserInterface {
+ public:
+ explicit IpRuleParser(std::vector<Netlink::IpRule>* ip_rules)
+ : ip_rules_(ip_rules) {}
+
+ void Run(struct nlmsghdr* netlink_message) override {
+ if (netlink_message->nlmsg_type != RTM_NEWRULE) {
+ QUIC_LOG(WARNING) << QuicStrCat(
+ "Unexpected nlmsg_type: ", netlink_message->nlmsg_type,
+ " expected: ", RTM_NEWRULE);
+ return;
+ }
+
+ auto* rule = reinterpret_cast<rtmsg*>(NLMSG_DATA(netlink_message));
+ int payload_length = RTM_PAYLOAD(netlink_message);
+
+ if (rule->rtm_family != AF_INET6) {
+ QUIC_LOG(ERROR) << QuicStrCat("Unexpected family: ", rule->rtm_family);
+ return;
+ }
+
+ Netlink::IpRule ip_rule;
+ ip_rule.table = rule->rtm_table;
+
+ struct rtattr* rta;
+ for (rta = RTM_RTA(rule); RTA_OK(rta, payload_length);
+ rta = RTA_NEXT(rta, payload_length)) {
+ switch (rta->rta_type) {
+ case RTA_TABLE: {
+ ip_rule.table = *reinterpret_cast<uint32_t*>(RTA_DATA(rta));
+ break;
+ }
+ case RTA_SRC: {
+ QuicIpAddress src_addr;
+ src_addr.FromPackedString(reinterpret_cast<char*>(RTA_DATA(rta)),
+ RTA_PAYLOAD(rta));
+ IpRange src_range(src_addr, rule->rtm_src_len);
+ ip_rule.source_range = src_range;
+ break;
+ }
+ default: {
+ QUIC_VLOG(2) << QuicStrCat("Uninteresting attribute: ",
+ rta->rta_type);
+ }
+ }
+ }
+ ip_rules_->emplace_back(ip_rule);
+ }
+
+ private:
+ std::vector<Netlink::IpRule>* ip_rules_;
+};
+
+} // namespace
+
+bool Netlink::GetRuleInfo(std::vector<Netlink::IpRule>* ip_rules) {
+ rtmsg rule_message{};
+ rule_message.rtm_family = AF_INET6;
+
+ auto message = RuleMessage::New(RtnetlinkMessage::Operation::GET,
+ NLM_F_REQUEST | NLM_F_DUMP, seq_, getpid(),
+ &rule_message);
+
+ if (!Send(message.BuildIoVec().get(), message.IoVecSize())) {
+ QUIC_LOG(ERROR) << "send failed";
+ return false;
+ }
+
+ IpRuleParser parser(ip_rules);
+ if (!Recv(seq_++, &parser)) {
+ QUIC_LOG(ERROR) << "receive failed.";
+ return false;
+ }
+ return true;
+}
+
+bool Netlink::ChangeRule(Verb verb, uint32_t table, IpRange source_range) {
+ RtnetlinkMessage::Operation operation;
+ uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
+
+ rtmsg rule_message{};
+ rule_message.rtm_family = AF_INET6;
+ rule_message.rtm_protocol = RTPROT_STATIC;
+ rule_message.rtm_scope = RT_SCOPE_UNIVERSE;
+ rule_message.rtm_table = RT_TABLE_UNSPEC;
+
+ rule_message.rtm_flags |= FIB_RULE_FIND_SADDR;
+
+ switch (verb) {
+ case Verb::kAdd:
+ if (!source_range.IsInitialized()) {
+ QUIC_LOG(ERROR) << "Source range must be initialized.";
+ return false;
+ }
+ operation = RtnetlinkMessage::Operation::NEW;
+ flags |= NLM_F_EXCL | NLM_F_CREATE;
+ rule_message.rtm_type = FRA_DST;
+ rule_message.rtm_src_len = source_range.prefix_length();
+ break;
+ case Verb::kRemove:
+ operation = RtnetlinkMessage::Operation::DEL;
+ break;
+ case Verb::kReplace:
+ QUIC_LOG(ERROR) << "Unsupported verb: kReplace";
+ return false;
+ }
+ auto message =
+ RuleMessage::New(operation, flags, seq_, getpid(), &rule_message);
+
+ message.AppendAttribute(RTA_TABLE, &table, sizeof(table));
+
+ if (source_range.IsInitialized()) {
+ std::string packed_src = source_range.prefix().ToPackedString();
+ message.AppendAttribute(RTA_SRC,
+ reinterpret_cast<const void*>(packed_src.c_str()),
+ packed_src.size());
+ }
+
+ if (!Send(message.BuildIoVec().get(), message.IoVecSize())) {
+ QUIC_LOG(ERROR) << "send failed";
+ return false;
+ }
+
+ UnknownParser parser;
+ if (!Recv(seq_++, &parser)) {
+ QUIC_LOG(ERROR) << "receive failed.";
+ return false;
+ }
+ return true;
+}
+
+bool Netlink::Send(struct iovec* iov, size_t iovlen) {
+ if (!OpenSocket()) {
+ QUIC_LOG(ERROR) << "can't open socket";
+ return false;
+ }
+
+ // an address for communicating with the kernel netlink code
+ sockaddr_nl netlink_address;
+ memset(&netlink_address, 0, sizeof(netlink_address));
+ netlink_address.nl_family = AF_NETLINK;
+ netlink_address.nl_pid = 0; // destination is kernel
+ netlink_address.nl_groups = 0; // no multicast
+
+ struct msghdr msg = {
+ &netlink_address, sizeof(netlink_address), iov, iovlen, nullptr, 0, 0};
+
+ if (kernel_->sendmsg(socket_fd_, &msg, 0) < 0) {
+ QUIC_LOG(ERROR) << "sendmsg failed";
+ CloseSocket();
+ return false;
+ }
+
+ return true;
+}
+
+bool Netlink::Recv(uint32_t seq, NetlinkParserInterface* parser) {
+ sockaddr_nl netlink_address;
+
+ // replies can span multiple packets
+ for (;;) {
+ socklen_t address_length = sizeof(netlink_address);
+
+ // First, call recvfrom with buffer size of 0 and MSG_PEEK | MSG_TRUNC set
+ // so that we know the size of the incoming packet before actually receiving
+ // it.
+ int next_packet_size = kernel_->recvfrom(
+ socket_fd_, recvbuf_.get(), /* len = */ 0, MSG_PEEK | MSG_TRUNC,
+ reinterpret_cast<struct sockaddr*>(&netlink_address), &address_length);
+ if (next_packet_size < 0) {
+ QUIC_LOG(ERROR)
+ << "error recvfrom with MSG_PEEK | MSG_TRUNC to get packet length.";
+ CloseSocket();
+ return false;
+ }
+ QUIC_VLOG(3) << "netlink packet size: " << next_packet_size;
+ if (next_packet_size > recvbuf_length_) {
+ QUIC_VLOG(2) << "resizing recvbuf to " << next_packet_size;
+ ResetRecvBuf(next_packet_size);
+ }
+
+ // Get the packet for real.
+ memset(recvbuf_.get(), 0, recvbuf_length_);
+ int len = kernel_->recvfrom(
+ socket_fd_, recvbuf_.get(), recvbuf_length_, /* flags = */ 0,
+ reinterpret_cast<struct sockaddr*>(&netlink_address), &address_length);
+ QUIC_VLOG(3) << "recvfrom returned: " << len;
+ if (len < 0) {
+ QUIC_LOG(INFO) << "can't receive netlink packet";
+ CloseSocket();
+ return false;
+ }
+
+ // there may be multiple nlmsg's in each reply packet
+ struct nlmsghdr* netlink_message;
+ for (netlink_message = reinterpret_cast<struct nlmsghdr*>(recvbuf_.get());
+ NLMSG_OK(netlink_message, len);
+ netlink_message = NLMSG_NEXT(netlink_message, len)) {
+ QUIC_VLOG(3) << "netlink_message->nlmsg_type = "
+ << netlink_message->nlmsg_type;
+ // make sure this is to us
+ if (netlink_message->nlmsg_seq != seq) {
+ QUIC_LOG(INFO) << "netlink_message not meant for us."
+ << " seq: " << seq
+ << " nlmsg_seq: " << netlink_message->nlmsg_seq;
+ continue;
+ }
+
+ // done with this whole reply (not just this particular packet)
+ if (netlink_message->nlmsg_type == NLMSG_DONE) {
+ return true;
+ }
+ if (netlink_message->nlmsg_type == NLMSG_ERROR) {
+ struct nlmsgerr* err =
+ reinterpret_cast<struct nlmsgerr*>(NLMSG_DATA(netlink_message));
+ if (netlink_message->nlmsg_len <
+ NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
+ QUIC_LOG(INFO) << "netlink_message ERROR truncated";
+ } else {
+ // an ACK
+ if (err->error == 0) {
+ QUIC_VLOG(3) << "Netlink sent an ACK";
+ return true;
+ }
+ QUIC_LOG(INFO) << "netlink_message ERROR: " << err->error;
+ }
+ return false;
+ }
+
+ parser->Run(netlink_message);
+ }
+ }
+}
+
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/platform/netlink.h b/chromium/net/third_party/quiche/src/quic/qbone/platform/netlink.h
new file mode 100644
index 00000000000..591da0f7ed0
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/platform/netlink.h
@@ -0,0 +1,142 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_QBONE_PLATFORM_NETLINK_H_
+#define QUICHE_QUIC_QBONE_PLATFORM_NETLINK_H_
+
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+#include <cstdint>
+#include <functional>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h"
+#include "net/third_party/quiche/src/quic/qbone/platform/ip_range.h"
+#include "net/third_party/quiche/src/quic/qbone/platform/kernel_interface.h"
+#include "net/third_party/quiche/src/quic/qbone/platform/netlink_interface.h"
+
+namespace quic {
+
+// A wrapper class to provide convenient methods of manipulating IP address and
+// routing table using netlink (man 7 netlink) socket. More specifically,
+// rtnetlink is used (man 7 rtnetlink).
+//
+// This class is not thread safe, but thread compatible, as long as callers can
+// make sure Send and Recv pairs are executed in sequence for a particular
+// query.
+class Netlink : public NetlinkInterface {
+ public:
+ explicit Netlink(KernelInterface* kernel);
+ ~Netlink() override;
+
+ // Gets the link information for the interface referred by the given
+ // interface_name.
+ //
+ // This is a synchronous communication. That should not be a problem since the
+ // kernel should answer immediately.
+ bool GetLinkInfo(const string& interface_name, LinkInfo* link_info) override;
+
+ // Gets the addresses for the given interface referred by the given
+ // interface_index.
+ //
+ // This is a synchronous communication. This should not be a problem since the
+ // kernel should answer immediately.
+ bool GetAddresses(int interface_index,
+ uint8_t unwanted_flags,
+ std::vector<AddressInfo>* addresses,
+ int* num_ipv6_nodad_dadfailed_addresses) override;
+
+ // Performs the given verb that modifies local addresses on the given
+ // interface_index.
+ //
+ // additional_attributes are RTAs (man 7 rtnelink) that will be sent together
+ // with the netlink message. Note that rta_len in each RTA is used to decide
+ // the length of the payload. The caller is responsible for making sure
+ // payload bytes are accessible after the RTA header.
+ bool ChangeLocalAddress(
+ uint32_t interface_index,
+ Verb verb,
+ const QuicIpAddress& address,
+ uint8_t prefix_length,
+ uint8_t ifa_flags,
+ uint8_t ifa_scope,
+ const std::vector<struct rtattr*>& additional_attributes) override;
+
+ // Gets the list of routing rules from the main routing table (RT_TABLE_MAIN),
+ // which is programmable.
+ //
+ // This is a synchronous communication. This should not be a problem since the
+ // kernel should answer immediately.
+ bool GetRouteInfo(std::vector<RoutingRule>* routing_rules) override;
+
+ // Performs the given Verb on the matching rule in the main routing table
+ // (RT_TABLE_MAIN).
+ //
+ // preferred_source can be !IsInitialized(), in which case it will be omitted.
+ //
+ // For Verb::kRemove, rule matching is done by (destination_subnet, scope,
+ // preferred_source, interface_index). Return true if a matching rule is
+ // found. interface_index can be 0 for wilecard.
+ //
+ // For Verb::kAdd, rule matching is done by destination_subnet. If a rule for
+ // the given destination_subnet already exists, nothing will happen and false
+ // is returned.
+ //
+ // For Verb::kReplace, rule matching is done by destination_subnet. If no
+ // matching rule is found, a new entry will be created.
+ bool ChangeRoute(Netlink::Verb verb,
+ uint32_t table,
+ const IpRange& destination_subnet,
+ uint8_t scope,
+ QuicIpAddress preferred_source,
+ int32_t interface_index) override;
+
+ // Returns the set of all rules in the routing policy database.
+ bool GetRuleInfo(std::vector<Netlink::IpRule>* ip_rules) override;
+
+ // Performs the give verb on the matching rule in the routing policy database.
+ // When deleting a rule, the |source_range| may be unspecified, in which case
+ // the lowest priority rule from |table| will be removed. When adding a rule,
+ // the |source_address| must be specified.
+ bool ChangeRule(Verb verb, uint32_t table, IpRange source_range) override;
+
+ // Sends a netlink message to the kernel. iov and iovlen represents an array
+ // of struct iovec to be fed into sendmsg. The caller needs to make sure the
+ // message conform to what's expected by NLMSG_* macros.
+ //
+ // This can be useful if more flexibility is needed than the provided
+ // convenient methods can provide.
+ bool Send(struct iovec* iov, size_t iovlen) override;
+
+ // Receives a netlink message from the kernel.
+ // parser will be called on the caller's stack.
+ //
+ // This can be useful if more flexibility is needed than the provided
+ // convenient methods can provide.
+ // TODO(b/69412655): vectorize this.
+ bool Recv(uint32_t seq, NetlinkParserInterface* parser) override;
+
+ private:
+ // Reset the size of recvbuf_ to size. If size is 0, recvbuf_ will be nullptr.
+ void ResetRecvBuf(size_t size);
+
+ // Opens a netlink socket if not already opened.
+ bool OpenSocket();
+
+ // Closes the opened netlink socket. Noop if no netlink socket is opened.
+ void CloseSocket();
+
+ KernelInterface* kernel_;
+ int socket_fd_ = -1;
+ std::unique_ptr<char[]> recvbuf_ = nullptr;
+ size_t recvbuf_length_ = 0;
+ uint32_t seq_; // next msg sequence number
+};
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_QBONE_PLATFORM_NETLINK_H_
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/platform/netlink_interface.h b/chromium/net/third_party/quiche/src/quic/qbone/platform/netlink_interface.h
new file mode 100644
index 00000000000..447c8b2014f
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/platform/netlink_interface.h
@@ -0,0 +1,146 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_QBONE_PLATFORM_NETLINK_INTERFACE_H_
+#define QUICHE_QUIC_QBONE_PLATFORM_NETLINK_INTERFACE_H_
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h"
+#include "net/third_party/quiche/src/quic/qbone/platform/ip_range.h"
+
+namespace quic {
+
+constexpr int kHwAddrSize = 6;
+
+class NetlinkParserInterface {
+ public:
+ virtual ~NetlinkParserInterface() {}
+ virtual void Run(struct nlmsghdr* netlink_message) = 0;
+};
+
+// An interface providing convenience methods for manipulating IP address and
+// routing table using netlink (man 7 netlink) socket.
+class NetlinkInterface {
+ public:
+ virtual ~NetlinkInterface() = default;
+
+ // Link information returned from GetLinkInfo.
+ struct LinkInfo {
+ int index;
+ uint8_t type;
+ uint8_t hardware_address[kHwAddrSize];
+ uint8_t broadcast_address[kHwAddrSize];
+ size_t hardware_address_length; // 0 if no hardware address found
+ size_t broadcast_address_length; // 0 if no broadcast address found
+ };
+
+ // Gets the link information for the interface referred by the given
+ // interface_name.
+ virtual bool GetLinkInfo(const string& interface_name,
+ LinkInfo* link_info) = 0;
+
+ // Address information reported back from GetAddresses.
+ struct AddressInfo {
+ QuicIpAddress local_address;
+ QuicIpAddress interface_address;
+ uint8_t prefix_length = 0;
+ uint8_t scope = 0;
+ };
+
+ // Gets the addresses for the given interface referred by the given
+ // interface_index.
+ virtual bool GetAddresses(int interface_index,
+ uint8_t unwanted_flags,
+ std::vector<AddressInfo>* addresses,
+ int* num_ipv6_nodad_dadfailed_addresses) = 0;
+
+ enum class Verb {
+ kAdd,
+ kRemove,
+ kReplace,
+ };
+
+ // Performs the given verb that modifies local addresses on the given
+ // interface_index.
+ //
+ // additional_attributes are RTAs (man 7 rtnelink) that will be sent together
+ // with the netlink message. Note that rta_len in each RTA is used to decide
+ // the length of the payload. The caller is responsible for making sure
+ // payload bytes are accessible after the RTA header.
+ virtual bool ChangeLocalAddress(
+ uint32_t interface_index,
+ Verb verb,
+ const QuicIpAddress& address,
+ uint8_t prefix_length,
+ uint8_t ifa_flags,
+ uint8_t ifa_scope,
+ const std::vector<struct rtattr*>& additional_attributes) = 0;
+
+ // Routing rule reported back from GetRouteInfo.
+ struct RoutingRule {
+ uint32_t table;
+ IpRange destination_subnet;
+ QuicIpAddress preferred_source;
+ uint8_t scope;
+ int out_interface;
+ };
+
+ struct IpRule {
+ uint32_t table;
+ IpRange source_range;
+ };
+
+ // Gets the list of routing rules from the main routing table (RT_TABLE_MAIN),
+ // which is programmable.
+ virtual bool GetRouteInfo(std::vector<RoutingRule>* routing_rules) = 0;
+
+ // Performs the given Verb on the matching rule in the main routing table
+ // (RT_TABLE_MAIN).
+ //
+ // preferred_source can be !IsInitialized(), in which case it will be omitted.
+ //
+ // For Verb::kRemove, rule matching is done by (destination_subnet, scope,
+ // preferred_source, interface_index). Return true if a matching rule is
+ // found. interface_index can be 0 for wilecard.
+ //
+ // For Verb::kAdd, rule matching is done by destination_subnet. If a rule for
+ // the given destination_subnet already exists, nothing will happen and false
+ // is returned.
+ //
+ // For Verb::kReplace, rule matching is done by destination_subnet. If no
+ // matching rule is found, a new entry will be created.
+ virtual bool ChangeRoute(Verb verb,
+ uint32_t table,
+ const IpRange& destination_subnet,
+ uint8_t scope,
+ QuicIpAddress preferred_source,
+ int32_t interface_index) = 0;
+
+ // Returns the set of all rules in the routing policy database.
+ virtual bool GetRuleInfo(std::vector<IpRule>* ip_rules) = 0;
+
+ // Performs the give verb on the matching rule in the routing policy database.
+ // When deleting a rule, the |source_range| may be unspecified, in which case
+ // the lowest priority rule from |table| will be removed. When adding a rule,
+ // the |source_address| must be specified.
+ virtual bool ChangeRule(Verb verb, uint32_t table, IpRange source_range) = 0;
+
+ // Sends a netlink message to the kernel. iov and iovlen represents an array
+ // of struct iovec to be fed into sendmsg. The caller needs to make sure the
+ // message conform to what's expected by NLMSG_* macros.
+ //
+ // This can be useful if more flexibility is needed than the provided
+ // convenient methods can provide.
+ virtual bool Send(struct iovec* iov, size_t iovlen) = 0;
+
+ // Receives a netlink message from the kernel.
+ // parser will be called on the caller's stack.
+ //
+ // This can be useful if more flexibility is needed than the provided
+ // convenient methods can provide.
+ virtual bool Recv(uint32_t seq, NetlinkParserInterface* parser) = 0;
+};
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_QBONE_PLATFORM_NETLINK_INTERFACE_H_
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
new file mode 100644
index 00000000000..024e0fb4801
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/platform/netlink_test.cc
@@ -0,0 +1,763 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/qbone/platform/netlink.h"
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+#include "net/third_party/quiche/src/quic/qbone/platform/mock_kernel.h"
+#include "net/third_party/quiche/src/quic/qbone/qbone_constants.h"
+
+namespace quic {
+namespace {
+
+using ::testing::_;
+using ::testing::Contains;
+using ::testing::InSequence;
+using ::testing::Invoke;
+using ::testing::Return;
+using ::testing::Unused;
+
+const int kSocketFd = 101;
+
+class NetlinkTest : public QuicTest {
+ protected:
+ NetlinkTest() {
+ ON_CALL(mock_kernel_, socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE))
+ .WillByDefault(Invoke([this](Unused, Unused, Unused) {
+ EXPECT_CALL(mock_kernel_, close(kSocketFd)).WillOnce(Return(0));
+ return kSocketFd;
+ }));
+ }
+
+ void ExpectNetlinkPacket(
+ uint16_t type,
+ uint16_t flags,
+ const std::function<ssize_t(void* buf, size_t len, int seq)>&
+ recv_callback,
+ const std::function<void(const void* buf, size_t len)>& send_callback =
+ nullptr) {
+ static int seq = -1;
+ InSequence s;
+
+ EXPECT_CALL(mock_kernel_, sendmsg(kSocketFd, _, _))
+ .WillOnce(Invoke([this, type, flags, send_callback](
+ Unused, const struct msghdr* msg, int) {
+ EXPECT_EQ(sizeof(struct sockaddr_nl), msg->msg_namelen);
+ auto* nl_addr =
+ reinterpret_cast<const struct sockaddr_nl*>(msg->msg_name);
+ EXPECT_EQ(AF_NETLINK, nl_addr->nl_family);
+ EXPECT_EQ(0, nl_addr->nl_pid);
+ EXPECT_EQ(0, nl_addr->nl_groups);
+
+ EXPECT_GE(msg->msg_iovlen, 1);
+ EXPECT_GE(msg->msg_iov[0].iov_len, sizeof(struct nlmsghdr));
+
+ string buf;
+ for (int i = 0; i < msg->msg_iovlen; i++) {
+ buf.append(string(reinterpret_cast<char*>(msg->msg_iov[i].iov_base),
+ msg->msg_iov[i].iov_len));
+ }
+
+ auto* netlink_message =
+ reinterpret_cast<const struct nlmsghdr*>(buf.c_str());
+ EXPECT_EQ(type, netlink_message->nlmsg_type);
+ EXPECT_EQ(flags, netlink_message->nlmsg_flags);
+ EXPECT_GE(buf.size(), netlink_message->nlmsg_len);
+
+ if (send_callback != nullptr) {
+ send_callback(buf.c_str(), buf.size());
+ }
+
+ CHECK_EQ(seq, -1);
+ seq = netlink_message->nlmsg_seq;
+ return buf.size();
+ }));
+
+ EXPECT_CALL(mock_kernel_,
+ recvfrom(kSocketFd, _, 0, MSG_PEEK | MSG_TRUNC, _, _))
+ .WillOnce(Invoke([this, recv_callback](Unused, Unused, Unused, Unused,
+ struct sockaddr* src_addr,
+ socklen_t* addrlen) {
+ auto* nl_addr = reinterpret_cast<struct sockaddr_nl*>(src_addr);
+ nl_addr->nl_family = AF_NETLINK;
+ nl_addr->nl_pid = 0; // from kernel
+ nl_addr->nl_groups = 0; // no multicast
+
+ int ret = recv_callback(reply_packet_, sizeof(reply_packet_), seq);
+ CHECK_LE(ret, sizeof(reply_packet_));
+ return ret;
+ }));
+
+ EXPECT_CALL(mock_kernel_, recvfrom(kSocketFd, _, _, _, _, _))
+ .WillOnce(Invoke([recv_callback](Unused, void* buf, size_t len, Unused,
+ struct sockaddr* src_addr,
+ socklen_t* addrlen) {
+ auto* nl_addr = reinterpret_cast<struct sockaddr_nl*>(src_addr);
+ nl_addr->nl_family = AF_NETLINK;
+ nl_addr->nl_pid = 0; // from kernel
+ nl_addr->nl_groups = 0; // no multicast
+
+ int ret = recv_callback(buf, len, seq);
+ EXPECT_GE(len, ret);
+ seq = -1;
+ return ret;
+ }));
+ }
+
+ char reply_packet_[4096];
+ MockKernel mock_kernel_;
+};
+
+void AddRTA(struct nlmsghdr* netlink_message,
+ uint16_t type,
+ const void* data,
+ size_t len) {
+ auto* next_header_ptr = reinterpret_cast<char*>(netlink_message) +
+ NLMSG_ALIGN(netlink_message->nlmsg_len);
+
+ auto* rta = reinterpret_cast<struct rtattr*>(next_header_ptr);
+ rta->rta_type = type;
+ rta->rta_len = RTA_LENGTH(len);
+ memcpy(RTA_DATA(rta), data, len);
+
+ netlink_message->nlmsg_len =
+ NLMSG_ALIGN(netlink_message->nlmsg_len) + RTA_LENGTH(len);
+}
+
+void CreateIfinfomsg(struct nlmsghdr* netlink_message,
+ const string& interface_name,
+ uint16_t type,
+ int index,
+ unsigned int flags,
+ unsigned int change,
+ uint8_t address[],
+ int address_len,
+ uint8_t broadcast[],
+ int broadcast_len) {
+ auto* interface_info =
+ reinterpret_cast<struct ifinfomsg*>(NLMSG_DATA(netlink_message));
+ interface_info->ifi_family = AF_UNSPEC;
+ interface_info->ifi_type = type;
+ interface_info->ifi_index = index;
+ interface_info->ifi_flags = flags;
+ interface_info->ifi_change = change;
+ netlink_message->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+
+ // Add address
+ AddRTA(netlink_message, IFLA_ADDRESS, address, address_len);
+
+ // Add broadcast address
+ AddRTA(netlink_message, IFLA_BROADCAST, broadcast, broadcast_len);
+
+ // Add name
+ AddRTA(netlink_message, IFLA_IFNAME, interface_name.c_str(),
+ interface_name.size());
+}
+
+struct nlmsghdr* CreateNetlinkMessage(void* buf, // NOLINT
+ struct nlmsghdr* previous_netlink_message,
+ uint16_t type,
+ int seq) {
+ auto* next_header_ptr = reinterpret_cast<char*>(buf);
+ if (previous_netlink_message != nullptr) {
+ next_header_ptr = reinterpret_cast<char*>(previous_netlink_message) +
+ NLMSG_ALIGN(previous_netlink_message->nlmsg_len);
+ }
+ auto* netlink_message = reinterpret_cast<nlmsghdr*>(next_header_ptr);
+ netlink_message->nlmsg_len = NLMSG_LENGTH(0);
+ netlink_message->nlmsg_type = type;
+ netlink_message->nlmsg_flags = NLM_F_MULTI;
+ netlink_message->nlmsg_pid = 0; // from the kernel
+ netlink_message->nlmsg_seq = seq;
+
+ return netlink_message;
+}
+
+void CreateIfaddrmsg(struct nlmsghdr* nlm,
+ int interface_index,
+ unsigned char prefixlen,
+ unsigned char flags,
+ unsigned char scope,
+ QuicIpAddress ip) {
+ CHECK(ip.IsInitialized());
+ unsigned char family;
+ switch (ip.address_family()) {
+ case IpAddressFamily::IP_V4:
+ family = AF_INET;
+ break;
+ case IpAddressFamily::IP_V6:
+ family = AF_INET6;
+ break;
+ default:
+ QUIC_BUG << absl::StrCat("unexpected address family: ",
+ ip.address_family());
+ family = AF_UNSPEC;
+ }
+ auto* msg = reinterpret_cast<struct ifaddrmsg*>(NLMSG_DATA(nlm));
+ msg->ifa_family = family;
+ msg->ifa_prefixlen = prefixlen;
+ msg->ifa_flags = flags;
+ msg->ifa_scope = scope;
+ msg->ifa_index = interface_index;
+ nlm->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
+
+ // Add local address
+ AddRTA(nlm, IFA_LOCAL, ip.ToPackedString().c_str(),
+ ip.ToPackedString().size());
+}
+
+void CreateRtmsg(struct nlmsghdr* nlm,
+ unsigned char family,
+ unsigned char destination_length,
+ unsigned char source_length,
+ unsigned char tos,
+ unsigned char table,
+ unsigned char protocol,
+ unsigned char scope,
+ unsigned char type,
+ unsigned int flags,
+ QuicIpAddress destination,
+ int interface_index) {
+ auto* msg = reinterpret_cast<struct rtmsg*>(NLMSG_DATA(nlm));
+ msg->rtm_family = family;
+ msg->rtm_dst_len = destination_length;
+ msg->rtm_src_len = source_length;
+ msg->rtm_tos = tos;
+ msg->rtm_table = table;
+ msg->rtm_protocol = protocol;
+ msg->rtm_scope = scope;
+ msg->rtm_type = type;
+ msg->rtm_flags = flags;
+ nlm->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
+
+ // Add destination
+ AddRTA(nlm, RTA_DST, destination.ToPackedString().c_str(),
+ destination.ToPackedString().size());
+
+ // Add egress interface
+ AddRTA(nlm, RTA_OIF, &interface_index, sizeof(interface_index));
+}
+
+TEST_F(NetlinkTest, GetLinkInfoWorks) {
+ auto netlink = QuicMakeUnique<Netlink>(&mock_kernel_);
+
+ uint8_t hwaddr[] = {'a', 'b', 'c', 'd', 'e', 'f'};
+ uint8_t bcaddr[] = {'c', 'b', 'a', 'f', 'e', 'd'};
+
+ ExpectNetlinkPacket(
+ RTM_GETLINK, NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST,
+ [this, &hwaddr, &bcaddr](void* buf, size_t len, int seq) {
+ int ret = 0;
+
+ struct nlmsghdr* netlink_message =
+ CreateNetlinkMessage(buf, nullptr, RTM_NEWLINK, seq);
+ CreateIfinfomsg(netlink_message, "tun0", /* type = */ 1,
+ /* index = */ 7,
+ /* flags = */ 0,
+ /* change = */ 0xFFFFFFFF, hwaddr, 6, bcaddr, 6);
+ ret += NLMSG_ALIGN(netlink_message->nlmsg_len);
+
+ netlink_message =
+ CreateNetlinkMessage(buf, netlink_message, NLMSG_DONE, seq);
+ ret += NLMSG_ALIGN(netlink_message->nlmsg_len);
+
+ return ret;
+ });
+
+ Netlink::LinkInfo link_info;
+ EXPECT_TRUE(netlink->GetLinkInfo("tun0", &link_info));
+
+ EXPECT_EQ(7, link_info.index);
+ EXPECT_EQ(1, link_info.type);
+
+ for (int i = 0; i < link_info.hardware_address_length; ++i) {
+ EXPECT_EQ(hwaddr[i], link_info.hardware_address[i]);
+ }
+ for (int i = 0; i < link_info.broadcast_address_length; ++i) {
+ EXPECT_EQ(bcaddr[i], link_info.broadcast_address[i]);
+ }
+}
+
+TEST_F(NetlinkTest, GetAddressesWorks) {
+ auto netlink = QuicMakeUnique<Netlink>(&mock_kernel_);
+
+ QuicUnorderedSet<std::string> addresses = {QuicIpAddress::Any4().ToString(),
+ QuicIpAddress::Any6().ToString()};
+
+ ExpectNetlinkPacket(
+ RTM_GETADDR, NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST,
+ [this, &addresses](void* buf, size_t len, int seq) {
+ int ret = 0;
+
+ struct nlmsghdr* nlm = nullptr;
+
+ for (const auto& address : addresses) {
+ QuicIpAddress ip;
+ ip.FromString(address);
+ nlm = CreateNetlinkMessage(buf, nlm, RTM_NEWADDR, seq);
+ CreateIfaddrmsg(nlm, /* interface_index = */ 7, /* prefixlen = */ 24,
+ /* flags = */ 0, /* scope = */ RT_SCOPE_UNIVERSE, ip);
+
+ ret += NLMSG_ALIGN(nlm->nlmsg_len);
+ }
+
+ // Create IPs with unwanted flags.
+ {
+ QuicIpAddress ip;
+ ip.FromString("10.0.0.1");
+ nlm = CreateNetlinkMessage(buf, nlm, RTM_NEWADDR, seq);
+ CreateIfaddrmsg(nlm, /* interface_index = */ 7, /* prefixlen = */ 16,
+ /* flags = */ IFA_F_OPTIMISTIC, /* scope = */
+ RT_SCOPE_UNIVERSE, ip);
+
+ ret += NLMSG_ALIGN(nlm->nlmsg_len);
+
+ ip.FromString("10.0.0.2");
+ nlm = CreateNetlinkMessage(buf, nlm, RTM_NEWADDR, seq);
+ CreateIfaddrmsg(nlm, /* interface_index = */ 7, /* prefixlen = */ 16,
+ /* flags = */ IFA_F_TENTATIVE, /* scope = */
+ RT_SCOPE_UNIVERSE, ip);
+
+ ret += NLMSG_ALIGN(nlm->nlmsg_len);
+ }
+
+ nlm = CreateNetlinkMessage(buf, nlm, NLMSG_DONE, seq);
+ ret += NLMSG_ALIGN(nlm->nlmsg_len);
+
+ return ret;
+ });
+
+ std::vector<Netlink::AddressInfo> reported_addresses;
+ int num_ipv6_nodad_dadfailed_addresses = 0;
+ EXPECT_TRUE(netlink->GetAddresses(7, IFA_F_TENTATIVE | IFA_F_OPTIMISTIC,
+ &reported_addresses,
+ &num_ipv6_nodad_dadfailed_addresses));
+
+ for (const auto& reported_address : reported_addresses) {
+ EXPECT_TRUE(reported_address.local_address.IsInitialized());
+ EXPECT_FALSE(reported_address.interface_address.IsInitialized());
+ EXPECT_THAT(addresses, Contains(reported_address.local_address.ToString()));
+ addresses.erase(reported_address.local_address.ToString());
+
+ EXPECT_EQ(24, reported_address.prefix_length);
+ }
+
+ EXPECT_TRUE(addresses.empty());
+}
+
+TEST_F(NetlinkTest, ChangeLocalAddressAdd) {
+ auto netlink = QuicMakeUnique<Netlink>(&mock_kernel_);
+
+ QuicIpAddress ip = QuicIpAddress::Any6();
+ ExpectNetlinkPacket(
+ RTM_NEWADDR, NLM_F_ACK | NLM_F_REQUEST,
+ [](void* buf, size_t len, int seq) {
+ struct nlmsghdr* netlink_message =
+ CreateNetlinkMessage(buf, nullptr, NLMSG_ERROR, seq);
+ auto* err =
+ reinterpret_cast<struct nlmsgerr*>(NLMSG_DATA(netlink_message));
+ // Ack the request
+ err->error = 0;
+ netlink_message->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
+ return netlink_message->nlmsg_len;
+ },
+ [ip](const void* buf, size_t len) {
+ auto* netlink_message = reinterpret_cast<const struct nlmsghdr*>(buf);
+ auto* ifa = reinterpret_cast<const struct ifaddrmsg*>(
+ NLMSG_DATA(netlink_message));
+ EXPECT_EQ(19, ifa->ifa_prefixlen);
+ EXPECT_EQ(RT_SCOPE_UNIVERSE, ifa->ifa_scope);
+ EXPECT_EQ(IFA_F_PERMANENT, ifa->ifa_flags);
+ EXPECT_EQ(7, ifa->ifa_index);
+ EXPECT_EQ(AF_INET6, ifa->ifa_family);
+
+ const struct rtattr* rta;
+ int payload_length = IFA_PAYLOAD(netlink_message);
+ int num_rta = 0;
+ for (rta = IFA_RTA(ifa); RTA_OK(rta, payload_length);
+ rta = RTA_NEXT(rta, payload_length)) {
+ switch (rta->rta_type) {
+ case IFA_LOCAL: {
+ EXPECT_EQ(ip.ToPackedString().size(), RTA_PAYLOAD(rta));
+ const auto* raw_address =
+ reinterpret_cast<const char*>(RTA_DATA(rta));
+ ASSERT_EQ(sizeof(in6_addr), RTA_PAYLOAD(rta));
+ QuicIpAddress address;
+ address.FromPackedString(raw_address, RTA_PAYLOAD(rta));
+ EXPECT_EQ(ip, address);
+ break;
+ }
+ case IFA_CACHEINFO: {
+ EXPECT_EQ(sizeof(struct ifa_cacheinfo), RTA_PAYLOAD(rta));
+ const auto* cache_info =
+ reinterpret_cast<const struct ifa_cacheinfo*>(RTA_DATA(rta));
+ EXPECT_EQ(8, cache_info->ifa_prefered); // common_typos_disable
+ EXPECT_EQ(6, cache_info->ifa_valid);
+ EXPECT_EQ(4, cache_info->cstamp);
+ EXPECT_EQ(2, cache_info->tstamp);
+ break;
+ }
+ default:
+ EXPECT_TRUE(false) << "Seeing rtattr that should not exist";
+ }
+ ++num_rta;
+ }
+ EXPECT_EQ(2, num_rta);
+ });
+
+ struct {
+ struct rtattr rta;
+ struct ifa_cacheinfo cache_info;
+ } additional_rta;
+
+ additional_rta.rta.rta_type = IFA_CACHEINFO;
+ additional_rta.rta.rta_len = RTA_LENGTH(sizeof(struct ifa_cacheinfo));
+ additional_rta.cache_info.ifa_prefered = 8;
+ additional_rta.cache_info.ifa_valid = 6;
+ additional_rta.cache_info.cstamp = 4;
+ additional_rta.cache_info.tstamp = 2;
+
+ EXPECT_TRUE(netlink->ChangeLocalAddress(7, Netlink::Verb::kAdd, ip, 19,
+ IFA_F_PERMANENT, RT_SCOPE_UNIVERSE,
+ {&additional_rta.rta}));
+}
+
+TEST_F(NetlinkTest, ChangeLocalAddressRemove) {
+ auto netlink = QuicMakeUnique<Netlink>(&mock_kernel_);
+
+ QuicIpAddress ip = QuicIpAddress::Any4();
+ ExpectNetlinkPacket(
+ RTM_DELADDR, NLM_F_ACK | NLM_F_REQUEST,
+ [](void* buf, size_t len, int seq) {
+ struct nlmsghdr* netlink_message =
+ CreateNetlinkMessage(buf, nullptr, NLMSG_ERROR, seq);
+ auto* err =
+ reinterpret_cast<struct nlmsgerr*>(NLMSG_DATA(netlink_message));
+ // Ack the request
+ err->error = 0;
+ netlink_message->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
+ return netlink_message->nlmsg_len;
+ },
+ [ip](const void* buf, size_t len) {
+ auto* netlink_message = reinterpret_cast<const struct nlmsghdr*>(buf);
+ auto* ifa = reinterpret_cast<const struct ifaddrmsg*>(
+ NLMSG_DATA(netlink_message));
+ EXPECT_EQ(32, ifa->ifa_prefixlen);
+ EXPECT_EQ(RT_SCOPE_UNIVERSE, ifa->ifa_scope);
+ EXPECT_EQ(0, ifa->ifa_flags);
+ EXPECT_EQ(7, ifa->ifa_index);
+ EXPECT_EQ(AF_INET, ifa->ifa_family);
+
+ const struct rtattr* rta;
+ int payload_length = IFA_PAYLOAD(netlink_message);
+ int num_rta = 0;
+ for (rta = IFA_RTA(ifa); RTA_OK(rta, payload_length);
+ rta = RTA_NEXT(rta, payload_length)) {
+ switch (rta->rta_type) {
+ case IFA_LOCAL: {
+ const auto* raw_address =
+ reinterpret_cast<const char*>(RTA_DATA(rta));
+ ASSERT_EQ(sizeof(in_addr), RTA_PAYLOAD(rta));
+ QuicIpAddress address;
+ address.FromPackedString(raw_address, RTA_PAYLOAD(rta));
+ EXPECT_EQ(ip, address);
+ break;
+ }
+ default:
+ EXPECT_TRUE(false) << "Seeing rtattr that should not exist";
+ }
+ ++num_rta;
+ }
+ EXPECT_EQ(1, num_rta);
+ });
+
+ EXPECT_TRUE(netlink->ChangeLocalAddress(7, Netlink::Verb::kRemove, ip, 32, 0,
+ RT_SCOPE_UNIVERSE, {}));
+}
+
+TEST_F(NetlinkTest, GetRouteInfoWorks) {
+ auto netlink = QuicMakeUnique<Netlink>(&mock_kernel_);
+
+ QuicIpAddress destination;
+ ASSERT_TRUE(destination.FromString("f800::2"));
+ ExpectNetlinkPacket(RTM_GETROUTE, NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST,
+ [destination](void* buf, size_t len, int seq) {
+ int ret = 0;
+ struct nlmsghdr* netlink_message = CreateNetlinkMessage(
+ buf, nullptr, RTM_NEWROUTE, seq);
+ CreateRtmsg(netlink_message, AF_INET6, 48, 0, 0,
+ RT_TABLE_MAIN, RTPROT_STATIC, RT_SCOPE_LINK,
+ RTN_UNICAST, 0, destination, 7);
+ ret += NLMSG_ALIGN(netlink_message->nlmsg_len);
+
+ netlink_message = CreateNetlinkMessage(
+ buf, netlink_message, NLMSG_DONE, seq);
+ ret += NLMSG_ALIGN(netlink_message->nlmsg_len);
+
+ QUIC_LOG(INFO) << "ret: " << ret;
+ return ret;
+ });
+
+ std::vector<Netlink::RoutingRule> routing_rules;
+ EXPECT_TRUE(netlink->GetRouteInfo(&routing_rules));
+
+ ASSERT_EQ(1, routing_rules.size());
+ EXPECT_EQ(RT_SCOPE_LINK, routing_rules[0].scope);
+ EXPECT_EQ(IpRange(destination, 48).ToString(),
+ routing_rules[0].destination_subnet.ToString());
+ EXPECT_FALSE(routing_rules[0].preferred_source.IsInitialized());
+ EXPECT_EQ(7, routing_rules[0].out_interface);
+}
+
+TEST_F(NetlinkTest, ChangeRouteAdd) {
+ auto netlink = QuicMakeUnique<Netlink>(&mock_kernel_);
+
+ QuicIpAddress preferred_ip;
+ preferred_ip.FromString("ff80:dead:beef::1");
+ IpRange subnet;
+ subnet.FromString("ff80:dead:beef::/48");
+ int egress_interface_index = 7;
+ ExpectNetlinkPacket(
+ RTM_NEWROUTE, NLM_F_ACK | NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL,
+ [](void* buf, size_t len, int seq) {
+ struct nlmsghdr* netlink_message =
+ CreateNetlinkMessage(buf, nullptr, NLMSG_ERROR, seq);
+ auto* err =
+ reinterpret_cast<struct nlmsgerr*>(NLMSG_DATA(netlink_message));
+ // Ack the request
+ err->error = 0;
+ netlink_message->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
+ return netlink_message->nlmsg_len;
+ },
+ [preferred_ip, subnet, egress_interface_index](const void* buf,
+ size_t len) {
+ auto* netlink_message = reinterpret_cast<const struct nlmsghdr*>(buf);
+ auto* rtm =
+ reinterpret_cast<const struct rtmsg*>(NLMSG_DATA(netlink_message));
+ EXPECT_EQ(AF_INET6, rtm->rtm_family);
+ EXPECT_EQ(48, rtm->rtm_dst_len);
+ EXPECT_EQ(0, rtm->rtm_src_len);
+ EXPECT_EQ(RT_TABLE_MAIN, rtm->rtm_table);
+ EXPECT_EQ(RTPROT_STATIC, rtm->rtm_protocol);
+ EXPECT_EQ(RT_SCOPE_LINK, rtm->rtm_scope);
+ EXPECT_EQ(RTN_UNICAST, rtm->rtm_type);
+
+ const struct rtattr* rta;
+ int payload_length = RTM_PAYLOAD(netlink_message);
+ int num_rta = 0;
+ for (rta = RTM_RTA(rtm); RTA_OK(rta, payload_length);
+ rta = RTA_NEXT(rta, payload_length)) {
+ switch (rta->rta_type) {
+ case RTA_PREFSRC: {
+ 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(preferred_ip, address);
+ break;
+ }
+ case RTA_OIF: {
+ ASSERT_EQ(sizeof(int), RTA_PAYLOAD(rta));
+ const auto* interface_index =
+ reinterpret_cast<const int*>(RTA_DATA(rta));
+ EXPECT_EQ(egress_interface_index, *interface_index);
+ break;
+ }
+ case RTA_DST: {
+ 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(subnet.ToString(),
+ IpRange(address, rtm->rtm_dst_len).ToString());
+ break;
+ }
+ case RTA_TABLE: {
+ ASSERT_EQ(*reinterpret_cast<uint32_t*>(RTA_DATA(rta)),
+ QboneConstants::kQboneRouteTableId);
+ break;
+ }
+ default:
+ EXPECT_TRUE(false) << "Seeing rtattr that should not be sent";
+ }
+ ++num_rta;
+ }
+ EXPECT_EQ(4, num_rta);
+ });
+ EXPECT_TRUE(netlink->ChangeRoute(
+ Netlink::Verb::kAdd, QboneConstants::kQboneRouteTableId, subnet,
+ RT_SCOPE_LINK, preferred_ip, egress_interface_index));
+}
+
+TEST_F(NetlinkTest, ChangeRouteRemove) {
+ auto netlink = QuicMakeUnique<Netlink>(&mock_kernel_);
+
+ QuicIpAddress preferred_ip;
+ preferred_ip.FromString("ff80:dead:beef::1");
+ IpRange subnet;
+ subnet.FromString("ff80:dead:beef::/48");
+ int egress_interface_index = 7;
+ ExpectNetlinkPacket(
+ RTM_DELROUTE, NLM_F_ACK | NLM_F_REQUEST,
+ [](void* buf, size_t len, int seq) {
+ struct nlmsghdr* netlink_message =
+ CreateNetlinkMessage(buf, nullptr, NLMSG_ERROR, seq);
+ auto* err =
+ reinterpret_cast<struct nlmsgerr*>(NLMSG_DATA(netlink_message));
+ // Ack the request
+ err->error = 0;
+ netlink_message->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
+ return netlink_message->nlmsg_len;
+ },
+ [preferred_ip, subnet, egress_interface_index](const void* buf,
+ size_t len) {
+ auto* netlink_message = reinterpret_cast<const struct nlmsghdr*>(buf);
+ auto* rtm =
+ reinterpret_cast<const struct rtmsg*>(NLMSG_DATA(netlink_message));
+ EXPECT_EQ(AF_INET6, rtm->rtm_family);
+ EXPECT_EQ(48, rtm->rtm_dst_len);
+ EXPECT_EQ(0, rtm->rtm_src_len);
+ EXPECT_EQ(RT_TABLE_MAIN, rtm->rtm_table);
+ EXPECT_EQ(RTPROT_UNSPEC, rtm->rtm_protocol);
+ EXPECT_EQ(RT_SCOPE_LINK, rtm->rtm_scope);
+ EXPECT_EQ(RTN_UNICAST, rtm->rtm_type);
+
+ const struct rtattr* rta;
+ int payload_length = RTM_PAYLOAD(netlink_message);
+ int num_rta = 0;
+ for (rta = RTM_RTA(rtm); RTA_OK(rta, payload_length);
+ rta = RTA_NEXT(rta, payload_length)) {
+ switch (rta->rta_type) {
+ case RTA_PREFSRC: {
+ 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(preferred_ip, address);
+ break;
+ }
+ case RTA_OIF: {
+ ASSERT_EQ(sizeof(int), RTA_PAYLOAD(rta));
+ const auto* interface_index =
+ reinterpret_cast<const int*>(RTA_DATA(rta));
+ EXPECT_EQ(egress_interface_index, *interface_index);
+ break;
+ }
+ case RTA_DST: {
+ 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(subnet.ToString(),
+ IpRange(address, rtm->rtm_dst_len).ToString());
+ break;
+ }
+ case RTA_TABLE: {
+ ASSERT_EQ(*reinterpret_cast<uint32_t*>(RTA_DATA(rta)),
+ QboneConstants::kQboneRouteTableId);
+ break;
+ }
+ default:
+ EXPECT_TRUE(false) << "Seeing rtattr that should not be sent";
+ }
+ ++num_rta;
+ }
+ EXPECT_EQ(4, num_rta);
+ });
+ EXPECT_TRUE(netlink->ChangeRoute(
+ Netlink::Verb::kRemove, QboneConstants::kQboneRouteTableId, subnet,
+ RT_SCOPE_LINK, preferred_ip, egress_interface_index));
+}
+
+TEST_F(NetlinkTest, ChangeRouteReplace) {
+ auto netlink = QuicMakeUnique<Netlink>(&mock_kernel_);
+
+ QuicIpAddress preferred_ip;
+ preferred_ip.FromString("ff80:dead:beef::1");
+ IpRange subnet;
+ subnet.FromString("ff80:dead:beef::/48");
+ int egress_interface_index = 7;
+ ExpectNetlinkPacket(
+ RTM_NEWROUTE, NLM_F_ACK | NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE,
+ [](void* buf, size_t len, int seq) {
+ struct nlmsghdr* netlink_message =
+ CreateNetlinkMessage(buf, nullptr, NLMSG_ERROR, seq);
+ auto* err =
+ reinterpret_cast<struct nlmsgerr*>(NLMSG_DATA(netlink_message));
+ // Ack the request
+ err->error = 0;
+ netlink_message->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
+ return netlink_message->nlmsg_len;
+ },
+ [preferred_ip, subnet, egress_interface_index](const void* buf,
+ size_t len) {
+ auto* netlink_message = reinterpret_cast<const struct nlmsghdr*>(buf);
+ auto* rtm =
+ reinterpret_cast<const struct rtmsg*>(NLMSG_DATA(netlink_message));
+ EXPECT_EQ(AF_INET6, rtm->rtm_family);
+ EXPECT_EQ(48, rtm->rtm_dst_len);
+ EXPECT_EQ(0, rtm->rtm_src_len);
+ EXPECT_EQ(RT_TABLE_MAIN, rtm->rtm_table);
+ EXPECT_EQ(RTPROT_STATIC, rtm->rtm_protocol);
+ EXPECT_EQ(RT_SCOPE_LINK, rtm->rtm_scope);
+ EXPECT_EQ(RTN_UNICAST, rtm->rtm_type);
+
+ const struct rtattr* rta;
+ int payload_length = RTM_PAYLOAD(netlink_message);
+ int num_rta = 0;
+ for (rta = RTM_RTA(rtm); RTA_OK(rta, payload_length);
+ rta = RTA_NEXT(rta, payload_length)) {
+ switch (rta->rta_type) {
+ case RTA_PREFSRC: {
+ 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(preferred_ip, address);
+ break;
+ }
+ case RTA_OIF: {
+ ASSERT_EQ(sizeof(int), RTA_PAYLOAD(rta));
+ const auto* interface_index =
+ reinterpret_cast<const int*>(RTA_DATA(rta));
+ EXPECT_EQ(egress_interface_index, *interface_index);
+ break;
+ }
+ case RTA_DST: {
+ 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(subnet.ToString(),
+ IpRange(address, rtm->rtm_dst_len).ToString());
+ break;
+ }
+ case RTA_TABLE: {
+ ASSERT_EQ(*reinterpret_cast<uint32_t*>(RTA_DATA(rta)),
+ QboneConstants::kQboneRouteTableId);
+ break;
+ }
+ default:
+ EXPECT_TRUE(false) << "Seeing rtattr that should not be sent";
+ }
+ ++num_rta;
+ }
+ EXPECT_EQ(4, num_rta);
+ });
+ EXPECT_TRUE(netlink->ChangeRoute(
+ Netlink::Verb::kReplace, QboneConstants::kQboneRouteTableId, subnet,
+ RT_SCOPE_LINK, preferred_ip, egress_interface_index));
+}
+
+} // namespace
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/platform/rtnetlink_message.cc b/chromium/net/third_party/quiche/src/quic/qbone/platform/rtnetlink_message.cc
new file mode 100644
index 00000000000..f35628a052e
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/platform/rtnetlink_message.cc
@@ -0,0 +1,177 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/qbone/platform/rtnetlink_message.h"
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
+
+namespace quic {
+
+RtnetlinkMessage::RtnetlinkMessage(uint16_t type,
+ uint16_t flags,
+ uint32_t seq,
+ uint32_t pid,
+ const void* payload_header,
+ size_t payload_header_length) {
+ auto* buf = new uint8_t[NLMSG_SPACE(payload_header_length)];
+ memset(buf, 0, NLMSG_SPACE(payload_header_length));
+
+ auto* message_header = reinterpret_cast<struct nlmsghdr*>(buf);
+ message_header->nlmsg_len = NLMSG_LENGTH(payload_header_length);
+ message_header->nlmsg_type = type;
+ message_header->nlmsg_flags = flags;
+ message_header->nlmsg_seq = seq;
+ message_header->nlmsg_pid = pid;
+
+ if (payload_header != nullptr) {
+ memcpy(NLMSG_DATA(message_header), payload_header, payload_header_length);
+ }
+ message_.push_back({buf, NLMSG_SPACE(payload_header_length)});
+}
+
+RtnetlinkMessage::~RtnetlinkMessage() {
+ for (const auto& iov : message_) {
+ delete[] reinterpret_cast<uint8_t*>(iov.iov_base);
+ }
+}
+
+void RtnetlinkMessage::AppendAttribute(uint16_t type,
+ const void* data,
+ uint16_t data_length) {
+ auto* buf = new uint8_t[RTA_SPACE(data_length)];
+ memset(buf, 0, RTA_SPACE(data_length));
+
+ auto* rta = reinterpret_cast<struct rtattr*>(buf);
+ static_assert(sizeof(uint16_t) == sizeof(rta->rta_len),
+ "struct rtattr uses unsigned short, it's no longer 16bits");
+ static_assert(sizeof(uint16_t) == sizeof(rta->rta_type),
+ "struct rtattr uses unsigned short, it's no longer 16bits");
+
+ rta->rta_len = RTA_LENGTH(data_length);
+ rta->rta_type = type;
+ memcpy(RTA_DATA(rta), data, data_length);
+
+ message_.push_back({buf, RTA_SPACE(data_length)});
+ AdjustMessageLength(rta->rta_len);
+}
+
+std::unique_ptr<struct iovec[]> RtnetlinkMessage::BuildIoVec() const {
+ auto message = QuicMakeUnique<struct iovec[]>(message_.size());
+ int idx = 0;
+ for (const auto& vec : message_) {
+ message[idx++] = vec;
+ }
+ return message;
+}
+
+size_t RtnetlinkMessage::IoVecSize() const {
+ return message_.size();
+}
+
+void RtnetlinkMessage::AdjustMessageLength(size_t additional_data_length) {
+ MessageHeader()->nlmsg_len =
+ NLMSG_ALIGN(MessageHeader()->nlmsg_len) + additional_data_length;
+}
+
+struct nlmsghdr* RtnetlinkMessage::MessageHeader() {
+ return reinterpret_cast<struct nlmsghdr*>(message_[0].iov_base);
+}
+
+LinkMessage LinkMessage::New(RtnetlinkMessage::Operation request_operation,
+ uint16_t flags,
+ uint32_t seq,
+ uint32_t pid,
+ const struct ifinfomsg* interface_info_header) {
+ uint16_t request_type;
+ switch (request_operation) {
+ case RtnetlinkMessage::Operation::NEW:
+ request_type = RTM_NEWLINK;
+ break;
+ case RtnetlinkMessage::Operation::DEL:
+ request_type = RTM_DELLINK;
+ break;
+ case RtnetlinkMessage::Operation::GET:
+ request_type = RTM_GETLINK;
+ break;
+ }
+ bool is_get = request_type == RTM_GETLINK;
+
+ if (is_get) {
+ struct rtgenmsg g = {AF_UNSPEC};
+ return LinkMessage(request_type, flags, seq, pid, &g, sizeof(g));
+ }
+ return LinkMessage(request_type, flags, seq, pid, interface_info_header,
+ sizeof(struct ifinfomsg));
+}
+
+AddressMessage AddressMessage::New(
+ RtnetlinkMessage::Operation request_operation,
+ uint16_t flags,
+ uint32_t seq,
+ uint32_t pid,
+ const struct ifaddrmsg* interface_address_header) {
+ uint16_t request_type;
+ switch (request_operation) {
+ case RtnetlinkMessage::Operation::NEW:
+ request_type = RTM_NEWADDR;
+ break;
+ case RtnetlinkMessage::Operation::DEL:
+ request_type = RTM_DELADDR;
+ break;
+ case RtnetlinkMessage::Operation::GET:
+ request_type = RTM_GETADDR;
+ break;
+ }
+ bool is_get = request_type == RTM_GETADDR;
+
+ if (is_get) {
+ struct rtgenmsg g = {AF_UNSPEC};
+ return AddressMessage(request_type, flags, seq, pid, &g, sizeof(g));
+ }
+ return AddressMessage(request_type, flags, seq, pid, interface_address_header,
+ sizeof(struct ifaddrmsg));
+}
+
+RouteMessage RouteMessage::New(RtnetlinkMessage::Operation request_operation,
+ uint16_t flags,
+ uint32_t seq,
+ uint32_t pid,
+ const struct rtmsg* route_message_header) {
+ uint16_t request_type;
+ switch (request_operation) {
+ case RtnetlinkMessage::Operation::NEW:
+ request_type = RTM_NEWROUTE;
+ break;
+ case RtnetlinkMessage::Operation::DEL:
+ request_type = RTM_DELROUTE;
+ break;
+ case RtnetlinkMessage::Operation::GET:
+ request_type = RTM_GETROUTE;
+ break;
+ }
+ return RouteMessage(request_type, flags, seq, pid, route_message_header,
+ sizeof(struct rtmsg));
+}
+
+RuleMessage RuleMessage::New(RtnetlinkMessage::Operation request_operation,
+ uint16_t flags,
+ uint32_t seq,
+ uint32_t pid,
+ const struct rtmsg* rule_message_header) {
+ uint16_t request_type;
+ switch (request_operation) {
+ case RtnetlinkMessage::Operation::NEW:
+ request_type = RTM_NEWRULE;
+ break;
+ case RtnetlinkMessage::Operation::DEL:
+ request_type = RTM_DELRULE;
+ break;
+ case RtnetlinkMessage::Operation::GET:
+ request_type = RTM_GETRULE;
+ break;
+ }
+ return RuleMessage(request_type, flags, seq, pid, rule_message_header,
+ sizeof(rtmsg));
+}
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/platform/rtnetlink_message.h b/chromium/net/third_party/quiche/src/quic/qbone/platform/rtnetlink_message.h
new file mode 100644
index 00000000000..0412d54e3f4
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/platform/rtnetlink_message.h
@@ -0,0 +1,126 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_QBONE_PLATFORM_RTNETLINK_MESSAGE_H_
+#define QUICHE_QUIC_QBONE_PLATFORM_RTNETLINK_MESSAGE_H_
+
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <stdint.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+
+#include <memory>
+#include <vector>
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h"
+
+namespace quic {
+
+// This base class is used to construct an array struct iovec that represents a
+// rtnetlink message as defined in man 7 rtnet. Padding for message header
+// alignment to conform NLMSG_* and RTA_* macros is added at the end of each
+// iovec::iov_base.
+class RtnetlinkMessage {
+ public:
+ virtual ~RtnetlinkMessage();
+
+ enum class Operation {
+ NEW,
+ DEL,
+ GET,
+ };
+
+ // Appends a struct rtattr to the message. nlmsg_len and rta_len is handled
+ // properly.
+ // Override this to perform check on type.
+ virtual void AppendAttribute(uint16_t type,
+ const void* data,
+ uint16_t data_length);
+
+ // Builds the array of iovec that can be fed into sendmsg directly.
+ std::unique_ptr<struct iovec[]> BuildIoVec() const;
+
+ // The size of the array of iovec if BuildIovec is called.
+ size_t IoVecSize() const;
+
+ protected:
+ // Subclass should add their own message header immediately after the
+ // nlmsghdr. Make this private to force the creation of such header.
+ RtnetlinkMessage(uint16_t type,
+ uint16_t flags,
+ uint32_t seq,
+ uint32_t pid,
+ const void* payload_header,
+ size_t payload_header_length);
+
+ // Adjusts nlmsg_len in the header assuming additional_data_length is appended
+ // at the end.
+ void AdjustMessageLength(size_t additional_data_length);
+
+ private:
+ // Convenient function for accessing the nlmsghdr.
+ struct nlmsghdr* MessageHeader();
+
+ std::vector<struct iovec> message_;
+};
+
+// Message for manipulating link level configuration as defined in man 7
+// rtnetlink. RTM_NEWLINK, RTM_DELLINK and RTM_GETLINK are supported.
+class LinkMessage : public RtnetlinkMessage {
+ public:
+ static LinkMessage New(RtnetlinkMessage::Operation request_operation,
+ uint16_t flags,
+ uint32_t seq,
+ uint32_t pid,
+ const struct ifinfomsg* interface_info_header);
+
+ private:
+ using RtnetlinkMessage::RtnetlinkMessage;
+};
+
+// Message for manipulating address level configuration as defined in man 7
+// rtnetlink. RTM_NEWADDR, RTM_NEWADDR and RTM_GETADDR are supported.
+class AddressMessage : public RtnetlinkMessage {
+ public:
+ static AddressMessage New(RtnetlinkMessage::Operation request_operation,
+ uint16_t flags,
+ uint32_t seq,
+ uint32_t pid,
+ const struct ifaddrmsg* interface_address_header);
+
+ private:
+ using RtnetlinkMessage::RtnetlinkMessage;
+};
+
+// Message for manipulating routing table as defined in man 7 rtnetlink.
+// RTM_NEWROUTE, RTM_DELROUTE and RTM_GETROUTE are supported.
+class RouteMessage : public RtnetlinkMessage {
+ public:
+ static RouteMessage New(RtnetlinkMessage::Operation request_operation,
+ uint16_t flags,
+ uint32_t seq,
+ uint32_t pid,
+ const struct rtmsg* route_message_header);
+
+ private:
+ using RtnetlinkMessage::RtnetlinkMessage;
+};
+
+class RuleMessage : public RtnetlinkMessage {
+ public:
+ static RuleMessage New(RtnetlinkMessage::Operation request_operation,
+ uint16_t flags,
+ uint32_t seq,
+ uint32_t pid,
+ const struct rtmsg* rule_message_header);
+
+ private:
+ using RtnetlinkMessage::RtnetlinkMessage;
+};
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_QBONE_PLATFORM_RTNETLINK_MESSAGE_H_
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/platform/rtnetlink_message_test.cc b/chromium/net/third_party/quiche/src/quic/qbone/platform/rtnetlink_message_test.cc
new file mode 100644
index 00000000000..b1292373358
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/platform/rtnetlink_message_test.cc
@@ -0,0 +1,228 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/qbone/platform/rtnetlink_message.h"
+
+#include <net/if_arp.h>
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+
+namespace quic {
+namespace {
+
+using ::testing::StrEq;
+
+TEST(RtnetlinkMessageTest, LinkMessageCanBeCreatedForGetOperation) {
+ uint16_t flags = NLM_F_REQUEST | NLM_F_ROOT | NLM_F_MATCH;
+ uint32_t seq = 42;
+ uint32_t pid = 7;
+ auto message = LinkMessage::New(RtnetlinkMessage::Operation::GET, flags, seq,
+ pid, nullptr);
+
+ // No rtattr appended.
+ EXPECT_EQ(1, message.IoVecSize());
+
+ // nlmsghdr is built properly.
+ auto iov = message.BuildIoVec();
+ EXPECT_EQ(NLMSG_SPACE(sizeof(struct rtgenmsg)), iov[0].iov_len);
+ auto* netlink_message = reinterpret_cast<struct nlmsghdr*>(iov[0].iov_base);
+ EXPECT_EQ(NLMSG_LENGTH(sizeof(struct rtgenmsg)), netlink_message->nlmsg_len);
+ EXPECT_EQ(RTM_GETLINK, netlink_message->nlmsg_type);
+ EXPECT_EQ(flags, netlink_message->nlmsg_flags);
+ EXPECT_EQ(seq, netlink_message->nlmsg_seq);
+ EXPECT_EQ(pid, netlink_message->nlmsg_pid);
+
+ // We actually included rtgenmsg instead of the passed in ifinfomsg since this
+ // is a GET operation.
+ EXPECT_EQ(NLMSG_LENGTH(sizeof(struct rtgenmsg)), netlink_message->nlmsg_len);
+}
+
+TEST(RtnetlinkMessageTest, LinkMessageCanBeCreatedForNewOperation) {
+ struct ifinfomsg interface_info_header = {AF_INET, /* pad */ 0, ARPHRD_TUNNEL,
+ 3, 0, 0xffffffff};
+ uint16_t flags = NLM_F_REQUEST | NLM_F_ROOT | NLM_F_MATCH;
+ uint32_t seq = 42;
+ uint32_t pid = 7;
+ auto message = LinkMessage::New(RtnetlinkMessage::Operation::NEW, flags, seq,
+ pid, &interface_info_header);
+
+ string device_name = "device0";
+ message.AppendAttribute(IFLA_IFNAME, device_name.c_str(), device_name.size());
+
+ // One rtattr appended.
+ EXPECT_EQ(2, message.IoVecSize());
+
+ // nlmsghdr is built properly.
+ auto iov = message.BuildIoVec();
+ EXPECT_EQ(NLMSG_ALIGN(NLMSG_LENGTH(sizeof(struct ifinfomsg))),
+ iov[0].iov_len);
+ auto* netlink_message = reinterpret_cast<struct nlmsghdr*>(iov[0].iov_base);
+ EXPECT_EQ(NLMSG_ALIGN(NLMSG_LENGTH(sizeof(struct ifinfomsg))) +
+ RTA_LENGTH(device_name.size()),
+ netlink_message->nlmsg_len);
+ EXPECT_EQ(RTM_NEWLINK, netlink_message->nlmsg_type);
+ EXPECT_EQ(flags, netlink_message->nlmsg_flags);
+ EXPECT_EQ(seq, netlink_message->nlmsg_seq);
+ EXPECT_EQ(pid, netlink_message->nlmsg_pid);
+
+ // ifinfomsg is included properly.
+ auto* parsed_header =
+ reinterpret_cast<struct ifinfomsg*>(NLMSG_DATA(netlink_message));
+ EXPECT_EQ(interface_info_header.ifi_family, parsed_header->ifi_family);
+ EXPECT_EQ(interface_info_header.ifi_type, parsed_header->ifi_type);
+ EXPECT_EQ(interface_info_header.ifi_index, parsed_header->ifi_index);
+ EXPECT_EQ(interface_info_header.ifi_flags, parsed_header->ifi_flags);
+ EXPECT_EQ(interface_info_header.ifi_change, parsed_header->ifi_change);
+
+ // rtattr is handled properly.
+ EXPECT_EQ(RTA_SPACE(device_name.size()), iov[1].iov_len);
+ auto* rta = reinterpret_cast<struct rtattr*>(iov[1].iov_base);
+ EXPECT_EQ(IFLA_IFNAME, rta->rta_type);
+ EXPECT_EQ(RTA_LENGTH(device_name.size()), rta->rta_len);
+ EXPECT_THAT(device_name, StrEq(string(reinterpret_cast<char*>(RTA_DATA(rta)),
+ RTA_PAYLOAD(rta))));
+}
+
+TEST(RtnetlinkMessageTest, AddressMessageCanBeCreatedForGetOperation) {
+ uint16_t flags = NLM_F_REQUEST | NLM_F_ROOT | NLM_F_MATCH;
+ uint32_t seq = 42;
+ uint32_t pid = 7;
+ auto message = AddressMessage::New(RtnetlinkMessage::Operation::GET, flags,
+ seq, pid, nullptr);
+
+ // No rtattr appended.
+ EXPECT_EQ(1, message.IoVecSize());
+
+ // nlmsghdr is built properly.
+ auto iov = message.BuildIoVec();
+ EXPECT_EQ(NLMSG_SPACE(sizeof(struct rtgenmsg)), iov[0].iov_len);
+ auto* netlink_message = reinterpret_cast<struct nlmsghdr*>(iov[0].iov_base);
+ EXPECT_EQ(NLMSG_LENGTH(sizeof(struct rtgenmsg)), netlink_message->nlmsg_len);
+ EXPECT_EQ(RTM_GETADDR, netlink_message->nlmsg_type);
+ EXPECT_EQ(flags, netlink_message->nlmsg_flags);
+ EXPECT_EQ(seq, netlink_message->nlmsg_seq);
+ EXPECT_EQ(pid, netlink_message->nlmsg_pid);
+
+ // We actually included rtgenmsg instead of the passed in ifinfomsg since this
+ // is a GET operation.
+ EXPECT_EQ(NLMSG_LENGTH(sizeof(struct rtgenmsg)), netlink_message->nlmsg_len);
+}
+
+TEST(RtnetlinkMessageTest, AddressMessageCanBeCreatedForNewOperation) {
+ struct ifaddrmsg interface_address_header = {AF_INET,
+ /* prefixlen */ 24,
+ /* flags */ 0,
+ /* scope */ RT_SCOPE_LINK,
+ /* index */ 4};
+ uint16_t flags = NLM_F_REQUEST | NLM_F_ROOT | NLM_F_MATCH;
+ uint32_t seq = 42;
+ uint32_t pid = 7;
+ auto message = AddressMessage::New(RtnetlinkMessage::Operation::NEW, flags,
+ seq, pid, &interface_address_header);
+
+ QuicIpAddress ip;
+ CHECK(ip.FromString("10.0.100.3"));
+ message.AppendAttribute(IFA_ADDRESS, ip.ToPackedString().c_str(),
+ ip.ToPackedString().size());
+
+ // One rtattr is appended.
+ EXPECT_EQ(2, message.IoVecSize());
+
+ // nlmsghdr is built properly.
+ auto iov = message.BuildIoVec();
+ EXPECT_EQ(NLMSG_ALIGN(NLMSG_LENGTH(sizeof(struct ifaddrmsg))),
+ iov[0].iov_len);
+ auto* netlink_message = reinterpret_cast<struct nlmsghdr*>(iov[0].iov_base);
+ EXPECT_EQ(NLMSG_ALIGN(NLMSG_LENGTH(sizeof(struct ifaddrmsg))) +
+ RTA_LENGTH(ip.ToPackedString().size()),
+ netlink_message->nlmsg_len);
+ EXPECT_EQ(RTM_NEWADDR, netlink_message->nlmsg_type);
+ EXPECT_EQ(flags, netlink_message->nlmsg_flags);
+ EXPECT_EQ(seq, netlink_message->nlmsg_seq);
+ EXPECT_EQ(pid, netlink_message->nlmsg_pid);
+
+ // ifaddrmsg is included properly.
+ auto* parsed_header =
+ reinterpret_cast<struct ifaddrmsg*>(NLMSG_DATA(netlink_message));
+ EXPECT_EQ(interface_address_header.ifa_family, parsed_header->ifa_family);
+ EXPECT_EQ(interface_address_header.ifa_prefixlen,
+ parsed_header->ifa_prefixlen);
+ EXPECT_EQ(interface_address_header.ifa_flags, parsed_header->ifa_flags);
+ EXPECT_EQ(interface_address_header.ifa_scope, parsed_header->ifa_scope);
+ EXPECT_EQ(interface_address_header.ifa_index, parsed_header->ifa_index);
+
+ // rtattr is handled properly.
+ EXPECT_EQ(RTA_SPACE(ip.ToPackedString().size()), iov[1].iov_len);
+ auto* rta = reinterpret_cast<struct rtattr*>(iov[1].iov_base);
+ EXPECT_EQ(IFA_ADDRESS, rta->rta_type);
+ EXPECT_EQ(RTA_LENGTH(ip.ToPackedString().size()), rta->rta_len);
+ EXPECT_THAT(
+ ip.ToPackedString(),
+ StrEq(string(reinterpret_cast<char*>(RTA_DATA(rta)), RTA_PAYLOAD(rta))));
+}
+
+TEST(RtnetlinkMessageTest, RouteMessageCanBeCreatedFromNewOperation) {
+ struct rtmsg route_message_header = {AF_INET6,
+ /* rtm_dst_len */ 48,
+ /* rtm_src_len */ 0,
+ /* rtm_tos */ 0,
+ /* rtm_table */ RT_TABLE_MAIN,
+ /* rtm_protocol */ RTPROT_STATIC,
+ /* rtm_scope */ RT_SCOPE_LINK,
+ /* rtm_type */ RTN_LOCAL,
+ /* rtm_flags */ 0};
+ uint16_t flags = NLM_F_REQUEST | NLM_F_ROOT | NLM_F_MATCH;
+ uint32_t seq = 42;
+ uint32_t pid = 7;
+ auto message = RouteMessage::New(RtnetlinkMessage::Operation::NEW, flags, seq,
+ pid, &route_message_header);
+
+ QuicIpAddress preferred_source;
+ CHECK(preferred_source.FromString("ff80::1"));
+ message.AppendAttribute(RTA_PREFSRC,
+ preferred_source.ToPackedString().c_str(),
+ preferred_source.ToPackedString().size());
+
+ // One rtattr is appended.
+ EXPECT_EQ(2, message.IoVecSize());
+
+ // nlmsghdr is built properly
+ auto iov = message.BuildIoVec();
+ EXPECT_EQ(NLMSG_ALIGN(NLMSG_LENGTH(sizeof(struct rtmsg))), iov[0].iov_len);
+ auto* netlink_message = reinterpret_cast<struct nlmsghdr*>(iov[0].iov_base);
+ EXPECT_EQ(NLMSG_ALIGN(NLMSG_LENGTH(sizeof(struct rtmsg))) +
+ RTA_LENGTH(preferred_source.ToPackedString().size()),
+ netlink_message->nlmsg_len);
+ EXPECT_EQ(RTM_NEWROUTE, netlink_message->nlmsg_type);
+ EXPECT_EQ(flags, netlink_message->nlmsg_flags);
+ EXPECT_EQ(seq, netlink_message->nlmsg_seq);
+ EXPECT_EQ(pid, netlink_message->nlmsg_pid);
+
+ // rtmsg is included properly.
+ auto* parsed_header =
+ reinterpret_cast<struct rtmsg*>(NLMSG_DATA(netlink_message));
+ EXPECT_EQ(route_message_header.rtm_family, parsed_header->rtm_family);
+ EXPECT_EQ(route_message_header.rtm_dst_len, parsed_header->rtm_dst_len);
+ EXPECT_EQ(route_message_header.rtm_src_len, parsed_header->rtm_src_len);
+ EXPECT_EQ(route_message_header.rtm_tos, parsed_header->rtm_tos);
+ EXPECT_EQ(route_message_header.rtm_table, parsed_header->rtm_table);
+ EXPECT_EQ(route_message_header.rtm_protocol, parsed_header->rtm_protocol);
+ EXPECT_EQ(route_message_header.rtm_scope, parsed_header->rtm_scope);
+ EXPECT_EQ(route_message_header.rtm_type, parsed_header->rtm_type);
+ EXPECT_EQ(route_message_header.rtm_flags, parsed_header->rtm_flags);
+
+ // rtattr is handled properly.
+ EXPECT_EQ(RTA_SPACE(preferred_source.ToPackedString().size()),
+ iov[1].iov_len);
+ auto* rta = reinterpret_cast<struct rtattr*>(iov[1].iov_base);
+ EXPECT_EQ(RTA_PREFSRC, rta->rta_type);
+ EXPECT_EQ(RTA_LENGTH(preferred_source.ToPackedString().size()), rta->rta_len);
+ EXPECT_THAT(
+ preferred_source.ToPackedString(),
+ StrEq(string(reinterpret_cast<char*>(RTA_DATA(rta)), RTA_PAYLOAD(rta))));
+}
+
+} // namespace
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/platform/tcp_packet.cc b/chromium/net/third_party/quiche/src/quic/qbone/platform/tcp_packet.cc
new file mode 100644
index 00000000000..56fa88ab2d3
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/platform/tcp_packet.cc
@@ -0,0 +1,125 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/qbone/platform/tcp_packet.h"
+
+#include <netinet/ip6.h>
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_endian.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
+#include "net/third_party/quiche/src/quic/qbone/platform/internet_checksum.h"
+
+namespace quic {
+namespace {
+
+constexpr size_t kIPv6AddressSize = sizeof(in6_addr);
+constexpr size_t kTcpTtl = 64;
+
+struct TCPv6Packet {
+ ip6_hdr ip_header;
+ tcphdr tcp_header;
+};
+
+struct TCPv6PseudoHeader {
+ uint32_t payload_size{};
+ uint8_t zeros[3] = {0, 0, 0};
+ uint8_t next_header = IPPROTO_TCP;
+};
+
+} // namespace
+
+void CreateTcpResetPacket(
+ quic::QuicStringPiece original_packet,
+ const std::function<void(quic::QuicStringPiece)>& cb) {
+ // By the time this method is called, original_packet should be fairly
+ // strongly validated. However, it's better to be more paranoid than not, so
+ // here are a bunch of very obvious checks.
+ if (QUIC_PREDICT_FALSE(original_packet.size() < sizeof(ip6_hdr))) {
+ return;
+ }
+ auto* ip6_header = reinterpret_cast<const ip6_hdr*>(original_packet.data());
+ if (QUIC_PREDICT_FALSE(ip6_header->ip6_vfc >> 4 != 6)) {
+ return;
+ }
+ if (QUIC_PREDICT_FALSE(ip6_header->ip6_nxt != IPPROTO_TCP)) {
+ return;
+ }
+ if (QUIC_PREDICT_FALSE(QuicEndian::NetToHost16(ip6_header->ip6_plen) <
+ sizeof(tcphdr))) {
+ return;
+ }
+ auto* tcp_header = reinterpret_cast<const tcphdr*>(ip6_header + 1);
+
+ // Now that the original packet has been confirmed to be well-formed, it's
+ // time to make the TCP RST packet.
+ TCPv6Packet tcp_packet{};
+
+ const size_t payload_size = sizeof(tcphdr);
+
+ // Set version to 6.
+ tcp_packet.ip_header.ip6_vfc = 0x6 << 4;
+ // Set the payload size, protocol and TTL.
+ tcp_packet.ip_header.ip6_plen = QuicEndian::HostToNet16(payload_size);
+ tcp_packet.ip_header.ip6_nxt = IPPROTO_TCP;
+ tcp_packet.ip_header.ip6_hops = kTcpTtl;
+ // Since the TCP RST is impersonating the endpoint, flip the source and
+ // destination addresses from the original packet.
+ tcp_packet.ip_header.ip6_src = ip6_header->ip6_dst;
+ tcp_packet.ip_header.ip6_dst = ip6_header->ip6_src;
+
+ // The same is true about the TCP ports
+ tcp_packet.tcp_header.dest = tcp_header->source;
+ tcp_packet.tcp_header.source = tcp_header->dest;
+
+ // There are no extensions in this header, so size is trivial
+ tcp_packet.tcp_header.doff = sizeof(tcphdr) >> 2;
+ // Checksum is 0 before it is computed
+ tcp_packet.tcp_header.check = 0;
+
+ // Per RFC 793, TCP RST comes in one of 3 flavors:
+ //
+ // * connection CLOSED
+ // * connection in non-synchronized state (LISTEN, SYN-SENT, SYN-RECEIVED)
+ // * connection in synchronized state (ESTABLISHED, FIN-WAIT-1, etc.)
+ //
+ // QBONE is acting like a firewall, so the RFC text of interest is the CLOSED
+ // state. Note, however, that it is possible for a connection to actually be
+ // in the FIN-WAIT-1 state on the remote end, but the processing logic does
+ // not change.
+ tcp_packet.tcp_header.rst = 1;
+
+ // If the incoming segment has an ACK field, the reset takes its sequence
+ // number from the ACK field of the segment,
+ if (tcp_header->ack) {
+ tcp_packet.tcp_header.seq = tcp_header->ack_seq;
+ } else {
+ // Otherwise the reset has sequence number zero and the ACK field is set to
+ // the sum of the sequence number and segment length of the incoming segment
+ tcp_packet.tcp_header.ack = 1;
+ tcp_packet.tcp_header.seq = 0;
+ tcp_packet.tcp_header.ack_seq =
+ QuicEndian::HostToNet32(QuicEndian::NetToHost32(tcp_header->seq) + 1);
+ }
+
+ TCPv6PseudoHeader pseudo_header{};
+ pseudo_header.payload_size = QuicEndian::HostToNet32(payload_size);
+
+ InternetChecksum checksum;
+ // Pseudoheader.
+ checksum.Update(tcp_packet.ip_header.ip6_src.s6_addr, kIPv6AddressSize);
+ checksum.Update(tcp_packet.ip_header.ip6_dst.s6_addr, kIPv6AddressSize);
+ checksum.Update(reinterpret_cast<char*>(&pseudo_header),
+ sizeof(pseudo_header));
+ // TCP header.
+ checksum.Update(reinterpret_cast<const char*>(&tcp_packet.tcp_header),
+ sizeof(tcp_packet.tcp_header));
+ // There is no body.
+ tcp_packet.tcp_header.check = checksum.Value();
+
+ const char* packet = reinterpret_cast<char*>(&tcp_packet);
+
+ cb(QuicStringPiece(packet, sizeof(tcp_packet)));
+}
+
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/platform/tcp_packet.h b/chromium/net/third_party/quiche/src/quic/qbone/platform/tcp_packet.h
new file mode 100644
index 00000000000..cf33f03709d
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/platform/tcp_packet.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_QBONE_PLATFORM_TCP_PACKET_H_
+#define QUICHE_QUIC_QBONE_PLATFORM_TCP_PACKET_H_
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+#include <functional>
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
+
+namespace quic {
+
+// Creates an TCPv6 RST packet, returning a packed string representation of the
+// packet to |cb|.
+void CreateTcpResetPacket(quic::QuicStringPiece original_packet,
+ const std::function<void(quic::QuicStringPiece)>& cb);
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_QBONE_PLATFORM_TCP_PACKET_H_
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/platform/tcp_packet_test.cc b/chromium/net/third_party/quiche/src/quic/qbone/platform/tcp_packet_test.cc
new file mode 100644
index 00000000000..53a2c3f9c01
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/platform/tcp_packet_test.cc
@@ -0,0 +1,116 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/qbone/platform/tcp_packet.h"
+
+#include <netinet/ip6.h>
+
+#include <cstdint>
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
+
+namespace quic {
+namespace {
+
+// clang-format off
+constexpr uint8_t kReferenceTCPSYNPacket[] = {
+ // START IPv6 Header
+ // IPv6 with zero ToS and flow label
+ 0x60, 0x00, 0x00, 0x00,
+ // Payload is 40 bytes
+ 0x00, 0x28,
+ // Next header is TCP (6)
+ 0x06,
+ // Hop limit is 64
+ 0x40,
+ // Source address of ::1
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ // Destination address of ::1
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ // END IPv6 Header
+ // START TCPv6 Header
+ // Source port
+ 0xac, 0x1e,
+ // Destination port
+ 0x27, 0x0f,
+ // Sequence number
+ 0x4b, 0x01, 0xe8, 0x99,
+ // Acknowledgement Sequence number,
+ 0x00, 0x00, 0x00, 0x00,
+ // Offset
+ 0xa0,
+ // Flags
+ 0x02,
+ // Window
+ 0xaa, 0xaa,
+ // Checksum
+ 0x2e, 0x21,
+ // Urgent
+ 0x00, 0x00,
+ // END TCPv6 Header
+ // Options
+ 0x02, 0x04, 0xff, 0xc4, 0x04, 0x02, 0x08, 0x0a,
+ 0x1b, 0xb8, 0x52, 0xa1, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x03, 0x03, 0x07,
+};
+
+constexpr uint8_t kReferenceTCPRSTPacket[] = {
+ // START IPv6 Header
+ // IPv6 with zero ToS and flow label
+ 0x60, 0x00, 0x00, 0x00,
+ // Payload is 20 bytes
+ 0x00, 0x14,
+ // Next header is TCP (6)
+ 0x06,
+ // Hop limit is 64
+ 0x40,
+ // Source address of ::1
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ // Destination address of ::1
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ // END IPv6 Header
+ // START TCPv6 Header
+ // Source port
+ 0x27, 0x0f,
+ // Destination port
+ 0xac, 0x1e,
+ // Sequence number
+ 0x00, 0x00, 0x00, 0x00,
+ // Acknowledgement Sequence number,
+ 0x4b, 0x01, 0xe8, 0x9a,
+ // Offset
+ 0x50,
+ // Flags
+ 0x14,
+ // Window
+ 0x00, 0x00,
+ // Checksum
+ 0xa9, 0x05,
+ // Urgent
+ 0x00, 0x00,
+ // END TCPv6 Header
+};
+// clang-format on
+
+} // namespace
+
+TEST(TcpPacketTest, CreatedPacketMatchesReference) {
+ QuicStringPiece syn =
+ QuicStringPiece(reinterpret_cast<const char*>(kReferenceTCPSYNPacket),
+ sizeof(kReferenceTCPSYNPacket));
+ QuicStringPiece expected_packet =
+ QuicStringPiece(reinterpret_cast<const char*>(kReferenceTCPRSTPacket),
+ sizeof(kReferenceTCPRSTPacket));
+ CreateTcpResetPacket(syn, [&expected_packet](QuicStringPiece packet) {
+ QUIC_LOG(INFO) << QuicTextUtils::HexDump(packet);
+ ASSERT_EQ(packet, expected_packet);
+ });
+}
+
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/qbone_client.cc b/chromium/net/third_party/quiche/src/quic/qbone/qbone_client.cc
new file mode 100644
index 00000000000..f062d3f92e5
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_client.cc
@@ -0,0 +1,98 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/qbone/qbone_client.h"
+
+#include "net/third_party/quiche/src/quic/core/quic_epoll_alarm_factory.h"
+#include "net/third_party/quiche/src/quic/core/quic_epoll_connection_helper.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_epoll.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_exported_stats.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
+#include "net/third_party/quiche/src/quic/qbone/qbone_stream.h"
+
+namespace quic {
+namespace {
+std::unique_ptr<QuicClientBase::NetworkHelper> CreateNetworkHelper(
+ QuicEpollServer* epoll_server,
+ QboneClient* client) {
+ std::unique_ptr<QuicClientBase::NetworkHelper> helper =
+ QuicMakeUnique<QuicClientEpollNetworkHelper>(epoll_server, client);
+ testing::testvalue::Adjust("QboneClient/network_helper", &helper);
+ return helper;
+}
+} // namespace
+
+QboneClient::QboneClient(QuicSocketAddress server_address,
+ const QuicServerId& server_id,
+ const ParsedQuicVersionVector& supported_versions,
+ QuicSession::Visitor* session_owner,
+ const QuicConfig& config,
+ QuicEpollServer* epoll_server,
+ std::unique_ptr<ProofVerifier> proof_verifier,
+ QbonePacketWriter* qbone_writer,
+ QboneClientControlStream::Handler* qbone_handler)
+ : QuicClientBase(
+ server_id,
+ supported_versions,
+ config,
+ new QuicEpollConnectionHelper(epoll_server, QuicAllocator::SIMPLE),
+ new QuicEpollAlarmFactory(epoll_server),
+ CreateNetworkHelper(epoll_server, this),
+ std::move(proof_verifier)),
+ qbone_writer_(qbone_writer),
+ qbone_handler_(qbone_handler),
+ session_owner_(session_owner) {
+ set_server_address(server_address);
+ crypto_config()->set_alpn("qbone");
+}
+
+QboneClient::~QboneClient() {
+ ResetSession();
+}
+
+QboneClientSession* QboneClient::qbone_session() {
+ return static_cast<QboneClientSession*>(QuicClientBase::session());
+}
+
+void QboneClient::ProcessPacketFromNetwork(QuicStringPiece packet) {
+ qbone_session()->ProcessPacketFromNetwork(packet);
+}
+
+int QboneClient::GetNumSentClientHellosFromSession() {
+ return qbone_session()->GetNumSentClientHellos();
+}
+
+int QboneClient::GetNumReceivedServerConfigUpdatesFromSession() {
+ return qbone_session()->GetNumReceivedServerConfigUpdates();
+}
+
+void QboneClient::ResendSavedData() {
+ // no op.
+}
+
+void QboneClient::ClearDataToResend() {
+ // no op.
+}
+
+bool QboneClient::HasActiveRequests() {
+ return qbone_session()->HasActiveRequests();
+}
+
+class QboneClientSessionWithConnection : public QboneClientSession {
+ public:
+ using QboneClientSession::QboneClientSession;
+
+ ~QboneClientSessionWithConnection() override { delete connection(); }
+};
+
+// Takes ownership of |connection|.
+std::unique_ptr<QuicSession> QboneClient::CreateQuicClientSession(
+ const ParsedQuicVersionVector& supported_versions,
+ QuicConnection* connection) {
+ return QuicMakeUnique<QboneClientSessionWithConnection>(
+ connection, crypto_config(), session_owner(), *config(),
+ supported_versions, server_id(), qbone_writer_, qbone_handler_);
+}
+
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/qbone_client.h b/chromium/net/third_party/quiche/src/quic/qbone/qbone_client.h
new file mode 100644
index 00000000000..a0fe4fc70dd
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_client.h
@@ -0,0 +1,74 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_QBONE_QBONE_CLIENT_H_
+#define QUICHE_QUIC_QBONE_QBONE_CLIENT_H_
+
+#include "net/third_party/quiche/src/quic/qbone/qbone_client_interface.h"
+#include "net/third_party/quiche/src/quic/qbone/qbone_client_session.h"
+#include "net/third_party/quiche/src/quic/qbone/qbone_packet_writer.h"
+#include "net/third_party/quiche/src/quic/tools/quic_client_base.h"
+#include "net/third_party/quiche/src/quic/tools/quic_client_epoll_network_helper.h"
+
+namespace quic {
+// A QboneClient encapsulates connecting to a server via an epoll server
+// and setting up a Qbone tunnel. See the QboneTestClient in qbone_client_test
+// for usage.
+class QboneClient : public QuicClientBase, public QboneClientInterface {
+ public:
+ // Note that the epoll server, qbone writer, and handler are owned
+ // by the caller.
+ QboneClient(QuicSocketAddress server_address,
+ const QuicServerId& server_id,
+ const ParsedQuicVersionVector& supported_versions,
+ QuicSession::Visitor* session_owner,
+ const QuicConfig& config,
+ QuicEpollServer* epoll_server,
+ std::unique_ptr<ProofVerifier> proof_verifier,
+ QbonePacketWriter* qbone_writer,
+ QboneClientControlStream::Handler* qbone_handler);
+ ~QboneClient() override;
+ QboneClientSession* qbone_session();
+
+ // From QboneClientInterface. Accepts a given packet from the network and
+ // sends the packet down to the QBONE connection.
+ void ProcessPacketFromNetwork(QuicStringPiece packet) override;
+
+ protected:
+ int GetNumSentClientHellosFromSession() override;
+ int GetNumReceivedServerConfigUpdatesFromSession() override;
+
+ // This client does not resend saved data. This will be a no-op.
+ void ResendSavedData() override;
+
+ // This client does not resend saved data. This will be a no-op.
+ void ClearDataToResend() override;
+
+ // Takes ownership of |connection|.
+ std::unique_ptr<QuicSession> CreateQuicClientSession(
+ const ParsedQuicVersionVector& supported_versions,
+ QuicConnection* connection) override;
+
+ QbonePacketWriter* qbone_writer() { return qbone_writer_; }
+
+ QboneClientControlStream::Handler* qbone_control_handler() {
+ return qbone_handler_;
+ }
+
+ QuicSession::Visitor* session_owner() {
+ return session_owner_;
+ }
+
+ bool HasActiveRequests() override;
+
+ private:
+ QbonePacketWriter* qbone_writer_;
+ QboneClientControlStream::Handler* qbone_handler_;
+
+ QuicSession::Visitor* session_owner_;
+};
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_QBONE_QBONE_CLIENT_H_
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/qbone_client_interface.h b/chromium/net/third_party/quiche/src/quic/qbone/qbone_client_interface.h
new file mode 100644
index 00000000000..28d88ac24ad
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_client_interface.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_QBONE_QBONE_CLIENT_INTERFACE_H_
+#define QUICHE_QUIC_QBONE_QBONE_CLIENT_INTERFACE_H_
+
+#include <cstdint>
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
+
+namespace quic {
+
+// An interface that includes methods to interact with a QBONE client.
+class QboneClientInterface {
+ public:
+ virtual ~QboneClientInterface() {}
+ // Accepts a given packet from the network and sends the packet down to the
+ // QBONE connection.
+ virtual void ProcessPacketFromNetwork(QuicStringPiece packet) = 0;
+};
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_QBONE_QBONE_CLIENT_INTERFACE_H_
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/qbone_client_session.cc b/chromium/net/third_party/quiche/src/quic/qbone/qbone_client_session.cc
new file mode 100644
index 00000000000..c2972ea5dae
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_client_session.cc
@@ -0,0 +1,87 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/qbone/qbone_client_session.h"
+
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
+#include "net/third_party/quiche/src/quic/qbone/qbone_constants.h"
+
+namespace quic {
+
+QboneClientSession::QboneClientSession(
+ QuicConnection* connection,
+ QuicCryptoClientConfig* quic_crypto_client_config,
+ QuicSession::Visitor* owner,
+ const QuicConfig& config,
+ const ParsedQuicVersionVector& supported_versions,
+ const QuicServerId& server_id,
+ QbonePacketWriter* writer,
+ QboneClientControlStream::Handler* handler)
+ : QboneSessionBase(connection, owner, config, supported_versions, writer),
+ server_id_(server_id),
+ quic_crypto_client_config_(quic_crypto_client_config),
+ handler_(handler) {}
+
+QboneClientSession::~QboneClientSession() {}
+
+std::unique_ptr<QuicCryptoStream> QboneClientSession::CreateCryptoStream() {
+ return QuicMakeUnique<QuicCryptoClientStream>(
+ server_id_, this, nullptr, quic_crypto_client_config_, this);
+}
+
+void QboneClientSession::Initialize() {
+ // Initialize must be called first, as that's what generates the crypto
+ // stream.
+ QboneSessionBase::Initialize();
+ static_cast<QuicCryptoClientStreamBase*>(GetMutableCryptoStream())
+ ->CryptoConnect();
+ // Register the reserved control stream.
+ QuicStreamId next_id = GetNextOutgoingBidirectionalStreamId();
+ DCHECK_EQ(next_id, QboneConstants::GetControlStreamId(
+ connection()->transport_version()));
+ auto control_stream =
+ QuicMakeUnique<QboneClientControlStream>(this, handler_);
+ control_stream_ = control_stream.get();
+ RegisterStaticStream(std::move(control_stream));
+}
+
+int QboneClientSession::GetNumSentClientHellos() const {
+ return static_cast<const QuicCryptoClientStreamBase*>(GetCryptoStream())
+ ->num_sent_client_hellos();
+}
+
+int QboneClientSession::GetNumReceivedServerConfigUpdates() const {
+ return static_cast<const QuicCryptoClientStreamBase*>(GetCryptoStream())
+ ->num_scup_messages_received();
+}
+
+bool QboneClientSession::SendServerRequest(const QboneServerRequest& request) {
+ if (!control_stream_) {
+ QUIC_BUG << "Cannot send server request before control stream is created.";
+ return false;
+ }
+ return control_stream_->SendRequest(request);
+}
+
+void QboneClientSession::ProcessPacketFromNetwork(QuicStringPiece packet) {
+ SendPacketToPeer(packet);
+}
+
+void QboneClientSession::ProcessPacketFromPeer(QuicStringPiece packet) {
+ writer_->WritePacketToNetwork(packet.data(), packet.size());
+}
+
+void QboneClientSession::OnProofValid(
+ const QuicCryptoClientConfig::CachedState& cached) {}
+
+void QboneClientSession::OnProofVerifyDetailsAvailable(
+ const ProofVerifyDetails& verify_details) {}
+
+bool QboneClientSession::HasActiveRequests() const {
+ return (stream_map().size() - num_incoming_static_streams() -
+ num_outgoing_static_streams()) > 0;
+}
+
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/qbone_client_session.h b/chromium/net/third_party/quiche/src/quic/qbone/qbone_client_session.h
new file mode 100644
index 00000000000..5dcf2acfca4
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_client_session.h
@@ -0,0 +1,76 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_QBONE_QBONE_CLIENT_SESSION_H_
+#define QUICHE_QUIC_QBONE_QBONE_CLIENT_SESSION_H_
+
+#include "net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
+#include "net/third_party/quiche/src/quic/qbone/qbone_control.pb.h"
+#include "net/third_party/quiche/src/quic/qbone/qbone_control_stream.h"
+#include "net/third_party/quiche/src/quic/qbone/qbone_packet_writer.h"
+#include "net/third_party/quiche/src/quic/qbone/qbone_session_base.h"
+
+namespace quic {
+
+class QUIC_EXPORT_PRIVATE QboneClientSession
+ : public QboneSessionBase,
+ public QuicCryptoClientStream::ProofHandler {
+ public:
+ QboneClientSession(QuicConnection* connection,
+ QuicCryptoClientConfig* quic_crypto_client_config,
+ QuicSession::Visitor* owner,
+ const QuicConfig& config,
+ const ParsedQuicVersionVector& supported_versions,
+ const QuicServerId& server_id,
+ QbonePacketWriter* writer,
+ QboneClientControlStream::Handler* handler);
+ QboneClientSession(const QboneClientSession&) = delete;
+ QboneClientSession& operator=(const QboneClientSession&) = delete;
+ ~QboneClientSession() override;
+
+ // QuicSession overrides. This will initiate the crypto stream.
+ void Initialize() override;
+
+ // Returns the number of client hello messages that have been sent on the
+ // crypto stream. If the handshake has completed then this is one greater
+ // than the number of round-trips needed for the handshake.
+ int GetNumSentClientHellos() const;
+ int GetNumReceivedServerConfigUpdates() const;
+
+ bool SendServerRequest(const QboneServerRequest& request);
+
+ void ProcessPacketFromNetwork(QuicStringPiece packet) override;
+ void ProcessPacketFromPeer(QuicStringPiece packet) override;
+
+ // Returns true if there are active requests on this session.
+ bool HasActiveRequests() const;
+
+ protected:
+ // QboneSessionBase interface implementation.
+ std::unique_ptr<QuicCryptoStream> CreateCryptoStream() override;
+
+ // ProofHandler interface implementation.
+ void OnProofValid(const QuicCryptoClientConfig::CachedState& cached) override;
+ void OnProofVerifyDetailsAvailable(
+ const ProofVerifyDetails& verify_details) override;
+
+ QuicServerId server_id() { return server_id_; }
+ QuicCryptoClientConfig* crypto_client_config() {
+ return quic_crypto_client_config_;
+ }
+
+ private:
+ QuicServerId server_id_;
+ // Config for QUIC crypto client stream, used by the client.
+ QuicCryptoClientConfig* quic_crypto_client_config_;
+ // Passed to the control stream.
+ QboneClientControlStream::Handler* handler_;
+ // The unowned control stream.
+ QboneClientControlStream* control_stream_;
+};
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_QBONE_QBONE_CLIENT_SESSION_H_
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/qbone_client_test.cc b/chromium/net/third_party/quiche/src/quic/qbone/qbone_client_test.cc
new file mode 100644
index 00000000000..2902b19f0e1
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_client_test.cc
@@ -0,0 +1,259 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Sets up a dispatcher and sends requests via the QboneClient.
+
+#include "net/third_party/quiche/src/quic/qbone/qbone_client.h"
+
+#include "net/third_party/quiche/src/quic/core/quic_alarm_factory.h"
+#include "net/third_party/quiche/src/quic/core/quic_default_packet_writer.h"
+#include "net/third_party/quiche/src/quic/core/quic_dispatcher.h"
+#include "net/third_party/quiche/src/quic/core/quic_epoll_alarm_factory.h"
+#include "net/third_party/quiche/src/quic/core/quic_epoll_connection_helper.h"
+#include "net/third_party/quiche/src/quic/core/quic_packet_reader.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_mutex.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_port_utils.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_test_loopback.h"
+#include "net/quic/platform/impl/quic_socket_utils.h"
+#include "net/third_party/quiche/src/quic/qbone/qbone_constants.h"
+#include "net/third_party/quiche/src/quic/qbone/qbone_packet_processor_test_tools.h"
+#include "net/third_party/quiche/src/quic/qbone/qbone_server_session.h"
+#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_server_peer.h"
+#include "net/third_party/quiche/src/quic/test_tools/server_thread.h"
+#include "net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.h"
+#include "net/third_party/quiche/src/quic/tools/quic_server.h"
+
+namespace quic {
+namespace test {
+namespace {
+
+string TestPacketIn(const string& body) {
+ return PrependIPv6HeaderForTest(body, 5);
+}
+
+string TestPacketOut(const string& body) {
+ return PrependIPv6HeaderForTest(body, 4);
+}
+
+class DataSavingQbonePacketWriter : public QbonePacketWriter {
+ public:
+ void WritePacketToNetwork(const char* packet, size_t size) override {
+ QuicWriterMutexLock lock(&mu_);
+ data_.push_back(string(packet, size));
+ }
+
+ std::vector<string> data() {
+ QuicWriterMutexLock lock(&mu_);
+ return data_;
+ }
+
+ private:
+ QuicMutex mu_;
+ std::vector<string> data_;
+};
+
+// A subclass of a qbone session that will own the connection passed in.
+class ConnectionOwningQboneServerSession : public QboneServerSession {
+ public:
+ ConnectionOwningQboneServerSession(
+ const ParsedQuicVersionVector& supported_versions,
+ QuicConnection* connection,
+ Visitor* owner,
+ const QuicConfig& config,
+ const QuicCryptoServerConfig* quic_crypto_server_config,
+ QuicCompressedCertsCache* compressed_certs_cache,
+ QbonePacketWriter* writer)
+ : QboneServerSession(supported_versions,
+ connection,
+ owner,
+ config,
+ quic_crypto_server_config,
+ compressed_certs_cache,
+ writer,
+ TestLoopback6(),
+ TestLoopback6(),
+ 64,
+ nullptr),
+ connection_(connection) {}
+
+ private:
+ // Note that we don't expect the QboneServerSession or any of its parent
+ // classes to do anything with the connection_ in their destructors.
+ std::unique_ptr<QuicConnection> connection_;
+};
+
+class QuicQboneDispatcher : public QuicDispatcher {
+ public:
+ QuicQboneDispatcher(
+ const QuicConfig* config,
+ const QuicCryptoServerConfig* crypto_config,
+ QuicVersionManager* version_manager,
+ std::unique_ptr<QuicConnectionHelperInterface> helper,
+ std::unique_ptr<QuicCryptoServerStream::Helper> session_helper,
+ std::unique_ptr<QuicAlarmFactory> alarm_factory,
+ QbonePacketWriter* writer)
+ : QuicDispatcher(config,
+ crypto_config,
+ version_manager,
+ std::move(helper),
+ std::move(session_helper),
+ std::move(alarm_factory),
+ kQuicDefaultConnectionIdLength),
+ writer_(writer) {}
+
+ QuicSession* CreateQuicSession(
+ QuicConnectionId id,
+ const QuicSocketAddress& client,
+ QuicStringPiece alpn,
+ const quic::ParsedQuicVersion& version) override {
+ CHECK_EQ(alpn, "qbone");
+ QuicConnection* connection =
+ new QuicConnection(id, client, helper(), alarm_factory(), writer(),
+ /* owns_writer= */ false, Perspective::IS_SERVER,
+ ParsedQuicVersionVector{version});
+ // The connection owning wrapper owns the connection created.
+ QboneServerSession* session = new ConnectionOwningQboneServerSession(
+ GetSupportedVersions(), connection, this, config(), crypto_config(),
+ compressed_certs_cache(), writer_);
+ session->Initialize();
+ return session;
+ }
+
+ QuicConnectionId GenerateNewServerConnectionId(
+ ParsedQuicVersion version,
+ QuicConnectionId connection_id) const override {
+ char connection_id_bytes[kQuicDefaultConnectionIdLength] = {};
+ return QuicConnectionId(connection_id_bytes, sizeof(connection_id_bytes));
+ }
+
+ private:
+ QbonePacketWriter* writer_;
+};
+
+class QboneTestServer : public QuicServer {
+ public:
+ explicit QboneTestServer(std::unique_ptr<ProofSource> proof_source)
+ : QuicServer(std::move(proof_source), &response_cache_) {}
+ QuicDispatcher* CreateQuicDispatcher() override {
+ QuicEpollAlarmFactory alarm_factory(epoll_server());
+ return new QuicQboneDispatcher(
+ &config(), &crypto_config(), version_manager(),
+ std::unique_ptr<QuicEpollConnectionHelper>(
+ new QuicEpollConnectionHelper(epoll_server(),
+ QuicAllocator::BUFFER_POOL)),
+ std::unique_ptr<QuicCryptoServerStream::Helper>(
+ new QboneCryptoServerStreamHelper()),
+ std::unique_ptr<QuicEpollAlarmFactory>(
+ new QuicEpollAlarmFactory(epoll_server())),
+ &writer_);
+ }
+
+ std::vector<string> data() { return writer_.data(); }
+
+ void WaitForDataSize(int n) {
+ while (data().size() != n) {
+ }
+ }
+
+ private:
+ quic::QuicMemoryCacheBackend response_cache_;
+ DataSavingQbonePacketWriter writer_;
+};
+
+class QboneTestClient : public QboneClient {
+ public:
+ QboneTestClient(QuicSocketAddress server_address,
+ const QuicServerId& server_id,
+ const ParsedQuicVersionVector& supported_versions,
+ QuicEpollServer* epoll_server,
+ std::unique_ptr<ProofVerifier> proof_verifier)
+ : QboneClient(server_address,
+ server_id,
+ supported_versions,
+ /*session_owner=*/nullptr,
+ QuicConfig(),
+ epoll_server,
+ std::move(proof_verifier),
+ &qbone_writer_,
+ nullptr) {}
+
+ ~QboneTestClient() override {}
+
+ void SendData(const string& data) {
+ qbone_session()->ProcessPacketFromNetwork(data);
+ }
+
+ void WaitForWriteToFlush() {
+ while (connected() && session()->HasDataToWrite()) {
+ WaitForEvents();
+ }
+ }
+
+ void WaitForDataSize(int n) {
+ while (data().size() != n) {
+ WaitForEvents();
+ }
+ }
+
+ std::vector<string> data() { return qbone_writer_.data(); }
+
+ private:
+ DataSavingQbonePacketWriter qbone_writer_;
+};
+
+TEST(QboneClientTest, SendDataFromClient) {
+ SetQuicReloadableFlag(quic_use_parse_public_header, true);
+ auto server = new QboneTestServer(crypto_test_utils::ProofSourceForTesting());
+ QuicSocketAddress server_address(TestLoopback(),
+ QuicPickServerPortForTestsOrDie());
+ ServerThread server_thread(server, server_address);
+ server_thread.Initialize();
+ server_thread.Start();
+
+ QuicEpollServer epoll_server;
+ QboneTestClient client(
+ server_address,
+ QuicServerId("test.example.com", server_address.port(), false),
+ AllSupportedVersions(), &epoll_server,
+ crypto_test_utils::ProofVerifierForTesting());
+ ASSERT_TRUE(client.Initialize());
+ ASSERT_TRUE(client.Connect());
+ ASSERT_TRUE(client.WaitForCryptoHandshakeConfirmed());
+ client.SendData(TestPacketIn("hello"));
+ client.SendData(TestPacketIn("world"));
+ client.WaitForWriteToFlush();
+ server->WaitForDataSize(2);
+ EXPECT_THAT(server->data()[0], testing::Eq(TestPacketOut("hello")));
+ EXPECT_THAT(server->data()[1], testing::Eq(TestPacketOut("world")));
+ auto server_session =
+ static_cast<QboneServerSession*>(QuicServerPeer::GetDispatcher(server)
+ ->session_map()
+ .begin()
+ ->second.get());
+ string long_data(QboneConstants::kMaxQbonePacketBytes - sizeof(ip6_hdr) - 1,
+ 'A');
+ // Pretend the server gets data.
+ server_thread.Schedule([&server_session, &long_data]() {
+ server_session->ProcessPacketFromNetwork(
+ TestPacketIn("Somethingsomething"));
+ server_session->ProcessPacketFromNetwork(TestPacketIn(long_data));
+ server_session->ProcessPacketFromNetwork(TestPacketIn(long_data));
+ });
+ client.WaitForDataSize(3);
+ EXPECT_THAT(client.data()[0],
+ testing::Eq(TestPacketOut("Somethingsomething")));
+ EXPECT_THAT(client.data()[1], testing::Eq(TestPacketOut(long_data)));
+ EXPECT_THAT(client.data()[2], testing::Eq(TestPacketOut(long_data)));
+
+ client.Disconnect();
+ server_thread.Quit();
+ server_thread.Join();
+}
+
+} // namespace
+} // namespace test
+} // namespace quic
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
new file mode 100644
index 00000000000..a83f74e4d1d
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_constants.cc
@@ -0,0 +1,36 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/qbone/qbone_constants.h"
+
+#include "net/third_party/quiche/src/quic/core/quic_utils.h"
+
+namespace quic {
+
+constexpr char QboneConstants::kQboneAlpn[];
+const QuicByteCount QboneConstants::kMaxQbonePacketBytes;
+const uint32_t QboneConstants::kQboneRouteTableId;
+
+QuicStreamId QboneConstants::GetControlStreamId(QuicTransportVersion version) {
+ return QuicUtils::GetFirstBidirectionalStreamId(version,
+ Perspective::IS_CLIENT);
+}
+
+const QuicIpAddress* QboneConstants::TerminatorLocalAddress() {
+ static auto* terminator_address = []() {
+ QuicIpAddress* address = new QuicIpAddress;
+ // 0x71 0x62 0x6f 0x6e 0x65 is 'qbone' in ascii.
+ address->FromString("fe80::71:626f:6e65");
+ return address;
+ }();
+ return terminator_address;
+}
+
+const IpRange* QboneConstants::TerminatorLocalAddressRange() {
+ static auto* range =
+ new quic::IpRange(*quic::QboneConstants::TerminatorLocalAddress(), 128);
+ return range;
+}
+
+} // 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
new file mode 100644
index 00000000000..1fa2688f518
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_constants.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_QBONE_QBONE_CONSTANTS_H_
+#define QUICHE_QUIC_QBONE_QBONE_CONSTANTS_H_
+
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/core/quic_versions.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h"
+#include "net/third_party/quiche/src/quic/qbone/platform/ip_range.h"
+
+namespace quic {
+
+struct QboneConstants {
+ // Qbone's ALPN
+ static constexpr char kQboneAlpn[] = "qbone";
+ // The maximum number of bytes allowed in a qbone packet.
+ static const QuicByteCount kMaxQbonePacketBytes = 2000;
+ // The table id for Qbone's routing table. 'bone' in ascii.
+ static const uint32_t kQboneRouteTableId = 0x626F6E65;
+ // The stream ID of the control channel.
+ static QuicStreamId GetControlStreamId(QuicTransportVersion version);
+ // The link-local address of the Terminator
+ static const QuicIpAddress* TerminatorLocalAddress();
+ // The IPRange containing the TerminatorLocalAddress
+ static const IpRange* TerminatorLocalAddressRange();
+};
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_QBONE_QBONE_CONSTANTS_H_
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/qbone_control.proto b/chromium/net/third_party/quiche/src/quic/qbone/qbone_control.proto
new file mode 100644
index 00000000000..f0090d6cf8a
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_control.proto
@@ -0,0 +1,13 @@
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+
+package quic;
+
+message QboneServerRequest {
+ extensions 1000 to max;
+};
+
+message QboneClientRequest {
+ extensions 1000 to max;
+};
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/qbone_control_placeholder.proto b/chromium/net/third_party/quiche/src/quic/qbone/qbone_control_placeholder.proto
new file mode 100644
index 00000000000..375b015df02
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_control_placeholder.proto
@@ -0,0 +1,20 @@
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+
+package quic;
+
+import "net/third_party/quiche/src/quic/qbone/qbone_control.proto";
+
+// These provide fields for QboneServerRequest and QboneClientRequest that are
+// used to test the control channel. Once the control channel actually has real
+// data to pass they can be removed.
+// TODO(b/62139999): Remove this file in favor of testing actual configuration.
+
+extend QboneServerRequest {
+ optional string server_placeholder = 179838467;
+}
+
+extend QboneClientRequest {
+ optional string client_placeholder = 179838467;
+}
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/qbone_control_stream.cc b/chromium/net/third_party/quiche/src/quic/qbone/qbone_control_stream.cc
new file mode 100644
index 00000000000..6272f3ff883
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_control_stream.cc
@@ -0,0 +1,67 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/qbone/qbone_control_stream.h"
+
+#include "net/third_party/quiche/src/quic/core/quic_session.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
+#include "net/third_party/quiche/src/quic/qbone/qbone_constants.h"
+
+namespace quic {
+
+namespace {
+static constexpr size_t kRequestSizeBytes = sizeof(uint16_t);
+} // namespace
+
+QboneControlStreamBase::QboneControlStreamBase(QuicSession* session)
+ : QuicStream(QboneConstants::GetControlStreamId(
+ session->connection()->transport_version()),
+ session,
+ /*is_static=*/true,
+ BIDIRECTIONAL),
+ pending_message_size_(0) {}
+
+void QboneControlStreamBase::OnDataAvailable() {
+ sequencer()->Read(&buffer_);
+ while (true) {
+ if (pending_message_size_ == 0) {
+ // Start of a message.
+ if (buffer_.size() < kRequestSizeBytes) {
+ return;
+ }
+ memcpy(&pending_message_size_, buffer_.data(), kRequestSizeBytes);
+ buffer_.erase(0, kRequestSizeBytes);
+ }
+ // Continuation of a message.
+ if (buffer_.size() < pending_message_size_) {
+ return;
+ }
+ string tmp = buffer_.substr(0, pending_message_size_);
+ buffer_.erase(0, pending_message_size_);
+ pending_message_size_ = 0;
+ OnMessage(tmp);
+ }
+}
+
+bool QboneControlStreamBase::SendMessage(const proto2::Message& proto) {
+ string tmp;
+ if (!proto.SerializeToString(&tmp)) {
+ QUIC_BUG << "Failed to serialize QboneControlRequest";
+ return false;
+ }
+ if (tmp.size() > kuint16max) {
+ QUIC_BUG << "QboneControlRequest too large: " << tmp.size() << " > "
+ << kuint16max;
+ return false;
+ }
+ uint16_t size = tmp.size();
+ char size_str[kRequestSizeBytes];
+ memcpy(size_str, &size, kRequestSizeBytes);
+ WriteOrBufferData(QuicStringPiece(size_str, kRequestSizeBytes), false,
+ nullptr);
+ WriteOrBufferData(tmp, false, nullptr);
+ return true;
+}
+
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/qbone_control_stream.h b/chromium/net/third_party/quiche/src/quic/qbone/qbone_control_stream.h
new file mode 100644
index 00000000000..6e3dead9d8e
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_control_stream.h
@@ -0,0 +1,75 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_QBONE_QBONE_CONTROL_STREAM_H_
+#define QUICHE_QUIC_QBONE_QBONE_CONTROL_STREAM_H_
+
+#include "net/third_party/quiche/src/quic/core/quic_stream.h"
+#include "net/third_party/quiche/src/quic/qbone/qbone_control.pb.h"
+
+namespace quic {
+
+class QboneSessionBase;
+
+class QUIC_EXPORT_PRIVATE QboneControlStreamBase : public QuicStream {
+ public:
+ explicit QboneControlStreamBase(QuicSession* session);
+
+ void OnDataAvailable() override;
+
+ protected:
+ virtual void OnMessage(const string& data) = 0;
+ bool SendMessage(const proto2::Message& proto);
+
+ private:
+ uint16_t pending_message_size_;
+ string buffer_;
+};
+
+template <class T>
+class QUIC_EXPORT_PRIVATE QboneControlHandler {
+ public:
+ virtual ~QboneControlHandler() { }
+
+ virtual void OnControlRequest(const T& request) = 0;
+ virtual void OnControlError() = 0;
+};
+
+template <class Incoming, class Outgoing>
+class QUIC_EXPORT_PRIVATE QboneControlStream : public QboneControlStreamBase {
+ public:
+ using Handler = QboneControlHandler<Incoming>;
+
+ QboneControlStream(QuicSession* session, Handler* handler)
+ : QboneControlStreamBase(session), handler_(handler) {}
+
+ bool SendRequest(const Outgoing& request) { return SendMessage(request); }
+
+ protected:
+ void OnMessage(const string& data) override {
+ Incoming request;
+ if (!request.ParseFromString(data)) {
+ QUIC_LOG(ERROR) << "Failed to parse incoming request";
+ if (handler_ != nullptr) {
+ handler_->OnControlError();
+ }
+ return;
+ }
+ if (handler_ != nullptr) {
+ handler_->OnControlRequest(request);
+ }
+ }
+
+ private:
+ Handler* handler_;
+};
+
+using QboneServerControlStream =
+ QboneControlStream<QboneServerRequest, QboneClientRequest>;
+using QboneClientControlStream =
+ QboneControlStream<QboneClientRequest, QboneServerRequest>;
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_QBONE_QBONE_CONTROL_STREAM_H_
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_exchanger.cc b/chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_exchanger.cc
new file mode 100644
index 00000000000..3f3a5f9cea6
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_exchanger.cc
@@ -0,0 +1,70 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/qbone/qbone_packet_exchanger.h"
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
+
+namespace quic {
+
+bool QbonePacketExchanger::ReadAndDeliverPacket(
+ QboneClientInterface* qbone_client) {
+ bool blocked = false;
+ string error;
+ std::unique_ptr<QuicData> packet = ReadPacket(&blocked, &error);
+ if (packet == nullptr) {
+ if (!blocked) {
+ visitor_->OnReadError(error);
+ }
+ return false;
+ }
+ qbone_client->ProcessPacketFromNetwork(packet->AsStringPiece());
+ return true;
+}
+
+void QbonePacketExchanger::WritePacketToNetwork(const char* packet,
+ size_t size) {
+ bool blocked = false;
+ string error;
+ if (packet_queue_.empty() && !write_blocked_) {
+ if (WritePacket(packet, size, &blocked, &error)) {
+ return;
+ }
+ if (!blocked) {
+ visitor_->OnWriteError(error);
+ return;
+ }
+ write_blocked_ = true;
+ }
+
+ // Drop the packet on the floor if the queue if full.
+ if (packet_queue_.size() >= max_pending_packets_) {
+ return;
+ }
+
+ auto data_copy = new char[size];
+ memcpy(data_copy, packet, size);
+ packet_queue_.push_back(
+ QuicMakeUnique<QuicData>(data_copy, size, /* owns_buffer = */ true));
+}
+
+void QbonePacketExchanger::SetWritable() {
+ write_blocked_ = false;
+ while (!packet_queue_.empty()) {
+ bool blocked = false;
+ string error;
+ if (WritePacket(packet_queue_.front()->data(),
+ packet_queue_.front()->length(), &blocked, &error)) {
+ packet_queue_.pop_front();
+ } else {
+ if (!blocked) {
+ visitor_->OnWriteError(error);
+ }
+ write_blocked_ = blocked;
+ return;
+ }
+ }
+}
+
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_exchanger.h b/chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_exchanger.h
new file mode 100644
index 00000000000..8620a492fdb
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_exchanger.h
@@ -0,0 +1,80 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_QBONE_QBONE_PACKET_EXCHANGER_H_
+#define QUICHE_QUIC_QBONE_QBONE_PACKET_EXCHANGER_H_
+
+#include "net/third_party/quiche/src/quic/core/quic_packets.h"
+#include "net/third_party/quiche/src/quic/qbone/qbone_client_interface.h"
+#include "net/third_party/quiche/src/quic/qbone/qbone_packet_writer.h"
+
+namespace quic {
+
+// Handles reading and writing on the local network and exchange packets between
+// the local network with a Qbone connection.
+class QbonePacketExchanger : public QbonePacketWriter {
+ public:
+ // The owner might want to receive notifications when read or write fails.
+ class Visitor {
+ public:
+ virtual ~Visitor() {}
+ virtual void OnReadError(const string& error) {}
+ virtual void OnWriteError(const string& error) {}
+ };
+ // Does not take ownership of visitor.
+ QbonePacketExchanger(Visitor* visitor, size_t max_pending_packets)
+ : visitor_(visitor), max_pending_packets_(max_pending_packets) {}
+
+ QbonePacketExchanger(const QbonePacketExchanger&) = delete;
+ QbonePacketExchanger& operator=(const QbonePacketExchanger&) = delete;
+
+ QbonePacketExchanger(QbonePacketExchanger&&) = delete;
+ QbonePacketExchanger& operator=(QbonePacketExchanger&&) = delete;
+
+ ~QbonePacketExchanger() = default;
+
+ // Returns true if there may be more packets to read.
+ // Implementations handles the actual raw read and delivers the packet to
+ // qbone_client.
+ bool ReadAndDeliverPacket(QboneClientInterface* qbone_client);
+
+ // From QbonePacketWriter.
+ // Writes a packet to the local network. If the write would be blocked, the
+ // packet will be queued if the queue is smaller than max_pending_packets_.
+ void WritePacketToNetwork(const char* packet, size_t size) override;
+
+ // The caller signifies that the local network is no longer blocked.
+ void SetWritable();
+
+ private:
+ // The actual implementation that reads a packet from the local network.
+ // Returns the packet if one is successfully read. This might nullptr when a)
+ // there is no packet to read, b) the read failed. In the former case, blocked
+ // is set to true. error contains the error message.
+ virtual std::unique_ptr<QuicData> ReadPacket(bool* blocked,
+ string* error) = 0;
+
+ // The actual implementation that writes a packet to the local network.
+ // Returns true if the write succeeds. blocked will be set to true if the
+ // write failure is caused by the local network being blocked. error contains
+ // the error message.
+ virtual bool WritePacket(const char* packet,
+ size_t size,
+ bool* blocked,
+ string* error) = 0;
+
+ std::list<std::unique_ptr<QuicData>> packet_queue_;
+
+ Visitor* visitor_;
+
+ // The maximum number of packets that could be queued up when writing to local
+ // network is blocked.
+ size_t max_pending_packets_;
+
+ bool write_blocked_ = false;
+};
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_QBONE_QBONE_PACKET_EXCHANGER_H_
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_exchanger_test.cc b/chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_exchanger_test.cc
new file mode 100644
index 00000000000..4e63b994721
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_exchanger_test.cc
@@ -0,0 +1,253 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/qbone/qbone_packet_exchanger.h"
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+#include "net/third_party/quiche/src/quic/qbone/mock_qbone_client.h"
+
+namespace quic {
+namespace {
+
+using ::testing::StrEq;
+using ::testing::StrictMock;
+
+const size_t kMaxPendingPackets = 2;
+
+class MockVisitor : public QbonePacketExchanger::Visitor {
+ public:
+ MOCK_METHOD1(OnReadError, void(const string&));
+ MOCK_METHOD1(OnWriteError, void(const string&));
+};
+
+class FakeQbonePacketExchanger : public QbonePacketExchanger {
+ public:
+ using QbonePacketExchanger::QbonePacketExchanger;
+
+ // Adds a packet to the end of list of packets to be returned by ReadPacket.
+ // When the list is empty, ReadPacket returns nullptr to signify error as
+ // defined by QbonePacketExchanger. If SetReadError is not called or called
+ // with empty error string, ReadPacket sets blocked to true.
+ void AddPacketToBeRead(std::unique_ptr<QuicData> packet) {
+ packets_to_be_read_.push_back(std::move(packet));
+ }
+
+ // Sets the error to be returned by ReadPacket when the list of packets is
+ // empty. If error is empty string, blocked is set by ReadPacket.
+ void SetReadError(const string& error) { read_error_ = error; }
+
+ // Force WritePacket to fail with the given status. WritePacket returns true
+ // when blocked == true and error is empty.
+ void ForceWriteFailure(bool blocked, const string& error) {
+ write_blocked_ = blocked;
+ write_error_ = error;
+ }
+
+ // Packets that have been successfully written by WritePacket.
+ const std::vector<string>& packets_written() const {
+ return packets_written_;
+ }
+
+ private:
+ // Implements QbonePacketExchanger::ReadPacket.
+ std::unique_ptr<QuicData> ReadPacket(bool* blocked, string* error) override {
+ *blocked = false;
+
+ if (packets_to_be_read_.empty()) {
+ *blocked = read_error_.empty();
+ *error = read_error_;
+ return nullptr;
+ }
+
+ std::unique_ptr<QuicData> packet = std::move(packets_to_be_read_.front());
+ packets_to_be_read_.pop_front();
+ return packet;
+ }
+
+ // Implements QbonePacketExchanger::WritePacket.
+ bool WritePacket(const char* packet,
+ size_t size,
+ bool* blocked,
+ string* error) override {
+ *blocked = false;
+
+ if (write_blocked_ || !write_error_.empty()) {
+ *blocked = write_blocked_;
+ *error = write_error_;
+ return false;
+ }
+
+ packets_written_.push_back(string(packet, size));
+ return true;
+ }
+
+ string read_error_;
+ std::list<std::unique_ptr<QuicData>> packets_to_be_read_;
+
+ string write_error_;
+ bool write_blocked_ = false;
+ std::vector<string> packets_written_;
+};
+
+TEST(QbonePacketExchangerTest,
+ ReadAndDeliverPacketDeliversPacketToQboneClient) {
+ StrictMock<MockVisitor> visitor;
+ FakeQbonePacketExchanger exchanger(&visitor, kMaxPendingPackets);
+ StrictMock<MockQboneClient> client;
+
+ string packet = "data";
+ exchanger.AddPacketToBeRead(
+ QuicMakeUnique<QuicData>(packet.data(), packet.length()));
+ EXPECT_CALL(client, ProcessPacketFromNetwork(StrEq("data")));
+
+ EXPECT_TRUE(exchanger.ReadAndDeliverPacket(&client));
+}
+
+TEST(QbonePacketExchangerTest,
+ ReadAndDeliverPacketNotifiesVisitorOnReadFailure) {
+ MockVisitor visitor;
+ FakeQbonePacketExchanger exchanger(&visitor, kMaxPendingPackets);
+ MockQboneClient client;
+
+ // Force read error.
+ string io_error = "I/O error";
+ exchanger.SetReadError(io_error);
+ EXPECT_CALL(visitor, OnReadError(StrEq(io_error))).Times(1);
+
+ EXPECT_FALSE(exchanger.ReadAndDeliverPacket(&client));
+}
+
+TEST(QbonePacketExchangerTest,
+ ReadAndDeliverPacketDoesNotNotifyVisitorOnBlockedIO) {
+ MockVisitor visitor;
+ FakeQbonePacketExchanger exchanger(&visitor, kMaxPendingPackets);
+ MockQboneClient client;
+
+ // No more packets to read.
+ EXPECT_FALSE(exchanger.ReadAndDeliverPacket(&client));
+}
+
+TEST(QbonePacketExchangerTest,
+ WritePacketToNetworkWritesDirectlyToNetworkWhenNotBlocked) {
+ MockVisitor visitor;
+ FakeQbonePacketExchanger exchanger(&visitor, kMaxPendingPackets);
+ MockQboneClient client;
+
+ string packet = "data";
+ exchanger.WritePacketToNetwork(packet.data(), packet.length());
+
+ ASSERT_EQ(exchanger.packets_written().size(), 1);
+ EXPECT_THAT(exchanger.packets_written()[0], StrEq(packet));
+}
+
+TEST(QbonePacketExchangerTest,
+ WritePacketToNetworkQueuesPacketsAndProcessThemLater) {
+ MockVisitor visitor;
+ FakeQbonePacketExchanger exchanger(&visitor, kMaxPendingPackets);
+ MockQboneClient client;
+
+ // Force write to be blocked so that packets are queued.
+ exchanger.ForceWriteFailure(true, "");
+ std::vector<string> packets = {"packet0", "packet1"};
+ for (int i = 0; i < packets.size(); i++) {
+ exchanger.WritePacketToNetwork(packets[i].data(), packets[i].length());
+ }
+
+ // Nothing should have been written because of blockage.
+ ASSERT_TRUE(exchanger.packets_written().empty());
+
+ // Remove blockage and start proccessing queued packets.
+ exchanger.ForceWriteFailure(false, "");
+ exchanger.SetWritable();
+
+ // Queued packets are processed.
+ ASSERT_EQ(exchanger.packets_written().size(), 2);
+ for (int i = 0; i < packets.size(); i++) {
+ EXPECT_THAT(exchanger.packets_written()[i], StrEq(packets[i]));
+ }
+}
+
+TEST(QbonePacketExchangerTest,
+ SetWritableContinuesProcessingPacketIfPreviousCallBlocked) {
+ MockVisitor visitor;
+ FakeQbonePacketExchanger exchanger(&visitor, kMaxPendingPackets);
+ MockQboneClient client;
+
+ // Force write to be blocked so that packets are queued.
+ exchanger.ForceWriteFailure(true, "");
+ std::vector<string> packets = {"packet0", "packet1"};
+ for (int i = 0; i < packets.size(); i++) {
+ exchanger.WritePacketToNetwork(packets[i].data(), packets[i].length());
+ }
+
+ // Nothing should have been written because of blockage.
+ ASSERT_TRUE(exchanger.packets_written().empty());
+
+ // Start processing packets, but since writes are still blocked, nothing
+ // should have been written.
+ exchanger.SetWritable();
+ ASSERT_TRUE(exchanger.packets_written().empty());
+
+ // Remove blockage and start processing packets again.
+ exchanger.ForceWriteFailure(false, "");
+ exchanger.SetWritable();
+
+ ASSERT_EQ(exchanger.packets_written().size(), 2);
+ for (int i = 0; i < packets.size(); i++) {
+ EXPECT_THAT(exchanger.packets_written()[i], StrEq(packets[i]));
+ }
+}
+
+TEST(QbonePacketExchangerTest, WritePacketToNetworkDropsPacketIfQueueIfFull) {
+ std::vector<string> packets = {"packet0", "packet1", "packet2"};
+ size_t queue_size = packets.size() - 1;
+ MockVisitor visitor;
+ // exchanger has smaller queue than number of packets.
+ FakeQbonePacketExchanger exchanger(&visitor, queue_size);
+ MockQboneClient client;
+
+ exchanger.ForceWriteFailure(true, "");
+ for (int i = 0; i < packets.size(); i++) {
+ exchanger.WritePacketToNetwork(packets[i].data(), packets[i].length());
+ }
+
+ // Blocked writes cause packets to be queued or dropped.
+ ASSERT_TRUE(exchanger.packets_written().empty());
+
+ exchanger.ForceWriteFailure(false, "");
+ exchanger.SetWritable();
+
+ ASSERT_EQ(exchanger.packets_written().size(), queue_size);
+ for (int i = 0; i < queue_size; i++) {
+ EXPECT_THAT(exchanger.packets_written()[i], StrEq(packets[i]));
+ }
+}
+
+TEST(QbonePacketExchangerTest, WriteErrorsGetNotified) {
+ MockVisitor visitor;
+ FakeQbonePacketExchanger exchanger(&visitor, kMaxPendingPackets);
+ MockQboneClient client;
+ string packet = "data";
+
+ // Write error is delivered to visitor during WritePacketToNetwork.
+ string io_error = "I/O error";
+ exchanger.ForceWriteFailure(false, io_error);
+ EXPECT_CALL(visitor, OnWriteError(StrEq(io_error))).Times(1);
+ exchanger.WritePacketToNetwork(packet.data(), packet.length());
+ ASSERT_TRUE(exchanger.packets_written().empty());
+
+ // Write error is delivered to visitor during SetWritable.
+ exchanger.ForceWriteFailure(true, "");
+ exchanger.WritePacketToNetwork(packet.data(), packet.length());
+
+ string sys_error = "sys error";
+ exchanger.ForceWriteFailure(false, sys_error);
+ EXPECT_CALL(visitor, OnWriteError(StrEq(sys_error))).Times(1);
+ exchanger.SetWritable();
+ ASSERT_TRUE(exchanger.packets_written().empty());
+}
+
+} // namespace
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_processor.cc b/chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_processor.cc
new file mode 100644
index 00000000000..db7a1382a8f
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_processor.cc
@@ -0,0 +1,269 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/qbone/qbone_packet_processor.h"
+
+#include <cstring>
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_endian.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
+#include "net/third_party/quiche/src/quic/qbone/platform/icmp_packet.h"
+#include "net/third_party/quiche/src/quic/qbone/platform/internet_checksum.h"
+#include "net/third_party/quiche/src/quic/qbone/platform/tcp_packet.h"
+
+namespace {
+
+constexpr size_t kIPv6AddressSize = 16;
+constexpr size_t kIPv6MinPacketSize = 1280;
+constexpr size_t kIcmpTtl = 64;
+constexpr size_t kICMPv6DestinationUnreachableDueToSourcePolicy = 5;
+
+} // namespace
+
+namespace quic {
+
+const QuicIpAddress QbonePacketProcessor::kInvalidIpAddress =
+ QuicIpAddress::Any6();
+
+QbonePacketProcessor::QbonePacketProcessor(QuicIpAddress self_ip,
+ QuicIpAddress client_ip,
+ size_t client_ip_subnet_length,
+ OutputInterface* output,
+ StatsInterface* stats)
+ : client_ip_(client_ip),
+ output_(output),
+ stats_(stats),
+ filter_(new Filter) {
+ memcpy(self_ip_.s6_addr, self_ip.ToPackedString().data(), kIPv6AddressSize);
+ DCHECK_LE(client_ip_subnet_length, kIPv6AddressSize * 8);
+ client_ip_subnet_length_ = client_ip_subnet_length;
+
+ DCHECK(IpAddressFamily::IP_V6 == self_ip.address_family());
+ DCHECK(IpAddressFamily::IP_V6 == client_ip.address_family());
+ DCHECK(self_ip != kInvalidIpAddress);
+}
+
+QbonePacketProcessor::OutputInterface::~OutputInterface() {}
+QbonePacketProcessor::StatsInterface::~StatsInterface() {}
+QbonePacketProcessor::Filter::~Filter() {}
+
+QbonePacketProcessor::ProcessingResult
+QbonePacketProcessor::Filter::FilterPacket(Direction direction,
+ QuicStringPiece full_packet,
+ QuicStringPiece payload,
+ icmp6_hdr* icmp_header,
+ OutputInterface* output) {
+ return ProcessingResult::OK;
+}
+
+void QbonePacketProcessor::ProcessPacket(string* packet, Direction direction) {
+ if (QUIC_PREDICT_FALSE(!IsValid())) {
+ QUIC_BUG << "QuicPacketProcessor is invoked in an invalid state.";
+ stats_->OnPacketDroppedSilently(direction);
+ return;
+ }
+
+ uint8_t transport_protocol;
+ char* transport_data;
+ icmp6_hdr icmp_header;
+ memset(&icmp_header, 0, sizeof(icmp_header));
+ ProcessingResult result = ProcessIPv6HeaderAndFilter(
+ packet, direction, &transport_protocol, &transport_data, &icmp_header);
+
+ switch (result) {
+ case ProcessingResult::OK:
+ switch (direction) {
+ case Direction::FROM_CLIENT:
+ output_->SendPacketToNetwork(*packet);
+ break;
+ case Direction::FROM_NETWORK:
+ output_->SendPacketToClient(*packet);
+ break;
+ }
+ stats_->OnPacketForwarded(direction);
+ break;
+ case ProcessingResult::SILENT_DROP:
+ stats_->OnPacketDroppedSilently(direction);
+ break;
+ case ProcessingResult::DEFER:
+ stats_->OnPacketDeferred(direction);
+ break;
+ case ProcessingResult::ICMP:
+ SendIcmpResponse(&icmp_header, *packet, direction);
+ stats_->OnPacketDroppedWithIcmp(direction);
+ break;
+ case ProcessingResult::ICMP_AND_TCP_RESET:
+ SendIcmpResponse(&icmp_header, *packet, direction);
+ stats_->OnPacketDroppedWithIcmp(direction);
+ SendTcpReset(*packet, direction);
+ stats_->OnPacketDroppedWithTcpReset(direction);
+ break;
+ }
+}
+
+QbonePacketProcessor::ProcessingResult
+QbonePacketProcessor::ProcessIPv6HeaderAndFilter(string* packet,
+ Direction direction,
+ uint8_t* transport_protocol,
+ char** transport_data,
+ icmp6_hdr* icmp_header) {
+ ProcessingResult result = ProcessIPv6Header(
+ packet, direction, transport_protocol, transport_data, icmp_header);
+
+ if (result == ProcessingResult::OK) {
+ char* packet_data = &*packet->begin();
+ size_t header_size = *transport_data - packet_data;
+ // Sanity-check the bounds.
+ if (packet_data >= *transport_data || header_size > packet->size() ||
+ header_size < kIPv6HeaderSize) {
+ QUIC_BUG << "Invalid pointers encountered in "
+ "QbonePacketProcessor::ProcessPacket. Dropping the packet";
+ return ProcessingResult::SILENT_DROP;
+ }
+
+ result = filter_->FilterPacket(
+ direction, *packet,
+ QuicStringPiece(*transport_data, packet->size() - header_size),
+ icmp_header, output_);
+ }
+
+ // Do not send ICMP error messages in response to ICMP errors.
+ if (result == ProcessingResult::ICMP) {
+ const uint8_t* header = reinterpret_cast<const uint8_t*>(packet->data());
+
+ constexpr size_t kIPv6NextHeaderOffset = 6;
+ constexpr size_t kIcmpMessageTypeOffset = kIPv6HeaderSize + 0;
+ constexpr size_t kIcmpMessageTypeMaxError = 127;
+ if (
+ // Check size.
+ packet->size() >= (kIPv6HeaderSize + kICMPv6HeaderSize) &&
+ // Check that the packet is in fact ICMP.
+ header[kIPv6NextHeaderOffset] == IPPROTO_ICMPV6 &&
+ // Check that ICMP message type is an error.
+ header[kIcmpMessageTypeOffset] < kIcmpMessageTypeMaxError) {
+ result = ProcessingResult::SILENT_DROP;
+ }
+ }
+
+ return result;
+}
+
+QbonePacketProcessor::ProcessingResult QbonePacketProcessor::ProcessIPv6Header(
+ string* packet,
+ Direction direction,
+ uint8_t* transport_protocol,
+ char** transport_data,
+ icmp6_hdr* icmp_header) {
+ // Check if the packet is big enough to have IPv6 header.
+ if (packet->size() < kIPv6HeaderSize) {
+ QUIC_DVLOG(1) << "Dropped malformed packet: IPv6 header too short";
+ return ProcessingResult::SILENT_DROP;
+ }
+
+ // Check version field.
+ ip6_hdr* header = reinterpret_cast<ip6_hdr*>(&*packet->begin());
+ if (header->ip6_vfc >> 4 != 6) {
+ QUIC_DVLOG(1) << "Dropped malformed packet: IP version is not IPv6";
+ return ProcessingResult::SILENT_DROP;
+ }
+
+ // Check payload size.
+ const size_t declared_payload_size =
+ QuicEndian::NetToHost16(header->ip6_plen);
+ const size_t actual_payload_size = packet->size() - kIPv6HeaderSize;
+ if (declared_payload_size != actual_payload_size) {
+ QUIC_DVLOG(1)
+ << "Dropped malformed packet: incorrect packet length specified";
+ return ProcessingResult::SILENT_DROP;
+ }
+
+ // Check that the address of the client is in the packet.
+ QuicIpAddress address_to_check;
+ uint8_t address_reject_code;
+ bool ip_parse_result;
+ switch (direction) {
+ case Direction::FROM_CLIENT:
+ // Expect the source IP to match the client.
+ ip_parse_result = address_to_check.FromPackedString(
+ reinterpret_cast<const char*>(&header->ip6_src),
+ sizeof(header->ip6_src));
+ address_reject_code = kICMPv6DestinationUnreachableDueToSourcePolicy;
+ break;
+ case Direction::FROM_NETWORK:
+ // Expect the destination IP to match the client.
+ ip_parse_result = address_to_check.FromPackedString(
+ reinterpret_cast<const char*>(&header->ip6_dst),
+ sizeof(header->ip6_src));
+ address_reject_code = ICMP6_DST_UNREACH_NOROUTE;
+ break;
+ }
+ DCHECK(ip_parse_result);
+ if (!client_ip_.InSameSubnet(address_to_check, client_ip_subnet_length_)) {
+ QUIC_DVLOG(1)
+ << "Dropped packet: source/destination address is not client's";
+ icmp_header->icmp6_type = ICMP6_DST_UNREACH;
+ icmp_header->icmp6_code = address_reject_code;
+ return ProcessingResult::ICMP;
+ }
+
+ // Check and decrement TTL.
+ if (header->ip6_hops <= 1) {
+ icmp_header->icmp6_type = ICMP6_TIME_EXCEEDED;
+ icmp_header->icmp6_code = ICMP6_TIME_EXCEED_TRANSIT;
+ return ProcessingResult::ICMP;
+ }
+ header->ip6_hops--;
+
+ // Check and extract IP headers.
+ switch (header->ip6_nxt) {
+ case IPPROTO_TCP:
+ case IPPROTO_UDP:
+ case IPPROTO_ICMPV6:
+ *transport_protocol = header->ip6_nxt;
+ *transport_data = (&*packet->begin()) + kIPv6HeaderSize;
+ break;
+ default:
+ icmp_header->icmp6_type = ICMP6_PARAM_PROB;
+ icmp_header->icmp6_code = ICMP6_PARAMPROB_NEXTHEADER;
+ return ProcessingResult::ICMP;
+ }
+
+ return ProcessingResult::OK;
+}
+
+void QbonePacketProcessor::SendIcmpResponse(icmp6_hdr* icmp_header,
+ QuicStringPiece original_packet,
+ Direction original_direction) {
+ in6_addr dst;
+ // TODO(b/70339814): ensure this is actually a unicast address.
+ memcpy(dst.s6_addr, &original_packet[8], kIPv6AddressSize);
+
+ CreateIcmpPacket(self_ip_, dst, *icmp_header, original_packet,
+ [this, original_direction](QuicStringPiece packet) {
+ SendResponse(original_direction, packet);
+ });
+}
+
+void QbonePacketProcessor::SendTcpReset(QuicStringPiece original_packet,
+ Direction original_direction) {
+ CreateTcpResetPacket(original_packet,
+ [this, original_direction](QuicStringPiece packet) {
+ SendResponse(original_direction, packet);
+ });
+}
+
+void QbonePacketProcessor::SendResponse(Direction original_direction,
+ QuicStringPiece packet) {
+ switch (original_direction) {
+ case Direction::FROM_CLIENT:
+ output_->SendPacketToClient(packet);
+ break;
+ case Direction::FROM_NETWORK:
+ output_->SendPacketToNetwork(packet);
+ break;
+ }
+}
+
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_processor.h b/chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_processor.h
new file mode 100644
index 00000000000..44767715c61
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_processor.h
@@ -0,0 +1,198 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_QBONE_QBONE_PACKET_PROCESSOR_H_
+#define QUICHE_QUIC_QBONE_QBONE_PACKET_PROCESSOR_H_
+
+#include <netinet/icmp6.h>
+#include <netinet/ip6.h>
+
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
+
+namespace quic {
+
+enum : size_t {
+ kIPv6HeaderSize = 40,
+ kICMPv6HeaderSize = sizeof(icmp6_hdr),
+ kTotalICMPv6HeaderSize = kIPv6HeaderSize + kICMPv6HeaderSize,
+};
+
+// QBONE packet processor accepts packets destined in either direction
+// (client-to-network or network-to-client). It inspects them and makes
+// decisions on whether they should be forwarded or dropped, replying with ICMP
+// messages as appropriate.
+class QbonePacketProcessor {
+ public:
+ enum class Direction {
+ // Packet is going from the QBONE client into the network behind the QBONE.
+ FROM_CLIENT = 0,
+ // Packet is going from the network begin QBONE to the client.
+ FROM_NETWORK = 1
+ };
+
+ enum class ProcessingResult {
+ OK = 0,
+ SILENT_DROP = 1,
+ ICMP = 2,
+ // Equivalent to |SILENT_DROP| at the moment, but indicates that the
+ // downstream filter has buffered the packet and deferred its processing.
+ // The packet may be emitted at a later time.
+ DEFER = 3,
+ // In addition to sending an ICMP message, also send a TCP RST. This option
+ // requires the incoming packet to have been a valid TCP packet, as a TCP
+ // RST requires information from the current connection state to be
+ // well-formed.
+ ICMP_AND_TCP_RESET = 4,
+ };
+
+ class OutputInterface {
+ public:
+ virtual ~OutputInterface();
+
+ virtual void SendPacketToClient(QuicStringPiece packet) = 0;
+ virtual void SendPacketToNetwork(QuicStringPiece packet) = 0;
+ };
+
+ class StatsInterface {
+ public:
+ virtual ~StatsInterface();
+
+ virtual void OnPacketForwarded(Direction direction) = 0;
+ virtual void OnPacketDroppedSilently(Direction direction) = 0;
+ virtual void OnPacketDroppedWithIcmp(Direction direction) = 0;
+ virtual void OnPacketDroppedWithTcpReset(Direction direction) = 0;
+ virtual void OnPacketDeferred(Direction direction) = 0;
+ };
+
+ // Allows to implement a custom packet filter on top of the filtering done by
+ // the packet processor itself.
+ class Filter {
+ public:
+ virtual ~Filter();
+ // The main interface function. The following arguments are supplied:
+ // - |direction|, to indicate direction of the packet.
+ // - |full_packet|, which includes the IPv6 header and possibly the IPv6
+ // options that were understood by the processor.
+ // - |payload|, the contents of the IPv6 packet, i.e. a TCP, a UDP or an
+ // ICMP packet.
+ // - |icmp_header|, an output argument which allows the filter to specify
+ // the ICMP message with which the packet is to be rejected.
+ // The method is called only on packets which were already verified as valid
+ // IPv6 packets.
+ //
+ // The implementer of this method has four options to return:
+ // - OK will cause the filter to pass the packet through
+ // - SILENT_DROP will cause the filter to drop the packet silently
+ // - ICMP will cause the filter to drop the packet and send an ICMP
+ // response.
+ // - DEFER will cause the packet to be not forwarded; the filter is
+ // responsible for sending (or not sending) it later using |output|.
+ //
+ // Note that |output| should not be used except in the DEFER case, as the
+ // processor will perform the necessary writes itself.
+ virtual ProcessingResult FilterPacket(Direction direction,
+ QuicStringPiece full_packet,
+ QuicStringPiece payload,
+ icmp6_hdr* icmp_header,
+ OutputInterface* output);
+
+ protected:
+ // Helper methods that allow to easily extract information that is required
+ // for filtering from the |ipv6_header| argument. All of those assume that
+ // the header is of valid size, which is true for everything passed into
+ // FilterPacket().
+ inline uint8_t TransportProtocolFromHeader(QuicStringPiece ipv6_header) {
+ return ipv6_header[6];
+ }
+ inline QuicIpAddress SourceIpFromHeader(QuicStringPiece ipv6_header) {
+ QuicIpAddress address;
+ address.FromPackedString(&ipv6_header[8],
+ QuicIpAddress::kIPv6AddressSize);
+ return address;
+ }
+ inline QuicIpAddress DestinationIpFromHeader(QuicStringPiece ipv6_header) {
+ QuicIpAddress address;
+ address.FromPackedString(&ipv6_header[24],
+ QuicIpAddress::kIPv6AddressSize);
+ return address;
+ }
+ };
+
+ // |self_ip| is the IP address from which the processor will originate ICMP
+ // messages. |client_ip| is the expected IP address of the client, used for
+ // packet validation.
+ //
+ // |output| and |stats| are the visitor interfaces used by the processor.
+ // |output| gets notified whenever the processor decides to send a packet, and
+ // |stats| gets notified about any decisions that processor makes, without a
+ // reference to which packet that decision was made about.
+ QbonePacketProcessor(QuicIpAddress self_ip,
+ QuicIpAddress client_ip,
+ size_t client_ip_subnet_length,
+ OutputInterface* output,
+ StatsInterface* stats);
+ QbonePacketProcessor(const QbonePacketProcessor&) = delete;
+ QbonePacketProcessor& operator=(const QbonePacketProcessor&) = delete;
+
+ // Accepts an IPv6 packet and handles it accordingly by either forwarding it,
+ // replying with an ICMP packet or silently dropping it. |packet| will be
+ // modified in the process, by having the TTL field decreased.
+ void ProcessPacket(string* packet, Direction direction);
+
+ void set_filter(std::unique_ptr<Filter> filter) {
+ filter_ = std::move(filter);
+ }
+
+ void set_client_ip(QuicIpAddress client_ip) { client_ip_ = client_ip; }
+ void set_client_ip_subnet_length(size_t client_ip_subnet_length) {
+ client_ip_subnet_length_ = client_ip_subnet_length;
+ }
+
+ static const QuicIpAddress kInvalidIpAddress;
+
+ protected:
+ // Processes the header and returns what should be done with the packet.
+ // After that, calls an external packet filter if registered. TTL of the
+ // packet may be decreased in the process.
+ ProcessingResult ProcessIPv6HeaderAndFilter(string* packet,
+ Direction direction,
+ uint8_t* transport_protocol,
+ char** transport_data,
+ icmp6_hdr* icmp_header);
+
+ void SendIcmpResponse(icmp6_hdr* icmp_header,
+ QuicStringPiece original_packet,
+ Direction original_direction);
+
+ void SendTcpReset(QuicStringPiece original_packet,
+ Direction original_direction);
+
+ inline bool IsValid() const { return client_ip_ != kInvalidIpAddress; }
+
+ // IP address of the server. Used to send ICMP messages.
+ in6_addr self_ip_;
+ // IP address range of the VPN client.
+ QuicIpAddress client_ip_;
+ size_t client_ip_subnet_length_;
+
+ OutputInterface* output_;
+ StatsInterface* stats_;
+ std::unique_ptr<Filter> filter_;
+
+ private:
+ // Performs basic sanity and permission checks on the packet, and decreases
+ // the TTL.
+ ProcessingResult ProcessIPv6Header(string* packet,
+ Direction direction,
+ uint8_t* transport_protocol,
+ char** transport_data,
+ icmp6_hdr* icmp_header);
+
+ void SendResponse(Direction original_direction, QuicStringPiece packet);
+};
+
+} // namespace quic
+#endif // QUICHE_QUIC_QBONE_QBONE_PACKET_PROCESSOR_H_
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_processor_test.cc b/chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_processor_test.cc
new file mode 100644
index 00000000000..256f5b0f142
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_processor_test.cc
@@ -0,0 +1,283 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/qbone/qbone_packet_processor.h"
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+#include "net/third_party/quiche/src/quic/qbone/qbone_packet_processor_test_tools.h"
+
+namespace quic {
+namespace {
+
+using Direction = QbonePacketProcessor::Direction;
+using ProcessingResult = QbonePacketProcessor::ProcessingResult;
+using OutputInterface = QbonePacketProcessor::OutputInterface;
+using ::testing::_;
+using ::testing::Return;
+
+// clang-format off
+static const char kReferenceClientPacketData[] = {
+ // IPv6 with zero TOS and flow label.
+ 0x60, 0x00, 0x00, 0x00,
+ // Payload size is 8 bytes.
+ 0x00, 0x08,
+ // Next header is UDP
+ 17,
+ // TTL is 50.
+ 50,
+ // IP address of the sender is fd00:0:0:1::1
+ 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ // IP address of the receiver is fd00:0:0:5::1
+ 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ // Source port 12345
+ 0x30, 0x39,
+ // Destination port 443
+ 0x01, 0xbb,
+ // UDP content length is zero
+ 0x00, 0x00,
+ // Checksum is not actually checked in any of the tests, so we leave it as
+ // zero
+ 0x00, 0x00,
+};
+
+static const char kReferenceNetworkPacketData[] = {
+ // IPv6 with zero TOS and flow label.
+ 0x60, 0x00, 0x00, 0x00,
+ // Payload size is 8 bytes.
+ 0x00, 0x08,
+ // Next header is UDP
+ 17,
+ // TTL is 50.
+ 50,
+ // IP address of the sender is fd00:0:0:5::1
+ 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ // IP address of the receiver is fd00:0:0:1::1
+ 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ // Source port 443
+ 0x01, 0xbb,
+ // Destination port 12345
+ 0x30, 0x39,
+ // UDP content length is zero
+ 0x00, 0x00,
+ // Checksum is not actually checked in any of the tests, so we leave it as
+ // zero
+ 0x00, 0x00,
+};
+
+static const char kReferenceClientSubnetPacketData[] = {
+ // IPv6 with zero TOS and flow label.
+ 0x60, 0x00, 0x00, 0x00,
+ // Payload size is 8 bytes.
+ 0x00, 0x08,
+ // Next header is UDP
+ 17,
+ // TTL is 50.
+ 50,
+ // IP address of the sender is fd00:0:0:2::1, which is within the /62 of the
+ // client.
+ 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ // IP address of the receiver is fd00:0:0:5::1
+ 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ // Source port 12345
+ 0x30, 0x39,
+ // Destination port 443
+ 0x01, 0xbb,
+ // UDP content length is zero
+ 0x00, 0x00,
+ // Checksum is not actually checked in any of the tests, so we leave it as
+ // zero
+ 0x00, 0x00,
+};
+
+// clang-format on
+
+static const QuicStringPiece kReferenceClientPacket(
+ kReferenceClientPacketData,
+ arraysize(kReferenceClientPacketData));
+
+static const QuicStringPiece kReferenceNetworkPacket(
+ kReferenceNetworkPacketData,
+ arraysize(kReferenceNetworkPacketData));
+
+static const QuicStringPiece kReferenceClientSubnetPacket(
+ kReferenceClientSubnetPacketData,
+ arraysize(kReferenceClientSubnetPacketData));
+
+MATCHER_P(IsIcmpMessage,
+ icmp_type,
+ "Checks whether the argument is an ICMP message of supplied type") {
+ if (arg.size() < kTotalICMPv6HeaderSize) {
+ return false;
+ }
+
+ return arg[40] == icmp_type;
+}
+
+class MockPacketFilter : public QbonePacketProcessor::Filter {
+ public:
+ MOCK_METHOD5(FilterPacket,
+ ProcessingResult(Direction,
+ QuicStringPiece,
+ QuicStringPiece,
+ icmp6_hdr*,
+ OutputInterface*));
+};
+
+class QbonePacketProcessorTest : public QuicTest {
+ protected:
+ QbonePacketProcessorTest() {
+ CHECK(client_ip_.FromString("fd00:0:0:1::1"));
+ CHECK(self_ip_.FromString("fd00:0:0:4::1"));
+ CHECK(network_ip_.FromString("fd00:0:0:5::1"));
+
+ processor_ = QuicMakeUnique<QbonePacketProcessor>(
+ self_ip_, client_ip_, /*client_ip_subnet_length=*/62, &output_,
+ &stats_);
+ }
+
+ void SendPacketFromClient(QuicStringPiece packet) {
+ string packet_buffer(packet.data(), packet.size());
+ processor_->ProcessPacket(&packet_buffer, Direction::FROM_CLIENT);
+ }
+
+ void SendPacketFromNetwork(QuicStringPiece packet) {
+ string packet_buffer(packet.data(), packet.size());
+ processor_->ProcessPacket(&packet_buffer, Direction::FROM_NETWORK);
+ }
+
+ QuicIpAddress client_ip_;
+ QuicIpAddress self_ip_;
+ QuicIpAddress network_ip_;
+
+ std::unique_ptr<QbonePacketProcessor> processor_;
+ testing::StrictMock<MockPacketProcessorOutput> output_;
+ testing::StrictMock<MockPacketProcessorStats> stats_;
+};
+
+TEST_F(QbonePacketProcessorTest, EmptyPacket) {
+ EXPECT_CALL(stats_, OnPacketDroppedSilently(Direction::FROM_CLIENT));
+ SendPacketFromClient("");
+
+ EXPECT_CALL(stats_, OnPacketDroppedSilently(Direction::FROM_NETWORK));
+ SendPacketFromNetwork("");
+}
+
+TEST_F(QbonePacketProcessorTest, RandomGarbage) {
+ EXPECT_CALL(stats_, OnPacketDroppedSilently(Direction::FROM_CLIENT));
+ SendPacketFromClient(string(1280, 'a'));
+
+ EXPECT_CALL(stats_, OnPacketDroppedSilently(Direction::FROM_NETWORK));
+ SendPacketFromNetwork(string(1280, 'a'));
+}
+
+TEST_F(QbonePacketProcessorTest, RandomGarbageWithCorrectLengthFields) {
+ string packet(40, 'a');
+ packet[4] = 0;
+ packet[5] = 0;
+
+ EXPECT_CALL(stats_, OnPacketDroppedWithIcmp(Direction::FROM_CLIENT));
+ EXPECT_CALL(output_, SendPacketToClient(IsIcmpMessage(ICMP6_DST_UNREACH)));
+ SendPacketFromClient(packet);
+}
+
+TEST_F(QbonePacketProcessorTest, GoodPacketFromClient) {
+ EXPECT_CALL(stats_, OnPacketForwarded(Direction::FROM_CLIENT));
+ EXPECT_CALL(output_, SendPacketToNetwork(_));
+ SendPacketFromClient(kReferenceClientPacket);
+}
+
+TEST_F(QbonePacketProcessorTest, GoodPacketFromClientSubnet) {
+ EXPECT_CALL(stats_, OnPacketForwarded(Direction::FROM_CLIENT));
+ EXPECT_CALL(output_, SendPacketToNetwork(_));
+ SendPacketFromClient(kReferenceClientSubnetPacket);
+}
+
+TEST_F(QbonePacketProcessorTest, GoodPacketFromNetwork) {
+ EXPECT_CALL(stats_, OnPacketForwarded(Direction::FROM_NETWORK));
+ EXPECT_CALL(output_, SendPacketToClient(_));
+ SendPacketFromNetwork(kReferenceNetworkPacket);
+}
+
+TEST_F(QbonePacketProcessorTest, GoodPacketFromNetworkWrongDirection) {
+ EXPECT_CALL(stats_, OnPacketDroppedWithIcmp(Direction::FROM_CLIENT));
+ EXPECT_CALL(output_, SendPacketToClient(IsIcmpMessage(ICMP6_DST_UNREACH)));
+ SendPacketFromClient(kReferenceNetworkPacket);
+}
+
+TEST_F(QbonePacketProcessorTest, TtlExpired) {
+ string packet(kReferenceNetworkPacket);
+ packet[7] = 1;
+
+ EXPECT_CALL(stats_, OnPacketDroppedWithIcmp(Direction::FROM_NETWORK));
+ EXPECT_CALL(output_, SendPacketToNetwork(IsIcmpMessage(ICMP6_TIME_EXCEEDED)));
+ SendPacketFromNetwork(packet);
+}
+
+TEST_F(QbonePacketProcessorTest, UnknownProtocol) {
+ string packet(kReferenceNetworkPacket);
+ packet[6] = IPPROTO_SCTP;
+
+ EXPECT_CALL(stats_, OnPacketDroppedWithIcmp(Direction::FROM_NETWORK));
+ EXPECT_CALL(output_, SendPacketToNetwork(IsIcmpMessage(ICMP6_PARAM_PROB)));
+ SendPacketFromNetwork(packet);
+}
+
+TEST_F(QbonePacketProcessorTest, FilterFromClient) {
+ auto filter = QuicMakeUnique<MockPacketFilter>();
+ EXPECT_CALL(*filter, FilterPacket(_, _, _, _, _))
+ .WillRepeatedly(Return(ProcessingResult::SILENT_DROP));
+ processor_->set_filter(std::move(filter));
+
+ EXPECT_CALL(stats_, OnPacketDroppedSilently(Direction::FROM_CLIENT));
+ SendPacketFromClient(kReferenceClientPacket);
+}
+
+class TestFilter : public QbonePacketProcessor::Filter {
+ public:
+ TestFilter(QuicIpAddress client_ip, QuicIpAddress network_ip)
+ : client_ip_(client_ip), network_ip_(network_ip) {}
+ ProcessingResult FilterPacket(Direction direction,
+ QuicStringPiece full_packet,
+ QuicStringPiece payload,
+ icmp6_hdr* icmp_header,
+ OutputInterface* output) override {
+ EXPECT_EQ(kIPv6HeaderSize, full_packet.size() - payload.size());
+ EXPECT_EQ(IPPROTO_UDP, TransportProtocolFromHeader(full_packet));
+ EXPECT_EQ(client_ip_, SourceIpFromHeader(full_packet));
+ EXPECT_EQ(network_ip_, DestinationIpFromHeader(full_packet));
+
+ called_++;
+ return ProcessingResult::SILENT_DROP;
+ }
+
+ int called() const { return called_; }
+
+ private:
+ int called_ = 0;
+
+ QuicIpAddress client_ip_;
+ QuicIpAddress network_ip_;
+};
+
+// Verify that the parameters are passed correctly into the filter, and that the
+// helper functions of the filter class work.
+TEST_F(QbonePacketProcessorTest, FilterHelperFunctions) {
+ auto filter_owned = QuicMakeUnique<TestFilter>(client_ip_, network_ip_);
+ TestFilter* filter = filter_owned.get();
+ processor_->set_filter(std::move(filter_owned));
+
+ EXPECT_CALL(stats_, OnPacketDroppedSilently(Direction::FROM_CLIENT));
+ SendPacketFromClient(kReferenceClientPacket);
+ ASSERT_EQ(1, filter->called());
+}
+
+} // namespace
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_processor_test_tools.cc b/chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_processor_test_tools.cc
new file mode 100644
index 00000000000..9f9b623be92
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_processor_test_tools.cc
@@ -0,0 +1,28 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/qbone/qbone_packet_processor_test_tools.h"
+
+#include <netinet/ip6.h>
+
+namespace quic {
+
+string PrependIPv6HeaderForTest(const string& body, int hops) {
+ ip6_hdr header;
+ memset(&header, 0, sizeof(header));
+
+ header.ip6_vfc = 6 << 4;
+ header.ip6_plen = htons(body.size());
+ header.ip6_nxt = IPPROTO_UDP;
+ header.ip6_hops = hops;
+ header.ip6_src = in6addr_loopback;
+ header.ip6_dst = in6addr_loopback;
+
+ string packet(sizeof(header) + body.size(), '\0');
+ memcpy(&packet[0], &header, sizeof(header));
+ memcpy(&packet[sizeof(header)], body.data(), body.size());
+ return packet;
+}
+
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_processor_test_tools.h b/chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_processor_test_tools.h
new file mode 100644
index 00000000000..646dc427c43
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_processor_test_tools.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_QBONE_QBONE_PACKET_PROCESSOR_TEST_TOOLS_H_
+#define QUICHE_QUIC_QBONE_QBONE_PACKET_PROCESSOR_TEST_TOOLS_H_
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+#include "net/third_party/quiche/src/quic/qbone/qbone_packet_processor.h"
+
+namespace quic {
+
+class MockPacketProcessorOutput : public QbonePacketProcessor::OutputInterface {
+ public:
+ MockPacketProcessorOutput() {}
+
+ MOCK_METHOD1(SendPacketToClient, void(QuicStringPiece));
+ MOCK_METHOD1(SendPacketToNetwork, void(QuicStringPiece));
+};
+
+class MockPacketProcessorStats : public QbonePacketProcessor::StatsInterface {
+ public:
+ MockPacketProcessorStats() {}
+
+ MOCK_METHOD1(OnPacketForwarded, void(QbonePacketProcessor::Direction));
+ MOCK_METHOD1(OnPacketDroppedSilently, void(QbonePacketProcessor::Direction));
+ MOCK_METHOD1(OnPacketDroppedWithIcmp, void(QbonePacketProcessor::Direction));
+ MOCK_METHOD1(OnPacketDroppedWithTcpReset,
+ void(QbonePacketProcessor::Direction));
+ MOCK_METHOD1(OnPacketDeferred, void(QbonePacketProcessor::Direction));
+};
+
+string PrependIPv6HeaderForTest(const string& body, int hops);
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_QBONE_QBONE_PACKET_PROCESSOR_TEST_TOOLS_H_
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_writer.h b/chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_writer.h
new file mode 100644
index 00000000000..1ed8a46fa04
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_writer.h
@@ -0,0 +1,24 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_QBONE_QBONE_PACKET_WRITER_H_
+#define QUICHE_QUIC_QBONE_QBONE_PACKET_WRITER_H_
+
+#include <cstring>
+
+namespace quic {
+
+// QbonePacketWriter expects only one function to be defined,
+// WritePacketToNetwork, which is called when a packet is received via QUIC
+// and should be sent out on the network. This is the complete packet,
+// and not just a fragment.
+class QbonePacketWriter {
+ public:
+ virtual ~QbonePacketWriter() {}
+ virtual void WritePacketToNetwork(const char* packet, size_t size) = 0;
+};
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_QBONE_QBONE_PACKET_WRITER_H_
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/qbone_server_session.cc b/chromium/net/third_party/quiche/src/quic/qbone/qbone_server_session.cc
new file mode 100644
index 00000000000..37cdd4cbe6f
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_server_session.cc
@@ -0,0 +1,94 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/qbone/qbone_server_session.h"
+
+#include "net/third_party/quiche/src/quic/core/quic_connection_id.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/core/quic_utils.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
+#include "net/third_party/quiche/src/quic/qbone/qbone_constants.h"
+
+namespace quic {
+
+bool QboneCryptoServerStreamHelper::CanAcceptClientHello(
+ const CryptoHandshakeMessage& chlo,
+ const QuicSocketAddress& client_address,
+ const QuicSocketAddress& peer_address,
+ const QuicSocketAddress& self_address,
+ string* error_details) const {
+ absl::string_view alpn;
+ chlo.GetStringPiece(quic::kALPN, &alpn);
+ if (alpn != QboneConstants::kQboneAlpn) {
+ *error_details = "ALPN-indicated protocol is not qbone";
+ return false;
+ }
+ return true;
+}
+
+QboneServerSession::QboneServerSession(
+ const quic::ParsedQuicVersionVector& supported_versions,
+ QuicConnection* connection,
+ Visitor* owner,
+ const QuicConfig& config,
+ const QuicCryptoServerConfig* quic_crypto_server_config,
+ QuicCompressedCertsCache* compressed_certs_cache,
+ QbonePacketWriter* writer,
+ QuicIpAddress self_ip,
+ QuicIpAddress client_ip,
+ size_t client_ip_subnet_length,
+ QboneServerControlStream::Handler* handler)
+ : QboneSessionBase(connection, owner, config, supported_versions, writer),
+ processor_(self_ip, client_ip, client_ip_subnet_length, this, this),
+ quic_crypto_server_config_(quic_crypto_server_config),
+ compressed_certs_cache_(compressed_certs_cache),
+ handler_(handler) {}
+
+QboneServerSession::~QboneServerSession() {}
+
+std::unique_ptr<QuicCryptoStream> QboneServerSession::CreateCryptoStream() {
+ return QuicMakeUnique<QuicCryptoServerStream>(quic_crypto_server_config_,
+ compressed_certs_cache_, this,
+ &stream_helper_);
+}
+
+void QboneServerSession::Initialize() {
+ QboneSessionBase::Initialize();
+ // Register the reserved control stream.
+ auto control_stream =
+ QuicMakeUnique<QboneServerControlStream>(this, handler_);
+ control_stream_ = control_stream.get();
+ RegisterStaticStream(std::move(control_stream));
+}
+
+bool QboneServerSession::SendClientRequest(const QboneClientRequest& request) {
+ if (!control_stream_) {
+ QUIC_BUG << "Cannot send client request before control stream is created.";
+ return false;
+ }
+ return control_stream_->SendRequest(request);
+}
+
+void QboneServerSession::ProcessPacketFromNetwork(QuicStringPiece packet) {
+ string buffer = string(packet);
+ processor_.ProcessPacket(&buffer,
+ QbonePacketProcessor::Direction::FROM_NETWORK);
+}
+
+void QboneServerSession::ProcessPacketFromPeer(QuicStringPiece packet) {
+ string buffer = string(packet);
+ processor_.ProcessPacket(&buffer,
+ QbonePacketProcessor::Direction::FROM_CLIENT);
+}
+
+void QboneServerSession::SendPacketToClient(QuicStringPiece packet) {
+ SendPacketToPeer(packet);
+}
+
+void QboneServerSession::SendPacketToNetwork(QuicStringPiece packet) {
+ DCHECK(writer_ != nullptr);
+ writer_->WritePacketToNetwork(packet.data(), packet.size());
+}
+
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/qbone_server_session.h b/chromium/net/third_party/quiche/src/quic/qbone/qbone_server_session.h
new file mode 100644
index 00000000000..9536f872de5
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_server_session.h
@@ -0,0 +1,92 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_QBONE_QBONE_SERVER_SESSION_H_
+#define QUICHE_QUIC_QBONE_QBONE_SERVER_SESSION_H_
+
+#include "net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h"
+#include "net/third_party/quiche/src/quic/core/quic_crypto_stream.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
+#include "net/third_party/quiche/src/quic/qbone/qbone_control.pb.h"
+#include "net/third_party/quiche/src/quic/qbone/qbone_control_stream.h"
+#include "net/third_party/quiche/src/quic/qbone/qbone_packet_processor.h"
+#include "net/third_party/quiche/src/quic/qbone/qbone_packet_writer.h"
+#include "net/third_party/quiche/src/quic/qbone/qbone_session_base.h"
+
+namespace quic {
+
+// A helper class is used by the QuicCryptoServerStream.
+class QboneCryptoServerStreamHelper : public QuicCryptoServerStream::Helper {
+ public:
+ // This will look for the qbone alpn.
+ bool CanAcceptClientHello(const CryptoHandshakeMessage& chlo,
+ const QuicSocketAddress& client_address,
+ const QuicSocketAddress& peer_address,
+ const QuicSocketAddress& self_address,
+ string* error_details) const override;
+};
+
+class QUIC_EXPORT_PRIVATE QboneServerSession
+ : public QboneSessionBase,
+ public QbonePacketProcessor::OutputInterface,
+ public QbonePacketProcessor::StatsInterface {
+ public:
+ QboneServerSession(const quic::ParsedQuicVersionVector& supported_versions,
+ QuicConnection* connection,
+ Visitor* owner,
+ const QuicConfig& config,
+ const QuicCryptoServerConfig* quic_crypto_server_config,
+ QuicCompressedCertsCache* compressed_certs_cache,
+ QbonePacketWriter* writer,
+ QuicIpAddress self_ip,
+ QuicIpAddress client_ip,
+ size_t client_ip_subnet_length,
+ QboneServerControlStream::Handler* handler);
+ QboneServerSession(const QboneServerSession&) = delete;
+ QboneServerSession& operator=(const QboneServerSession&) = delete;
+ ~QboneServerSession() override;
+
+ void Initialize() override;
+
+ virtual bool SendClientRequest(const QboneClientRequest& request);
+
+ void ProcessPacketFromNetwork(QuicStringPiece packet) override;
+ void ProcessPacketFromPeer(QuicStringPiece packet) override;
+
+ // QbonePacketProcessor::OutputInterface implementation.
+ void SendPacketToClient(QuicStringPiece packet) override;
+ void SendPacketToNetwork(QuicStringPiece packet) override;
+
+ // QbonePacketProcessor::StatsInterface implementation.
+ void OnPacketForwarded(QbonePacketProcessor::Direction direction) override {}
+ void OnPacketDroppedSilently(
+ QbonePacketProcessor::Direction direction) override {}
+ void OnPacketDroppedWithIcmp(
+ QbonePacketProcessor::Direction direction) override {}
+ void OnPacketDroppedWithTcpReset(
+ QbonePacketProcessor::Direction direction) override {}
+ void OnPacketDeferred(QbonePacketProcessor::Direction direction) override {}
+
+ protected:
+ // QboneSessionBase interface implementation.
+ std::unique_ptr<QuicCryptoStream> CreateCryptoStream() override;
+ // The packet processor.
+ QbonePacketProcessor processor_;
+
+ private:
+ // Config for QUIC crypto server stream, used by the server.
+ const QuicCryptoServerConfig* quic_crypto_server_config_;
+ // Used by QUIC crypto server stream to track most recently compressed certs.
+ QuicCompressedCertsCache* compressed_certs_cache_;
+ // This helper is needed when create QuicCryptoServerStream.
+ QboneCryptoServerStreamHelper stream_helper_;
+ // Passed to the control stream.
+ QboneServerControlStream::Handler* handler_;
+ // The unowned control stream.
+ QboneServerControlStream* control_stream_;
+};
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_QBONE_QBONE_SERVER_SESSION_H_
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/qbone_session_base.cc b/chromium/net/third_party/quiche/src/quic/qbone/qbone_session_base.cc
new file mode 100644
index 00000000000..d88197540e7
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_session_base.cc
@@ -0,0 +1,150 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/qbone/qbone_session_base.h"
+
+#include "net/third_party/quiche/src/quic/core/quic_data_reader.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_exported_stats.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
+#include "net/third_party/quiche/src/quic/qbone/qbone_constants.h"
+
+namespace quic {
+
+#define ENDPOINT \
+ (perspective() == Perspective::IS_SERVER ? "Server: " : "Client: ")
+
+QboneSessionBase::QboneSessionBase(
+ QuicConnection* connection,
+ Visitor* owner,
+ const QuicConfig& config,
+ const ParsedQuicVersionVector& supported_versions,
+ QbonePacketWriter* writer)
+ : QuicSession(connection,
+ owner,
+ config,
+ supported_versions,
+ /*num_expected_unidirectional_static_streams = */ 0) {
+ set_writer(writer);
+ const uint32_t max_streams =
+ (std::numeric_limits<uint32_t>::max() / kMaxAvailableStreamsMultiplier) -
+ 1;
+ this->config()->SetMaxIncomingBidirectionalStreamsToSend(max_streams);
+ if (VersionHasIetfQuicFrames(transport_version())) {
+ ConfigureMaxIncomingDynamicStreamsToSend(max_streams);
+ }
+}
+
+QboneSessionBase::~QboneSessionBase() {
+ // Clear out the streams before leaving this destructor to avoid calling
+ // QuicSession::UnregisterStreamPriority
+ stream_map().clear();
+ closed_streams()->clear();
+}
+
+void QboneSessionBase::Initialize() {
+ crypto_stream_ = CreateCryptoStream();
+ QuicSession::Initialize();
+}
+
+const QuicCryptoStream* QboneSessionBase::GetCryptoStream() const {
+ return crypto_stream_.get();
+}
+
+QuicCryptoStream* QboneSessionBase::GetMutableCryptoStream() {
+ return crypto_stream_.get();
+}
+
+QuicStream* QboneSessionBase::CreateOutgoingStream() {
+ return ActivateDataStream(
+ CreateDataStream(GetNextOutgoingUnidirectionalStreamId()));
+}
+
+void QboneSessionBase::CloseStream(QuicStreamId stream_id) {
+ if (IsClosedStream(stream_id)) {
+ // When CloseStream has been called recursively (via
+ // QuicStream::OnClose), the stream is already closed so return.
+ return;
+ }
+ QuicSession::CloseStream(stream_id);
+}
+
+void QboneSessionBase::OnStreamFrame(const QuicStreamFrame& frame) {
+ if (frame.offset == 0 && frame.fin && frame.data_length > 0) {
+ ++num_ephemeral_packets_;
+ ProcessPacketFromPeer(
+ QuicStringPiece(frame.data_buffer, frame.data_length));
+ flow_controller()->AddBytesConsumed(frame.data_length);
+ return;
+ }
+ QuicSession::OnStreamFrame(frame);
+}
+
+QuicStream* QboneSessionBase::CreateIncomingStream(QuicStreamId id) {
+ return ActivateDataStream(CreateDataStream(id));
+}
+
+QuicStream* QboneSessionBase::CreateIncomingStream(PendingStream* /*pending*/) {
+ QUIC_NOTREACHED();
+ return nullptr;
+}
+
+bool QboneSessionBase::ShouldKeepConnectionAlive() const {
+ // Qbone connections stay alive until they're explicitly closed.
+ return true;
+}
+
+std::unique_ptr<QuicStream> QboneSessionBase::CreateDataStream(
+ QuicStreamId id) {
+ if (crypto_stream_ == nullptr || !crypto_stream_->encryption_established()) {
+ // Encryption not active so no stream created
+ return nullptr;
+ }
+
+ if (IsIncomingStream(id)) {
+ ++num_streamed_packets_;
+ return QuicMakeUnique<QboneReadOnlyStream>(id, this);
+ }
+
+ return QuicMakeUnique<QboneWriteOnlyStream>(id, this);
+}
+
+QuicStream* QboneSessionBase::ActivateDataStream(
+ std::unique_ptr<QuicStream> stream) {
+ // Transfer ownership of the data stream to the session via ActivateStream().
+ QuicStream* raw = stream.get();
+ if (stream) {
+ // Make QuicSession take ownership of the stream.
+ ActivateStream(std::move(stream));
+ }
+ return raw;
+}
+
+void QboneSessionBase::SendPacketToPeer(QuicStringPiece packet) {
+ // Qbone streams are ephemeral.
+ QuicStream* stream = CreateOutgoingStream();
+ if (!stream) {
+ QUIC_BUG << "Failed to create an outgoing QBONE stream.";
+ return;
+ }
+
+ QboneWriteOnlyStream* qbone_stream =
+ static_cast<QboneWriteOnlyStream*>(stream);
+ qbone_stream->WritePacketToQuicStream(packet);
+}
+
+uint64_t QboneSessionBase::GetNumEphemeralPackets() const {
+ return num_ephemeral_packets_;
+}
+
+uint64_t QboneSessionBase::GetNumStreamedPackets() const {
+ return num_streamed_packets_;
+}
+
+void QboneSessionBase::set_writer(QbonePacketWriter* writer) {
+ writer_ = writer;
+ testing::testvalue::Adjust("quic_QbonePacketWriter", &writer_);
+}
+
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/qbone_session_base.h b/chromium/net/third_party/quiche/src/quic/qbone/qbone_session_base.h
new file mode 100644
index 00000000000..5bfc9be440d
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_session_base.h
@@ -0,0 +1,93 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_QBONE_QBONE_SESSION_BASE_H_
+#define QUICHE_QUIC_QBONE_QBONE_SESSION_BASE_H_
+
+#include "net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h"
+#include "net/third_party/quiche/src/quic/core/quic_crypto_stream.h"
+#include "net/third_party/quiche/src/quic/core/quic_error_codes.h"
+#include "net/third_party/quiche/src/quic/core/quic_session.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
+#include "net/third_party/quiche/src/quic/qbone/qbone_packet_writer.h"
+#include "net/third_party/quiche/src/quic/qbone/qbone_stream.h"
+
+namespace quic {
+
+class QUIC_EXPORT_PRIVATE QboneSessionBase : public QuicSession {
+ public:
+ QboneSessionBase(QuicConnection* connection,
+ Visitor* owner,
+ const QuicConfig& config,
+ const ParsedQuicVersionVector& supported_versions,
+ QbonePacketWriter* writer);
+ QboneSessionBase(const QboneSessionBase&) = delete;
+ QboneSessionBase& operator=(const QboneSessionBase&) = delete;
+ ~QboneSessionBase() override;
+
+ // Overrides from QuicSession.
+ // This will ensure that the crypto session is created.
+ void Initialize() override;
+ // This will ensure that we keep track of stream ids that can be
+ // write blocked.
+ void CloseStream(QuicStreamId stream_id) override;
+ // This will check if the packet is wholly contained.
+ void OnStreamFrame(const QuicStreamFrame& frame) override;
+
+ virtual void ProcessPacketFromNetwork(QuicStringPiece packet) = 0;
+ virtual void ProcessPacketFromPeer(QuicStringPiece packet) = 0;
+
+ // Returns the number of qbone network packets that were received
+ // that fit into a single QuicStreamFrame and elided the creation of
+ // a QboneReadOnlyStream.
+ uint64_t GetNumEphemeralPackets() const;
+
+ // Returns the number of qbone network packets that were via
+ // multiple packets, requiring the creation of a QboneReadOnlyStream.
+ uint64_t GetNumStreamedPackets() const;
+
+ void set_writer(QbonePacketWriter* writer);
+
+ protected:
+ virtual std::unique_ptr<QuicCryptoStream> CreateCryptoStream() = 0;
+
+ // QuicSession interface implementation.
+ QuicCryptoStream* GetMutableCryptoStream() override;
+ const QuicCryptoStream* GetCryptoStream() const override;
+ QuicStream* CreateIncomingStream(QuicStreamId id) override;
+ QuicStream* CreateIncomingStream(PendingStream* pending) override;
+ bool ShouldKeepConnectionAlive() const override;
+
+ bool MaybeIncreaseLargestPeerStreamId(const QuicStreamId stream_id) override {
+ return true;
+ }
+
+ QuicStream* CreateOutgoingStream();
+ std::unique_ptr<QuicStream> CreateDataStream(QuicStreamId id);
+ // Activates a QuicStream. The session takes ownership of the stream, but
+ // returns an unowned pointer to the stream for convenience.
+ QuicStream* ActivateDataStream(std::unique_ptr<QuicStream> stream);
+
+ // Accepts a given packet from the network and writes it out
+ // to the QUIC stream. This will create an ephemeral stream per
+ // packet. This function will return true if a stream was created
+ // and the packet sent. It will return false if the stream could not
+ // be created.
+ void SendPacketToPeer(QuicStringPiece packet);
+
+ QbonePacketWriter* writer_;
+
+ private:
+ // Used for the crypto handshake.
+ std::unique_ptr<QuicCryptoStream> crypto_stream_;
+
+ uint64_t num_ephemeral_packets_ = 0;
+ uint64_t num_streamed_packets_ = 0;
+ QuicUnorderedSet<QuicStreamId> reliable_streams_;
+};
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_QBONE_QBONE_SESSION_BASE_H_
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
new file mode 100644
index 00000000000..be598a927ff
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_session_test.cc
@@ -0,0 +1,520 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/core/proto/crypto_server_config_proto.h"
+#include "net/third_party/quiche/src/quic/core/quic_alarm_factory.h"
+#include "net/third_party/quiche/src/quic/core/quic_epoll_alarm_factory.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_port_utils.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_test_loopback.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
+#include "net/third_party/quiche/src/quic/qbone/qbone_client_session.h"
+#include "net/third_party/quiche/src/quic/qbone/qbone_constants.h"
+#include "net/third_party/quiche/src/quic/qbone/qbone_control_placeholder.pb.h"
+#include "net/third_party/quiche/src/quic/qbone/qbone_packet_processor_test_tools.h"
+#include "net/third_party/quiche/src/quic/qbone/qbone_server_session.h"
+#include "net/third_party/quiche/src/quic/test_tools/mock_clock.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_session_peer.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
+
+namespace quic {
+namespace test {
+namespace {
+
+using ::testing::_;
+using ::testing::Contains;
+using ::testing::ElementsAre;
+using ::testing::Eq;
+using ::testing::Invoke;
+using ::testing::NiceMock;
+using ::testing::Not;
+
+string TestPacketIn(const string& body) {
+ return PrependIPv6HeaderForTest(body, 5);
+}
+
+string TestPacketOut(const string& body) {
+ return PrependIPv6HeaderForTest(body, 4);
+}
+
+// Used by QuicCryptoServerConfig to provide server credentials, returning a
+// canned response equal to |success|.
+class FakeProofSource : public ProofSource {
+ public:
+ explicit FakeProofSource(bool success) : success_(success) {}
+
+ // ProofSource override.
+ void GetProof(const QuicSocketAddress& server_address,
+ const string& hostname,
+ const string& server_config,
+ QuicTransportVersion transport_version,
+ QuicStringPiece chlo_hash,
+ std::unique_ptr<Callback> callback) override {
+ QuicReferenceCountedPointer<ProofSource::Chain> chain =
+ GetCertChain(server_address, hostname);
+ QuicCryptoProof proof;
+ if (success_) {
+ proof.signature = "Signature";
+ proof.leaf_cert_scts = "Time";
+ }
+ callback->Run(success_, chain, proof, nullptr /* details */);
+ }
+
+ QuicReferenceCountedPointer<Chain> GetCertChain(
+ const QuicSocketAddress& server_address,
+ const string& hostname) override {
+ if (!success_) {
+ return QuicReferenceCountedPointer<Chain>();
+ }
+ std::vector<string> certs;
+ certs.push_back("Required to establish handshake");
+ return QuicReferenceCountedPointer<ProofSource::Chain>(
+ new ProofSource::Chain(certs));
+ }
+
+ void ComputeTlsSignature(
+ const QuicSocketAddress& server_address,
+ const string& hostname,
+ uint16_t signature_algorithm,
+ QuicStringPiece in,
+ std::unique_ptr<SignatureCallback> callback) override {
+ callback->Run(true, "Signature");
+ }
+
+ private:
+ // Whether or not obtaining proof source succeeds.
+ bool success_;
+};
+
+// Used by QuicCryptoClientConfig to verify server credentials, returning a
+// canned response of QUIC_SUCCESS if |success| is true.
+class FakeProofVerifier : public ProofVerifier {
+ public:
+ explicit FakeProofVerifier(bool success) : success_(success) {}
+
+ // ProofVerifier override
+ QuicAsyncStatus VerifyProof(
+ const string& hostname,
+ const uint16_t port,
+ const string& server_config,
+ QuicTransportVersion transport_version,
+ QuicStringPiece chlo_hash,
+ const std::vector<string>& certs,
+ const string& cert_sct,
+ const string& signature,
+ const ProofVerifyContext* context,
+ string* error_details,
+ std::unique_ptr<ProofVerifyDetails>* verify_details,
+ std::unique_ptr<ProofVerifierCallback> callback) override {
+ return success_ ? QUIC_SUCCESS : QUIC_FAILURE;
+ }
+
+ QuicAsyncStatus VerifyCertChain(
+ const string& hostname,
+ const std::vector<string>& certs,
+ const std::string& ocsp_response,
+ const std::string& cert_sct,
+ const ProofVerifyContext* context,
+ string* error_details,
+ std::unique_ptr<ProofVerifyDetails>* details,
+ std::unique_ptr<ProofVerifierCallback> callback) override {
+ return success_ ? QUIC_SUCCESS : QUIC_FAILURE;
+ }
+
+ std::unique_ptr<ProofVerifyContext> CreateDefaultContext() override {
+ return nullptr;
+ }
+
+ private:
+ // Whether or not proof verification succeeds.
+ bool success_;
+};
+
+class DataSavingQbonePacketWriter : public QbonePacketWriter {
+ public:
+ void WritePacketToNetwork(const char* packet, size_t size) override {
+ data_.push_back(string(packet, size));
+ }
+
+ const std::vector<string>& data() { return data_; }
+
+ private:
+ std::vector<string> data_;
+};
+
+template <class T>
+class DataSavingQboneControlHandler : public QboneControlHandler<T> {
+ public:
+ void OnControlRequest(const T& request) override { data_.push_back(request); }
+
+ void OnControlError() override { error_ = true; }
+
+ const std::vector<T>& data() { return data_; }
+ bool error() { return error_; }
+
+ private:
+ std::vector<T> data_;
+ bool error_ = false;
+};
+
+// Single-threaded scheduled task runner based on a MockClock.
+//
+// Simulates asynchronous execution on a single thread by holding scheduled
+// tasks until Run() is called. Performs no synchronization, assumes that
+// Schedule() and Run() are called on the same thread.
+class FakeTaskRunner {
+ public:
+ explicit FakeTaskRunner(MockQuicConnectionHelper* helper)
+ : tasks_([this](const TaskType& l, const TaskType& r) {
+ // Items at a later time should run after items at an earlier time.
+ // Priority queue comparisons should return true if l appears after r.
+ return l->time() > r->time();
+ }),
+ helper_(helper) {}
+
+ // Runs all tasks in time order. Executes tasks scheduled at
+ // the same in an arbitrary order.
+ void Run() {
+ while (!tasks_.empty()) {
+ tasks_.top()->Run();
+ tasks_.pop();
+ }
+ }
+
+ private:
+ class InnerTask {
+ public:
+ InnerTask(std::function<void()> task, QuicTime time)
+ : task_(std::move(task)), time_(time) {}
+
+ void Cancel() { cancelled_ = true; }
+
+ void Run() {
+ if (!cancelled_) {
+ task_();
+ }
+ }
+
+ QuicTime time() const { return time_; }
+
+ private:
+ bool cancelled_ = false;
+ std::function<void()> task_;
+ QuicTime time_;
+ };
+
+ public:
+ // Schedules a function to run immediately and advances the time.
+ void Schedule(std::function<void()> task) {
+ tasks_.push(std::shared_ptr<InnerTask>(
+ new InnerTask(std::move(task), helper_->GetClock()->Now())));
+ helper_->AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
+ }
+
+ private:
+ using TaskType = std::shared_ptr<InnerTask>;
+ std::priority_queue<TaskType,
+ std::vector<TaskType>,
+ std::function<bool(const TaskType&, const TaskType&)>>
+ tasks_;
+ MockQuicConnectionHelper* helper_;
+};
+
+class QboneSessionTest : public QuicTest {
+ public:
+ QboneSessionTest() : runner_(&helper_), compressed_certs_cache_(100) {}
+
+ ~QboneSessionTest() override {
+ delete client_connection_;
+ delete server_connection_;
+ }
+
+ const MockClock* GetClock() const {
+ return static_cast<const MockClock*>(helper_.GetClock());
+ }
+
+ // The parameters are used to control whether the handshake will success or
+ // not.
+ void CreateClientAndServerSessions(bool client_handshake_success = true,
+ bool server_handshake_success = true,
+ bool send_qbone_alpn = true) {
+ // Quic crashes if packets are sent at time 0, and the clock defaults to 0.
+ helper_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1000));
+ alarm_factory_ = QuicMakeUnique<QuicEpollAlarmFactory>(&epoll_server_);
+ client_writer_ = QuicMakeUnique<DataSavingQbonePacketWriter>();
+ server_writer_ = QuicMakeUnique<DataSavingQbonePacketWriter>();
+ client_handler_ =
+ QuicMakeUnique<DataSavingQboneControlHandler<QboneClientRequest>>();
+ server_handler_ =
+ QuicMakeUnique<DataSavingQboneControlHandler<QboneServerRequest>>();
+ QuicSocketAddress server_address(TestLoopback(),
+ QuicPickServerPortForTestsOrDie());
+ QuicSocketAddress client_address;
+ if (server_address.host().address_family() == IpAddressFamily::IP_V4) {
+ client_address = QuicSocketAddress(QuicIpAddress::Any4(), 0);
+ } else {
+ client_address = QuicSocketAddress(QuicIpAddress::Any6(), 0);
+ }
+
+ {
+ client_connection_ = new QuicConnection(
+ TestConnectionId(), server_address, &helper_, alarm_factory_.get(),
+ new NiceMock<MockPacketWriter>(), true, Perspective::IS_CLIENT,
+ ParsedVersionOfIndex(AllSupportedVersions(), 0));
+ client_connection_->SetSelfAddress(client_address);
+ QuicConfig config;
+ client_crypto_config_ = QuicMakeUnique<QuicCryptoClientConfig>(
+ QuicMakeUnique<FakeProofVerifier>(client_handshake_success));
+ if (send_qbone_alpn) {
+ client_crypto_config_->set_alpn("qbone");
+ }
+ client_peer_ = QuicMakeUnique<QboneClientSession>(
+ client_connection_, client_crypto_config_.get(),
+ /*owner=*/nullptr, config,
+ ParsedVersionOfIndex(AllSupportedVersions(), 0),
+ QuicServerId("test.example.com", 1234, false), client_writer_.get(),
+ client_handler_.get());
+ }
+
+ {
+ server_connection_ = new QuicConnection(
+ TestConnectionId(), client_address, &helper_, alarm_factory_.get(),
+ new NiceMock<MockPacketWriter>(), true, Perspective::IS_SERVER,
+ ParsedVersionOfIndex(AllSupportedVersions(), 0));
+ server_connection_->SetSelfAddress(server_address);
+ QuicConfig config;
+ server_crypto_config_ = QuicMakeUnique<QuicCryptoServerConfig>(
+ "TESTING", QuicRandom::GetInstance(),
+ std::unique_ptr<FakeProofSource>(
+ new FakeProofSource(server_handshake_success)),
+ KeyExchangeSource::Default());
+ QuicCryptoServerConfig::ConfigOptions options;
+ QuicServerConfigProtobuf primary_config =
+ server_crypto_config_->GenerateConfig(QuicRandom::GetInstance(),
+ GetClock(), options);
+ std::unique_ptr<CryptoHandshakeMessage> message(
+ server_crypto_config_->AddConfig(std::move(primary_config),
+ GetClock()->WallNow()));
+
+ server_peer_ = QuicMakeUnique<QboneServerSession>(
+ AllSupportedVersions(), server_connection_, nullptr, config,
+ server_crypto_config_.get(), &compressed_certs_cache_,
+ server_writer_.get(), TestLoopback6(), TestLoopback6(), 64,
+ server_handler_.get());
+ }
+
+ // Hook everything up!
+ MockPacketWriter* client_writer = static_cast<MockPacketWriter*>(
+ QuicConnectionPeer::GetWriter(client_peer_->connection()));
+ ON_CALL(*client_writer, WritePacket(_, _, _, _, _))
+ .WillByDefault(Invoke([this](const char* buffer, size_t buf_len,
+ const QuicIpAddress& self_address,
+ const QuicSocketAddress& peer_address,
+ PerPacketOptions* options) {
+ char* copy = new char[1024 * 1024];
+ memcpy(copy, buffer, buf_len);
+ runner_.Schedule([this, copy, buf_len] {
+ QuicReceivedPacket packet(copy, buf_len, GetClock()->Now());
+ server_peer_->ProcessUdpPacket(server_connection_->self_address(),
+ client_connection_->self_address(),
+ packet);
+ delete[] copy;
+ });
+ return WriteResult(WRITE_STATUS_OK, buf_len);
+ }));
+ MockPacketWriter* server_writer = static_cast<MockPacketWriter*>(
+ QuicConnectionPeer::GetWriter(server_peer_->connection()));
+ ON_CALL(*server_writer, WritePacket(_, _, _, _, _))
+ .WillByDefault(Invoke([this](const char* buffer, size_t buf_len,
+ const QuicIpAddress& self_address,
+ const QuicSocketAddress& peer_address,
+ PerPacketOptions* options) {
+ char* copy = new char[1024 * 1024];
+ memcpy(copy, buffer, buf_len);
+ runner_.Schedule([this, copy, buf_len] {
+ QuicReceivedPacket packet(copy, buf_len, GetClock()->Now());
+ client_peer_->ProcessUdpPacket(client_connection_->self_address(),
+ server_connection_->self_address(),
+ packet);
+ delete[] copy;
+ });
+ return WriteResult(WRITE_STATUS_OK, buf_len);
+ }));
+ }
+
+ void StartHandshake() {
+ server_peer_->Initialize();
+ client_peer_->Initialize();
+ runner_.Run();
+ }
+
+ // Test handshake establishment and sending/receiving of data for two
+ // directions.
+ void TestStreamConnection() {
+ ASSERT_TRUE(server_peer_->IsCryptoHandshakeConfirmed());
+ ASSERT_TRUE(client_peer_->IsCryptoHandshakeConfirmed());
+ ASSERT_TRUE(server_peer_->IsEncryptionEstablished());
+ ASSERT_TRUE(client_peer_->IsEncryptionEstablished());
+
+ // Create an outgoing stream from the client and say hello.
+ QUIC_LOG(INFO) << "Sending client -> server";
+ client_peer_->ProcessPacketFromNetwork(TestPacketIn("hello"));
+ client_peer_->ProcessPacketFromNetwork(TestPacketIn("world"));
+ runner_.Run();
+ // The server should see the data, the client hasn't received
+ // anything yet.
+ EXPECT_THAT(server_writer_->data(),
+ ElementsAre(TestPacketOut("hello"), TestPacketOut("world")));
+ EXPECT_TRUE(client_writer_->data().empty());
+ EXPECT_EQ(0u, server_peer_->GetNumActiveStreams());
+ EXPECT_EQ(0u, client_peer_->GetNumActiveStreams());
+
+ // Let's pretend some service responds.
+ QUIC_LOG(INFO) << "Sending server -> client";
+ server_peer_->ProcessPacketFromNetwork(TestPacketIn("Hello Again"));
+ server_peer_->ProcessPacketFromNetwork(TestPacketIn("Again"));
+ runner_.Run();
+ EXPECT_THAT(server_writer_->data(),
+ ElementsAre(TestPacketOut("hello"), TestPacketOut("world")));
+ EXPECT_THAT(
+ client_writer_->data(),
+ ElementsAre(TestPacketOut("Hello Again"), TestPacketOut("Again")));
+ EXPECT_EQ(0u, server_peer_->GetNumActiveStreams());
+ EXPECT_EQ(0u, client_peer_->GetNumActiveStreams());
+
+ // Try to send long payloads that are larger than the QUIC MTU but
+ // smaller than the QBONE max size.
+ // This should trigger the non-ephemeral stream code path.
+ string long_data(QboneConstants::kMaxQbonePacketBytes - sizeof(ip6_hdr) - 1,
+ 'A');
+ QUIC_LOG(INFO) << "Sending server -> client long data";
+ server_peer_->ProcessPacketFromNetwork(TestPacketIn(long_data));
+ runner_.Run();
+ EXPECT_THAT(client_writer_->data(), Contains(TestPacketOut(long_data)));
+ EXPECT_THAT(server_writer_->data(),
+ Not(Contains(TestPacketOut(long_data))));
+ EXPECT_EQ(0u, server_peer_->GetNumActiveStreams());
+ EXPECT_EQ(0u, client_peer_->GetNumActiveStreams());
+
+ QUIC_LOG(INFO) << "Sending client -> server long data";
+ client_peer_->ProcessPacketFromNetwork(TestPacketIn(long_data));
+ runner_.Run();
+ EXPECT_THAT(server_writer_->data(), Contains(TestPacketOut(long_data)));
+ EXPECT_THAT(client_peer_->GetNumSentClientHellos(), Eq(2));
+ EXPECT_THAT(client_peer_->GetNumReceivedServerConfigUpdates(), Eq(0));
+ EXPECT_THAT(client_peer_->GetNumEphemeralPackets(), Eq(2));
+ EXPECT_THAT(client_peer_->GetNumStreamedPackets(), Eq(1));
+ EXPECT_THAT(server_peer_->GetNumEphemeralPackets(), Eq(2));
+ EXPECT_THAT(server_peer_->GetNumStreamedPackets(), Eq(1));
+
+ // All streams are ephemeral and should be gone.
+ EXPECT_EQ(0u, server_peer_->GetNumActiveStreams());
+ EXPECT_EQ(0u, client_peer_->GetNumActiveStreams());
+ }
+
+ // Test that client and server are not connected after handshake failure.
+ void TestDisconnectAfterFailedHandshake() {
+ EXPECT_FALSE(client_peer_->IsEncryptionEstablished());
+ EXPECT_FALSE(client_peer_->IsCryptoHandshakeConfirmed());
+
+ EXPECT_FALSE(server_peer_->IsEncryptionEstablished());
+ EXPECT_FALSE(server_peer_->IsCryptoHandshakeConfirmed());
+ }
+
+ protected:
+ QuicEpollServer epoll_server_;
+ std::unique_ptr<QuicAlarmFactory> alarm_factory_;
+ FakeTaskRunner runner_;
+ MockQuicConnectionHelper helper_;
+ QuicConnection* client_connection_;
+ QuicConnection* server_connection_;
+ QuicCompressedCertsCache compressed_certs_cache_;
+
+ std::unique_ptr<QuicCryptoClientConfig> client_crypto_config_;
+ std::unique_ptr<QuicCryptoServerConfig> server_crypto_config_;
+ std::unique_ptr<DataSavingQbonePacketWriter> client_writer_;
+ std::unique_ptr<DataSavingQbonePacketWriter> server_writer_;
+ std::unique_ptr<DataSavingQboneControlHandler<QboneClientRequest>>
+ client_handler_;
+ std::unique_ptr<DataSavingQboneControlHandler<QboneServerRequest>>
+ server_handler_;
+
+ std::unique_ptr<QboneServerSession> server_peer_;
+ std::unique_ptr<QboneClientSession> client_peer_;
+};
+
+TEST_F(QboneSessionTest, StreamConnection) {
+ CreateClientAndServerSessions();
+ StartHandshake();
+ TestStreamConnection();
+}
+
+TEST_F(QboneSessionTest, ClientRejection) {
+ CreateClientAndServerSessions(false /*client_handshake_success*/,
+ true /*server_handshake_success*/,
+ true /*send_qbone_alpn*/);
+ StartHandshake();
+ TestDisconnectAfterFailedHandshake();
+}
+
+TEST_F(QboneSessionTest, BadAlpn) {
+ CreateClientAndServerSessions(true /*client_handshake_success*/,
+ true /*server_handshake_success*/,
+ false /*send_qbone_alpn*/);
+ StartHandshake();
+ TestDisconnectAfterFailedHandshake();
+}
+
+TEST_F(QboneSessionTest, ServerRejection) {
+ CreateClientAndServerSessions(true /*client_handshake_success*/,
+ false /*server_handshake_success*/,
+ true /*send_qbone_alpn*/);
+ StartHandshake();
+ TestDisconnectAfterFailedHandshake();
+}
+
+// Test that data streams are not created before handshake.
+TEST_F(QboneSessionTest, CannotCreateDataStreamBeforeHandshake) {
+ CreateClientAndServerSessions();
+ EXPECT_QUIC_BUG(client_peer_->ProcessPacketFromNetwork(TestPacketIn("hello")),
+ "Failed to create an outgoing QBONE stream");
+ EXPECT_QUIC_BUG(server_peer_->ProcessPacketFromNetwork(TestPacketIn("hello")),
+ "Failed to create an outgoing QBONE stream");
+ EXPECT_EQ(0u, server_peer_->GetNumActiveStreams());
+ EXPECT_EQ(0u, client_peer_->GetNumActiveStreams());
+}
+
+TEST_F(QboneSessionTest, ControlRequests) {
+ CreateClientAndServerSessions();
+ StartHandshake();
+ EXPECT_TRUE(client_handler_->data().empty());
+ EXPECT_FALSE(client_handler_->error());
+ EXPECT_TRUE(server_handler_->data().empty());
+ EXPECT_FALSE(server_handler_->error());
+
+ QboneClientRequest client_request;
+ client_request.SetExtension(client_placeholder, "hello from the server");
+ EXPECT_TRUE(server_peer_->SendClientRequest(client_request));
+ runner_.Run();
+ ASSERT_FALSE(client_handler_->data().empty());
+ EXPECT_THAT(client_handler_->data()[0].GetExtension(client_placeholder),
+ Eq("hello from the server"));
+ EXPECT_FALSE(client_handler_->error());
+
+ QboneServerRequest server_request;
+ server_request.SetExtension(server_placeholder, "hello from the client");
+ EXPECT_TRUE(client_peer_->SendServerRequest(server_request));
+ runner_.Run();
+ ASSERT_FALSE(server_handler_->data().empty());
+ EXPECT_THAT(server_handler_->data()[0].GetExtension(server_placeholder),
+ Eq("hello from the client"));
+ EXPECT_FALSE(server_handler_->error());
+}
+
+} // namespace
+} // namespace test
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/qbone_stream.cc b/chromium/net/third_party/quiche/src/quic/qbone/qbone_stream.cc
new file mode 100644
index 00000000000..b7ac0078561
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_stream.cc
@@ -0,0 +1,61 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/qbone/qbone_stream.h"
+
+#include "net/third_party/quiche/src/quic/core/quic_data_reader.h"
+#include "net/third_party/quiche/src/quic/core/quic_data_writer.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
+#include "net/third_party/quiche/src/quic/qbone/qbone_constants.h"
+#include "net/third_party/quiche/src/quic/qbone/qbone_session_base.h"
+
+namespace quic {
+
+QboneWriteOnlyStream::QboneWriteOnlyStream(QuicStreamId id,
+ QuicSession* session)
+ : QuicStream(id, session, /*is_static=*/false, WRITE_UNIDIRECTIONAL) {
+ // QBONE uses a LIFO queue to try to always make progress. An individual
+ // packet may persist for upto to 10 seconds in memory.
+ MaybeSetTtl(QuicTime::Delta::FromSeconds(10));
+}
+
+void QboneWriteOnlyStream::WritePacketToQuicStream(QuicStringPiece packet) {
+ // Streams are one way and ephemeral. This function should only be
+ // called once.
+ WriteOrBufferData(packet, /* fin= */ true, nullptr);
+}
+
+QboneReadOnlyStream::QboneReadOnlyStream(QuicStreamId id,
+ QboneSessionBase* session)
+ : QuicStream(id,
+ session,
+ /*is_static=*/false,
+ READ_UNIDIRECTIONAL),
+ session_(session) {
+ // QBONE uses a LIFO queue to try to always make progress. An individual
+ // packet may persist for upto to 10 seconds in memory.
+ MaybeSetTtl(QuicTime::Delta::FromSeconds(10));
+}
+
+QboneReadOnlyStream::~QboneReadOnlyStream() {}
+
+void QboneReadOnlyStream::OnDataAvailable() {
+ // Read in data and buffer it, attempt to frame to see if there's a packet.
+ sequencer()->Read(&buffer_);
+ if (sequencer()->IsClosed()) {
+ session_->ProcessPacketFromPeer(buffer_);
+ OnFinRead();
+ return;
+ }
+ if (buffer_.size() > QboneConstants::kMaxQbonePacketBytes) {
+ if (!rst_sent()) {
+ Reset(QUIC_BAD_APPLICATION_PAYLOAD);
+ }
+ StopReading();
+ }
+}
+
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/qbone/qbone_stream.h b/chromium/net/third_party/quiche/src/quic/qbone/qbone_stream.h
new file mode 100644
index 00000000000..73680051643
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_stream.h
@@ -0,0 +1,55 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_QBONE_QBONE_STREAM_H_
+#define QUICHE_QUIC_QBONE_QBONE_STREAM_H_
+
+#include "net/third_party/quiche/src/quic/core/quic_session.h"
+#include "net/third_party/quiche/src/quic/core/quic_stream.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
+
+namespace quic {
+
+class QboneSessionBase;
+
+// QboneWriteOnlyStream is responsible for sending data for a single
+// packet to the other side.
+// Note that the stream will be created HalfClosed (reads will be closed).
+class QUIC_EXPORT_PRIVATE QboneWriteOnlyStream : public QuicStream {
+ public:
+ QboneWriteOnlyStream(QuicStreamId id, QuicSession* session);
+
+ // QuicStream implementation. Qbone writers are ephemeral and don't
+ // read any data.
+ void OnDataAvailable() override {}
+
+ // Write a network packet over the quic stream.
+ void WritePacketToQuicStream(QuicStringPiece packet);
+};
+
+// QboneReadOnlyStream will be used if we find an incoming stream that
+// isn't fully contained. It will buffer the data when available and
+// attempt to parse it as a packet to send to the network when a FIN
+// is found.
+// Note that the stream will be created HalfClosed (writes will be closed).
+class QUIC_EXPORT_PRIVATE QboneReadOnlyStream : public QuicStream {
+ public:
+ QboneReadOnlyStream(QuicStreamId id, QboneSessionBase* session);
+
+ ~QboneReadOnlyStream() override;
+
+ // QuicStream overrides.
+ // OnDataAvailable is called when there is data in the quic stream buffer.
+ // This will copy the buffer locally and attempt to parse it to write out
+ // packets to the network.
+ void OnDataAvailable() override;
+
+ private:
+ string buffer_;
+ QboneSessionBase* session_;
+};
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_QBONE_QBONE_STREAM_H_
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
new file mode 100644
index 00000000000..1920aa55ee6
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_stream_test.cc
@@ -0,0 +1,249 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/qbone/qbone_stream.h"
+
+#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h"
+#include "net/third_party/quiche/src/quic/core/quic_session.h"
+#include "net/third_party/quiche/src/quic/core/quic_simple_buffer_allocator.h"
+#include "net/third_party/quiche/src/quic/core/quic_utils.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_test_loopback.h"
+#include "net/third_party/quiche/src/quic/qbone/qbone_constants.h"
+#include "net/third_party/quiche/src/quic/qbone/qbone_session_base.h"
+#include "net/third_party/quiche/src/quic/test_tools/mock_clock.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
+#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h"
+
+namespace quic {
+
+namespace {
+
+using ::testing::_;
+using ::testing::StrictMock;
+
+// MockQuicSession that does not create streams and writes data from
+// QuicStream to a string.
+class MockQuicSession : public QboneSessionBase {
+ public:
+ MockQuicSession(QuicConnection* connection, const QuicConfig& config)
+ : QboneSessionBase(connection,
+ nullptr /*visitor*/,
+ config,
+ CurrentSupportedVersions(),
+ nullptr /*writer*/) {}
+
+ ~MockQuicSession() override {}
+
+ // Writes outgoing data from QuicStream to a string.
+ QuicConsumedData WritevData(QuicStream* stream,
+ QuicStreamId id,
+ size_t write_length,
+ QuicStreamOffset offset,
+ StreamSendingState state) override {
+ if (!writable_) {
+ return QuicConsumedData(0, false);
+ }
+
+ return QuicConsumedData(write_length, state != StreamSendingState::NO_FIN);
+ }
+
+ QboneReadOnlyStream* CreateIncomingStream(QuicStreamId id) override {
+ return nullptr;
+ }
+
+ const QuicCryptoStream* GetCryptoStream() const override { return nullptr; }
+ QuicCryptoStream* GetMutableCryptoStream() override { return nullptr; }
+
+ // Called by QuicStream when they want to close stream.
+ MOCK_METHOD3(SendRstStream,
+ void(QuicStreamId, QuicRstStreamErrorCode, QuicStreamOffset));
+
+ // Sets whether data is written to buffer, or else if this is write blocked.
+ void set_writable(bool writable) { writable_ = writable; }
+
+ // Tracks whether the stream is write blocked and its priority.
+ void RegisterReliableStream(QuicStreamId stream_id) {
+ // The priority effectively does not matter. Put all streams on the same
+ // priority.
+ write_blocked_streams()->RegisterStream(
+ stream_id,
+ /*is_static_stream=*/false,
+ /* precedence= */ spdy::SpdyStreamPrecedence(3));
+ }
+
+ // The session take ownership of the stream.
+ void ActivateReliableStream(std::unique_ptr<QuicStream> stream) {
+ ActivateStream(std::move(stream));
+ }
+
+ std::unique_ptr<QuicCryptoStream> CreateCryptoStream() override {
+ return nullptr;
+ }
+
+ MOCK_METHOD1(ProcessPacketFromPeer, void(QuicStringPiece));
+ MOCK_METHOD1(ProcessPacketFromNetwork, void(QuicStringPiece));
+
+ private:
+ // Whether data is written to write_buffer_.
+ bool writable_ = true;
+};
+
+// Packet writer that does nothing. This is required for QuicConnection but
+// isn't used for writing data.
+class DummyPacketWriter : public QuicPacketWriter {
+ public:
+ DummyPacketWriter() {}
+
+ // QuicPacketWriter overrides.
+ WriteResult WritePacket(const char* buffer,
+ size_t buf_len,
+ const QuicIpAddress& self_address,
+ const QuicSocketAddress& peer_address,
+ PerPacketOptions* options) override {
+ return WriteResult(WRITE_STATUS_ERROR, 0);
+ }
+
+ bool IsWriteBlocked() const override { return false; };
+
+ void SetWritable() override {}
+
+ QuicByteCount GetMaxPacketSize(
+ const QuicSocketAddress& peer_address) const override {
+ return 0;
+ }
+
+ bool SupportsReleaseTime() const override { return false; }
+
+ bool IsBatchMode() const override { return false; }
+
+ char* GetNextWriteLocation(const QuicIpAddress& self_address,
+ const QuicSocketAddress& peer_address) override {
+ return nullptr;
+ }
+
+ WriteResult Flush() override { return WriteResult(WRITE_STATUS_OK, 0); }
+};
+
+class QboneReadOnlyStreamTest : public ::testing::Test,
+ public QuicConnectionHelperInterface {
+ public:
+ void CreateReliableQuicStream() {
+ // Arbitrary values for QuicConnection.
+ Perspective perspective = Perspective::IS_SERVER;
+ bool owns_writer = true;
+
+ alarm_factory_ = QuicMakeUnique<test::MockAlarmFactory>();
+
+ connection_.reset(new QuicConnection(
+ test::TestConnectionId(0), QuicSocketAddress(TestLoopback(), 0),
+ this /*QuicConnectionHelperInterface*/, alarm_factory_.get(),
+ new DummyPacketWriter(), owns_writer, perspective,
+ ParsedVersionOfIndex(CurrentSupportedVersions(), 0)));
+ clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
+ session_ = QuicMakeUnique<StrictMock<MockQuicSession>>(connection_.get(),
+ QuicConfig());
+ stream_ = new QboneReadOnlyStream(kStreamId, session_.get());
+ session_->ActivateReliableStream(
+ std::unique_ptr<QboneReadOnlyStream>(stream_));
+ }
+
+ ~QboneReadOnlyStreamTest() override {}
+
+ const QuicClock* GetClock() const override { return &clock_; }
+
+ QuicRandom* GetRandomGenerator() override {
+ return QuicRandom::GetInstance();
+ }
+
+ QuicBufferAllocator* GetStreamSendBufferAllocator() override {
+ return &buffer_allocator_;
+ }
+
+ protected:
+ // The QuicSession will take the ownership.
+ QboneReadOnlyStream* stream_;
+ std::unique_ptr<StrictMock<MockQuicSession>> session_;
+ std::unique_ptr<QuicAlarmFactory> alarm_factory_;
+ std::unique_ptr<QuicConnection> connection_;
+ // Used to implement the QuicConnectionHelperInterface.
+ SimpleBufferAllocator buffer_allocator_;
+ MockClock clock_;
+ const QuicStreamId kStreamId = QuicUtils::GetFirstUnidirectionalStreamId(
+ CurrentSupportedVersions()[0].transport_version,
+ Perspective::IS_CLIENT);
+};
+
+// Read an entire string.
+TEST_F(QboneReadOnlyStreamTest, ReadDataWhole) {
+ string packet = "Stuff";
+ CreateReliableQuicStream();
+ QuicStreamFrame frame(kStreamId, true, 0, packet);
+ EXPECT_CALL(*session_, ProcessPacketFromPeer("Stuff"));
+ stream_->OnStreamFrame(frame);
+}
+
+// Test buffering.
+TEST_F(QboneReadOnlyStreamTest, ReadBuffered) {
+ CreateReliableQuicStream();
+ string packet = "Stuf";
+ {
+ QuicStreamFrame frame(kStreamId, false, 0, packet);
+ stream_->OnStreamFrame(frame);
+ }
+ // We didn't write 5 bytes yet...
+
+ packet = "f";
+ EXPECT_CALL(*session_, ProcessPacketFromPeer("Stuff"));
+ {
+ QuicStreamFrame frame(kStreamId, true, 4, packet);
+ stream_->OnStreamFrame(frame);
+ }
+}
+
+TEST_F(QboneReadOnlyStreamTest, ReadOutOfOrder) {
+ CreateReliableQuicStream();
+ string packet = "f";
+ {
+ QuicStreamFrame frame(kStreamId, true, 4, packet);
+ stream_->OnStreamFrame(frame);
+ }
+
+ packet = "S";
+ {
+ QuicStreamFrame frame(kStreamId, false, 0, packet);
+ stream_->OnStreamFrame(frame);
+ }
+
+ packet = "tuf";
+ EXPECT_CALL(*session_, ProcessPacketFromPeer("Stuff"));
+ {
+ QuicStreamFrame frame(kStreamId, false, 1, packet);
+ stream_->OnStreamFrame(frame);
+ }
+}
+
+// Test buffering too many bytes.
+TEST_F(QboneReadOnlyStreamTest, ReadBufferedTooLarge) {
+ CreateReliableQuicStream();
+ string packet = "0123456789";
+ int iterations = (QboneConstants::kMaxQbonePacketBytes / packet.size()) + 2;
+ EXPECT_CALL(*session_,
+ SendRstStream(kStreamId, QUIC_BAD_APPLICATION_PAYLOAD, _));
+ for (int i = 0; i < iterations; ++i) {
+ QuicStreamFrame frame(kStreamId, i == (iterations - 1), i * packet.size(),
+ packet);
+ if (!stream_->reading_stopped()) {
+ stream_->OnStreamFrame(frame);
+ }
+ }
+ // We should have nothing written to the network and the stream
+ // should have stopped reading.
+ EXPECT_TRUE(stream_->reading_stopped());
+}
+
+} // namespace
+
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.cc
index 1446ab352d5..4f39271436e 100644
--- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.cc
+++ b/chromium/net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.cc
@@ -72,14 +72,6 @@ InsecureProofVerifier::CreateDefaultContext() {
return nullptr;
}
-QuicConnectionId QuartcCryptoServerStreamHelper::GenerateConnectionIdForReject(
- QuicTransportVersion /*version*/,
- QuicConnectionId /*connection_id*/) const {
- // TODO(b/124399417): Request a zero-length connection id here when the QUIC
- // server perspective supports it.
- return QuicUtils::CreateRandomConnectionId();
-}
-
bool QuartcCryptoServerStreamHelper::CanAcceptClientHello(
const CryptoHandshakeMessage& /*message*/,
const QuicSocketAddress& /*client_address*/,
diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.h b/chromium/net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.h
index 1436aeb41f0..cdf14a040eb 100644
--- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.h
+++ b/chromium/net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.h
@@ -101,10 +101,6 @@ class InsecureProofVerifier : public ProofVerifier {
// Implementation of the server-side crypto stream helper.
class QuartcCryptoServerStreamHelper : public QuicCryptoServerStream::Helper {
public:
- QuicConnectionId GenerateConnectionIdForReject(
- QuicTransportVersion version,
- QuicConnectionId connection_id) const override;
-
bool CanAcceptClientHello(const CryptoHandshakeMessage& message,
const QuicSocketAddress& client_address,
const QuicSocketAddress& peer_address,
diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_dispatcher.h b/chromium/net/third_party/quiche/src/quic/quartc/quartc_dispatcher.h
index d1128d61afe..06e799ea98a 100644
--- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_dispatcher.h
+++ b/chromium/net/third_party/quiche/src/quic/quartc/quartc_dispatcher.h
@@ -45,6 +45,9 @@ class QuartcDispatcher : public QuicDispatcher,
QuicStringPiece alpn,
const ParsedQuicVersion& version) override;
+ // TODO(b/124399417): Override GenerateNewServerConnectionId and request a
+ // zero-length connection id when the QUIC server perspective supports it.
+
// QuartcPacketTransport::Delegate overrides.
void OnTransportCanWrite() override;
void OnTransportReceived(const char* data, size_t data_len) override;
diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_factory.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_factory.cc
index 0c11bd0d85f..6742b895b33 100644
--- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_factory.cc
+++ b/chromium/net/third_party/quiche/src/quic/quartc/quartc_factory.cc
@@ -8,6 +8,7 @@
#include "net/third_party/quiche/src/quic/core/quic_utils.h"
#include "net/third_party/quiche/src/quic/core/tls_client_handshaker.h"
#include "net/third_party/quiche/src/quic/core/tls_server_handshaker.h"
+#include "net/third_party/quiche/src/quic/core/uber_received_packet_manager.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
#include "net/third_party/quiche/src/quic/quartc/quartc_connection_helper.h"
@@ -43,6 +44,13 @@ std::unique_ptr<QuartcSession> CreateQuartcClientSession(
dummy_id, dummy_address, connection_helper, alarm_factory, writer.get(),
Perspective::IS_CLIENT, supported_versions);
+ // Quartc sets its own ack delay; get that ack delay and copy it over
+ // to the QuicConfig so that it can be properly advertised to the peer
+ // via transport parameter negotiation.
+ quic_config.SetMaxAckDelayToSendMs(quic_connection->received_packet_manager()
+ .max_ack_delay()
+ .ToMilliseconds());
+
return QuicMakeUnique<QuartcClientSession>(
std::move(quic_connection), quic_config, supported_versions, clock,
std::move(writer),
@@ -195,6 +203,8 @@ std::unique_ptr<QuicConnection> CreateQuicConnection(
QuicSentPacketManager& sent_packet_manager =
quic_connection->sent_packet_manager();
+ UberReceivedPacketManager& received_packet_manager =
+ quic_connection->received_packet_manager();
// Default delayed ack time is 25ms.
// If data packets are sent less often (e.g. because p-time was modified),
@@ -206,7 +216,7 @@ std::unique_ptr<QuicConnection> CreateQuicConnection(
// The p-time can go up to as high as 120ms, and when it does, it's
// when the low overhead is the most important thing. Ideally it should be
// above 120ms, but it cannot be higher than 0.5*RTO, which equals to 100ms.
- sent_packet_manager.set_local_max_ack_delay(
+ received_packet_manager.set_max_ack_delay(
QuicTime::Delta::FromMilliseconds(100));
sent_packet_manager.set_peer_max_ack_delay(
QuicTime::Delta::FromMilliseconds(100));
diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_multiplexer.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_multiplexer.cc
new file mode 100644
index 00000000000..001e2198d16
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/quartc/quartc_multiplexer.cc
@@ -0,0 +1,269 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/quartc/quartc_multiplexer.h"
+
+#include <cstdint>
+
+#include "net/third_party/quiche/src/quic/core/quic_data_writer.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_mem_slice.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_mem_slice_span.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
+
+namespace quic {
+
+QuartcSendChannel::QuartcSendChannel(QuartcMultiplexer* multiplexer,
+ uint64_t id,
+ QuicBufferAllocator* allocator,
+ Delegate* delegate)
+ : multiplexer_(multiplexer),
+ id_(id),
+ encoded_length_(QuicDataWriter::GetVarInt62Len(id_)),
+ allocator_(allocator),
+ delegate_(delegate) {}
+
+QuartcStream* QuartcSendChannel::CreateOutgoingBidirectionalStream() {
+ if (!session_) {
+ QUIC_LOG(DFATAL) << "Session is not ready to write yet; channel_id=" << id_;
+ return nullptr;
+ }
+ QuicMemSlice id_slice = EncodeChannelId();
+
+ QuartcStream* stream = session_->CreateOutgoingBidirectionalStream();
+ QuicConsumedData consumed =
+ stream->WriteMemSlices(QuicMemSliceSpan(&id_slice), /*fin=*/false);
+ DCHECK_EQ(consumed.bytes_consumed, encoded_length_);
+ return stream;
+}
+
+bool QuartcSendChannel::SendOrQueueMessage(QuicMemSliceSpan message,
+ int64_t datagram_id) {
+ if (!session_) {
+ QUIC_LOG(DFATAL) << "Session is not ready to write yet; channel_id=" << id_
+ << "datagram size=" << message.total_length();
+ return false;
+ }
+ QuicMemSliceStorage storage(nullptr, 0, nullptr, 0); // Empty storage.
+ storage.Append(EncodeChannelId());
+
+ message.ConsumeAll(
+ [&storage](QuicMemSlice slice) { storage.Append(std::move(slice)); });
+
+ // Allocate a unique datagram id so that notifications can be routed back to
+ // the right send channel.
+ int64_t unique_datagram_id = multiplexer_->AllocateDatagramId(this);
+ multiplexer_to_user_datagram_ids_[unique_datagram_id] = datagram_id;
+
+ return session_->SendOrQueueMessage(storage.ToSpan(), unique_datagram_id);
+}
+
+void QuartcSendChannel::OnMessageSent(int64_t datagram_id) {
+ // Map back to the caller-chosen |datagram_id|.
+ datagram_id = multiplexer_to_user_datagram_ids_[datagram_id];
+ delegate_->OnMessageSent(datagram_id);
+}
+
+void QuartcSendChannel::OnMessageAcked(int64_t datagram_id,
+ QuicTime receive_timestamp) {
+ // Map back to the caller-chosen |datagram_id|.
+ auto it = multiplexer_to_user_datagram_ids_.find(datagram_id);
+ if (it == multiplexer_to_user_datagram_ids_.end()) {
+ QUIC_LOG(DFATAL) << "Datagram acked/lost multiple times; datagram_id="
+ << datagram_id;
+ return;
+ }
+ delegate_->OnMessageAcked(it->second, receive_timestamp);
+ multiplexer_to_user_datagram_ids_.erase(it);
+}
+
+void QuartcSendChannel::OnMessageLost(int64_t datagram_id) {
+ // Map back to the caller-chosen |datagram_id|.
+ auto it = multiplexer_to_user_datagram_ids_.find(datagram_id);
+ if (it == multiplexer_to_user_datagram_ids_.end()) {
+ QUIC_LOG(DFATAL) << "Datagram acked/lost multiple times; datagram_id="
+ << datagram_id;
+ return;
+ }
+ delegate_->OnMessageLost(it->second);
+ multiplexer_to_user_datagram_ids_.erase(it);
+}
+
+void QuartcSendChannel::OnSessionCreated(QuartcSession* session) {
+ session_ = session;
+}
+
+QuicMemSlice QuartcSendChannel::EncodeChannelId() {
+ QuicMemSlice id_slice(allocator_, encoded_length_);
+ QuicDataWriter writer(encoded_length_, const_cast<char*>(id_slice.data()));
+ writer.WriteVarInt62(id_);
+ return id_slice;
+}
+
+QuartcMultiplexer::QuartcMultiplexer(
+ QuicBufferAllocator* allocator,
+ QuartcSessionEventDelegate* session_delegate,
+ QuartcReceiveChannel* default_receive_channel)
+ : allocator_(allocator),
+ session_delegate_(session_delegate),
+ default_receive_channel_(default_receive_channel) {
+ CHECK_NE(session_delegate_, nullptr);
+ CHECK_NE(default_receive_channel_, nullptr);
+}
+
+QuartcSendChannel* QuartcMultiplexer::CreateSendChannel(
+ uint64_t channel_id,
+ QuartcSendChannel::Delegate* delegate) {
+ send_channels_.push_back(QuicMakeUnique<QuartcSendChannel>(
+ this, channel_id, allocator_, delegate));
+ if (session_) {
+ send_channels_.back()->OnSessionCreated(session_);
+ }
+ return send_channels_.back().get();
+}
+
+void QuartcMultiplexer::RegisterReceiveChannel(uint64_t channel_id,
+ QuartcReceiveChannel* channel) {
+ if (channel == nullptr) {
+ receive_channels_.erase(channel_id);
+ return;
+ }
+ auto& registered_channel = receive_channels_[channel_id];
+ if (registered_channel) {
+ QUIC_LOG(DFATAL) << "Attempted to overwrite existing channel_id="
+ << channel_id;
+ return;
+ }
+ registered_channel = channel;
+}
+
+int64_t QuartcMultiplexer::AllocateDatagramId(QuartcSendChannel* channel) {
+ send_channels_by_datagram_id_[next_datagram_id_] = channel;
+ return next_datagram_id_++;
+}
+
+void QuartcMultiplexer::OnSessionCreated(QuartcSession* session) {
+ for (auto& channel : send_channels_) {
+ channel->OnSessionCreated(session);
+ }
+ session_ = session;
+ session_delegate_->OnSessionCreated(session);
+}
+
+void QuartcMultiplexer::OnCryptoHandshakeComplete() {
+ session_delegate_->OnCryptoHandshakeComplete();
+}
+
+void QuartcMultiplexer::OnConnectionWritable() {
+ session_delegate_->OnConnectionWritable();
+}
+
+void QuartcMultiplexer::OnIncomingStream(QuartcStream* stream) {
+ stream->SetDelegate(this);
+}
+
+void QuartcMultiplexer::OnCongestionControlChange(
+ QuicBandwidth bandwidth_estimate,
+ QuicBandwidth pacing_rate,
+ QuicTime::Delta latest_rtt) {
+ session_delegate_->OnCongestionControlChange(bandwidth_estimate, pacing_rate,
+ latest_rtt);
+}
+
+void QuartcMultiplexer::OnConnectionClosed(
+ const QuicConnectionCloseFrame& frame,
+ ConnectionCloseSource source) {
+ session_delegate_->OnConnectionClosed(frame, source);
+}
+
+void QuartcMultiplexer::OnMessageReceived(QuicStringPiece message) {
+ QuicDataReader reader(message);
+ QuicVariableLengthIntegerLength channel_id_length =
+ reader.PeekVarInt62Length();
+
+ uint64_t channel_id;
+ if (!reader.ReadVarInt62(&channel_id)) {
+ QUIC_LOG(DFATAL) << "Received message without properly encoded channel id";
+ return;
+ }
+
+ QuartcReceiveChannel* channel = default_receive_channel_;
+ auto it = receive_channels_.find(channel_id);
+ if (it != receive_channels_.end()) {
+ channel = it->second;
+ }
+
+ channel->OnMessageReceived(channel_id, message.substr(channel_id_length));
+}
+
+void QuartcMultiplexer::OnMessageSent(int64_t datagram_id) {
+ auto it = send_channels_by_datagram_id_.find(datagram_id);
+ if (it == send_channels_by_datagram_id_.end()) {
+ return;
+ }
+ it->second->OnMessageSent(datagram_id);
+}
+
+void QuartcMultiplexer::OnMessageAcked(int64_t datagram_id,
+ QuicTime receive_timestamp) {
+ auto it = send_channels_by_datagram_id_.find(datagram_id);
+ if (it == send_channels_by_datagram_id_.end()) {
+ return;
+ }
+ it->second->OnMessageAcked(datagram_id, receive_timestamp);
+ send_channels_by_datagram_id_.erase(it);
+}
+
+void QuartcMultiplexer::OnMessageLost(int64_t datagram_id) {
+ auto it = send_channels_by_datagram_id_.find(datagram_id);
+ if (it == send_channels_by_datagram_id_.end()) {
+ return;
+ }
+ it->second->OnMessageLost(datagram_id);
+ send_channels_by_datagram_id_.erase(it);
+}
+
+size_t QuartcMultiplexer::OnReceived(QuartcStream* stream,
+ iovec* iov,
+ size_t iov_length,
+ bool /*fin*/) {
+ if (iov == nullptr || iov_length <= 0) {
+ return 0;
+ }
+
+ QuicDataReader reader(static_cast<char*>(iov[0].iov_base), iov[0].iov_len);
+ QuicVariableLengthIntegerLength channel_id_length =
+ reader.PeekVarInt62Length();
+
+ uint64_t channel_id;
+ if (reader.BytesRemaining() >= channel_id_length) {
+ // Fast path, have enough data to read immediately.
+ if (!reader.ReadVarInt62(&channel_id)) {
+ return 0;
+ }
+ } else {
+ // Slow path, need to coalesce multiple iovecs.
+ std::string data;
+ for (size_t i = 0; i < iov_length; ++i) {
+ data += std::string(static_cast<char*>(iov[i].iov_base), iov[i].iov_len);
+ }
+ QuicDataReader combined_reader(data);
+ if (!combined_reader.ReadVarInt62(&channel_id)) {
+ return 0;
+ }
+ }
+
+ QuartcReceiveChannel* channel = default_receive_channel_;
+ auto it = receive_channels_.find(channel_id);
+ if (it != receive_channels_.end()) {
+ channel = it->second;
+ }
+ channel->OnIncomingStream(channel_id, stream);
+ return channel_id_length;
+}
+
+void QuartcMultiplexer::OnClose(QuartcStream* /*stream*/) {}
+
+void QuartcMultiplexer::OnBufferChanged(QuartcStream* /*stream*/) {}
+
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_multiplexer.h b/chromium/net/third_party/quiche/src/quic/quartc/quartc_multiplexer.h
new file mode 100644
index 00000000000..9cb581d47b7
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/quartc/quartc_multiplexer.h
@@ -0,0 +1,190 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_QUARTC_QUARTC_MULTIPLEXER_H_
+#define QUICHE_QUIC_QUARTC_QUARTC_MULTIPLEXER_H_
+
+#include <cstdint>
+
+#include "net/third_party/quiche/src/quic/core/quic_time.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_mem_slice_span.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
+#include "net/third_party/quiche/src/quic/quartc/quartc_endpoint.h"
+#include "net/third_party/quiche/src/quic/quartc/quartc_session.h"
+#include "net/third_party/quiche/src/quic/quartc/quartc_stream.h"
+
+namespace quic {
+
+class QuartcMultiplexer;
+
+// A single, multiplexed send channel within a Quartc session. A send channel
+// wraps send-side operations with an outgoing multiplex id.
+class QuartcSendChannel {
+ public:
+ class Delegate {
+ public:
+ virtual ~Delegate() = default;
+
+ // Called when a message with |datagram_id| is sent by this channel.
+ virtual void OnMessageSent(int64_t datagram_id) = 0;
+
+ // Called when a message sent on this channel with |datagram_id| is acked.
+ // |receive_timestamp| indicates when the peer received this message,
+ // according to the peer's clock.
+ virtual void OnMessageAcked(int64_t datagram_id,
+ QuicTime receive_timestamp) = 0;
+
+ // Called when a message sent on this channel with |datagram_id| is lost.
+ virtual void OnMessageLost(int64_t datagram_id) = 0;
+ };
+
+ QuartcSendChannel(QuartcMultiplexer* multiplexer,
+ uint64_t id,
+ QuicBufferAllocator* allocator,
+ Delegate* delegate);
+ virtual ~QuartcSendChannel() = default;
+
+ // Creates a new, outgoing stream on this channel.
+ //
+ // Automatically writes the channel id to the start of the stream. The caller
+ // SHOULD create a |ScopedPacketFlusher| before calling this function to
+ // prevent the channel id from being sent by itself.
+ QuartcStream* CreateOutgoingBidirectionalStream();
+
+ // Writes |message| to the session. Prepends the channel's send id before any
+ // following message data.
+ bool SendOrQueueMessage(QuicMemSliceSpan message, int64_t datagram_id);
+
+ // Gets the current largest message payload for this channel. Returns the
+ // largest payload size supported by the session minus overhead required to
+ // encode this channel's send id.
+ QuicPacketLength GetCurrentLargestMessagePayload() const;
+
+ // The following are called by the multiplexer to deliver message
+ // notifications. The |datagram_id| passed to these is unique per-message,
+ // and must be translated back to the sender's chosen datagram_id.
+ void OnMessageSent(int64_t datagram_id);
+ void OnMessageAcked(int64_t datagram_id, QuicTime receive_timestamp);
+ void OnMessageLost(int64_t datagram_id);
+ void OnSessionCreated(QuartcSession* session);
+
+ private:
+ // Creates a mem slice containing a varint-62 encoded channel id.
+ QuicMemSlice EncodeChannelId();
+
+ QuartcMultiplexer* const multiplexer_;
+ const uint64_t id_;
+ const QuicVariableLengthIntegerLength encoded_length_;
+ QuicBufferAllocator* const allocator_;
+ Delegate* const delegate_;
+
+ QuartcSession* session_;
+
+ // Map of multiplexer-chosen to user/caller-specified datagram ids. The user
+ // may specify any number as a datagram's id. This number does not have to be
+ // unique across channels (nor even within a single channel). In order
+ // to demux sent, acked, and lost messages, the multiplexer assigns a globally
+ // unique id to each message. This map is used to restore the original caller
+ // datagram id before issuing callbacks.
+ QuicUnorderedMap<int64_t, int64_t> multiplexer_to_user_datagram_ids_;
+};
+
+// A single, multiplexed receive channel within a Quartc session. A receive
+// channel is a delegate which accepts incoming streams and datagrams on one (or
+// more) channel ids.
+class QuartcReceiveChannel {
+ public:
+ virtual ~QuartcReceiveChannel() = default;
+
+ // Called when a new incoming stream arrives on this channel.
+ virtual void OnIncomingStream(uint64_t channel_id, QuartcStream* stream) = 0;
+
+ // Called when a message is recieved by this channel.
+ virtual void OnMessageReceived(uint64_t channel_id,
+ QuicStringPiece message) = 0;
+};
+
+// Delegate for session-wide events.
+class QuartcSessionEventDelegate {
+ public:
+ virtual ~QuartcSessionEventDelegate() = default;
+
+ virtual void OnSessionCreated(QuartcSession* session) = 0;
+ virtual void OnCryptoHandshakeComplete() = 0;
+ virtual void OnConnectionWritable() = 0;
+ virtual void OnCongestionControlChange(QuicBandwidth bandwidth_estimate,
+ QuicBandwidth pacing_rate,
+ QuicTime::Delta latest_rtt) = 0;
+ virtual void OnConnectionClosed(const QuicConnectionCloseFrame& frame,
+ ConnectionCloseSource source) = 0;
+};
+
+// A multiplexer capable of sending and receiving data on multiple channels.
+class QuartcMultiplexer : public QuartcEndpoint::Delegate,
+ public QuartcStream::Delegate {
+ public:
+ // Creates a new multiplexer. |session_delegate| handles all session-wide
+ // events, while |default_receive_channel| handles incoming data on unknown
+ // or unregistered channel ids. Neither |session_delegate| nor
+ // |default_receive_channel| may be nullptr, and both must outlive the
+ // multiplexer.
+ QuartcMultiplexer(QuicBufferAllocator* allocator,
+ QuartcSessionEventDelegate* session_delegate,
+ QuartcReceiveChannel* default_receive_channel);
+
+ // Creates a new send channel. The channel is owned by the multiplexer, and
+ // references to it must not outlive the multiplexer.
+ QuartcSendChannel* CreateSendChannel(uint64_t channel_id,
+ QuartcSendChannel::Delegate* delegate);
+
+ // Registers a receiver for incoming data on |channel_id|.
+ void RegisterReceiveChannel(uint64_t channel_id,
+ QuartcReceiveChannel* channel);
+
+ // Allocates a datagram id to |channel|.
+ int64_t AllocateDatagramId(QuartcSendChannel* channel);
+
+ // QuartcEndpoint::Delegate overrides.
+ void OnSessionCreated(QuartcSession* session) override;
+
+ // QuartcSession::Delegate overrides.
+ void OnCryptoHandshakeComplete() override;
+ void OnConnectionWritable() override;
+ void OnIncomingStream(QuartcStream* stream) override;
+ void OnCongestionControlChange(QuicBandwidth bandwidth_estimate,
+ QuicBandwidth pacing_rate,
+ QuicTime::Delta latest_rtt) override;
+ void OnConnectionClosed(const QuicConnectionCloseFrame& frame,
+ ConnectionCloseSource source) override;
+ void OnMessageReceived(QuicStringPiece message) override;
+ void OnMessageSent(int64_t datagram_id) override;
+ void OnMessageAcked(int64_t datagram_id, QuicTime receive_timestamp) override;
+ void OnMessageLost(int64_t datagram_id) override;
+
+ // QuartcStream::Delegate overrides.
+ size_t OnReceived(QuartcStream* stream,
+ iovec* iov,
+ size_t iov_length,
+ bool fin) override;
+ void OnClose(QuartcStream* stream) override;
+ void OnBufferChanged(QuartcStream* stream) override;
+
+ private:
+ QuicBufferAllocator* const allocator_;
+ QuartcSessionEventDelegate* const session_delegate_;
+
+ QuartcSession* session_ = nullptr;
+ std::vector<std::unique_ptr<QuartcSendChannel>> send_channels_;
+ QuicUnorderedMap<uint64_t, QuartcReceiveChannel*> receive_channels_;
+ QuartcReceiveChannel* default_receive_channel_ = nullptr;
+
+ int64_t next_datagram_id_ = 1;
+ QuicUnorderedMap<int64_t, QuartcSendChannel*> send_channels_by_datagram_id_;
+};
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_QUARTC_QUARTC_MULTIPLEXER_H_
diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_multiplexer_test.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_multiplexer_test.cc
new file mode 100644
index 00000000000..64609cbc56e
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/quartc/quartc_multiplexer_test.cc
@@ -0,0 +1,490 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/quartc/quartc_multiplexer.h"
+
+#include <memory>
+
+#include "net/third_party/quiche/src/quic/core/frames/quic_connection_close_frame.h"
+#include "net/third_party/quiche/src/quic/core/quic_bandwidth.h"
+#include "net/third_party/quiche/src/quic/core/quic_buffer_allocator.h"
+#include "net/third_party/quiche/src/quic/core/quic_time.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_test_mem_slice_vector.h"
+#include "net/third_party/quiche/src/quic/quartc/counting_packet_filter.h"
+#include "net/third_party/quiche/src/quic/quartc/quartc_endpoint.h"
+#include "net/third_party/quiche/src/quic/quartc/quartc_fakes.h"
+#include "net/third_party/quiche/src/quic/quartc/quartc_session.h"
+#include "net/third_party/quiche/src/quic/quartc/quartc_stream.h"
+#include "net/third_party/quiche/src/quic/quartc/simulated_packet_transport.h"
+#include "net/third_party/quiche/src/quic/test_tools/simulator/link.h"
+#include "net/third_party/quiche/src/quic/test_tools/simulator/simulator.h"
+
+namespace quic {
+namespace {
+
+using ::testing::ElementsAreArray;
+using ::testing::Gt;
+using ::testing::IsEmpty;
+using ::testing::Pair;
+
+constexpr QuicTime::Delta kPropagationDelay =
+ QuicTime::Delta::FromMilliseconds(10);
+
+class FakeSessionEventDelegate : public QuartcSessionEventDelegate {
+ public:
+ void OnSessionCreated(QuartcSession* session) override {
+ session->StartCryptoHandshake();
+ session_ = session;
+ }
+
+ void OnConnectionWritable() override { ++writable_count_; }
+
+ void OnCryptoHandshakeComplete() override { ++handshake_count_; }
+
+ void OnConnectionClosed(const QuicConnectionCloseFrame& frame,
+ ConnectionCloseSource source) override {
+ error_ = frame.quic_error_code;
+ close_source_ = source;
+ }
+
+ void OnCongestionControlChange(QuicBandwidth bandwidth_estimate,
+ QuicBandwidth pacing_rate,
+ QuicTime::Delta latest_rtt) override {
+ latest_bandwidth_estimate_ = bandwidth_estimate;
+ latest_pacing_rate_ = pacing_rate;
+ latest_rtt_ = latest_rtt;
+ }
+
+ QuartcSession* session() { return session_; }
+ int writable_count() const { return writable_count_; }
+ int handshake_count() const { return handshake_count_; }
+ QuicErrorCode error() const { return error_; }
+ ConnectionCloseSource close_source() const { return close_source_; }
+ QuicBandwidth latest_bandwidth_estimate() const {
+ return latest_bandwidth_estimate_;
+ }
+ QuicBandwidth latest_pacing_rate() const { return latest_pacing_rate_; }
+ QuicTime::Delta latest_rtt() const { return latest_rtt_; }
+
+ private:
+ QuartcSession* session_ = nullptr;
+ int writable_count_ = 0;
+ int handshake_count_ = 0;
+ QuicErrorCode error_ = QUIC_NO_ERROR;
+ ConnectionCloseSource close_source_;
+ QuicBandwidth latest_bandwidth_estimate_ = QuicBandwidth::Zero();
+ QuicBandwidth latest_pacing_rate_ = QuicBandwidth::Zero();
+ QuicTime::Delta latest_rtt_ = QuicTime::Delta::Zero();
+};
+
+class FakeSendDelegate : public QuartcSendChannel::Delegate {
+ public:
+ void OnMessageSent(int64_t datagram_id) override {
+ datagrams_sent_.push_back(datagram_id);
+ }
+
+ void OnMessageAcked(int64_t datagram_id,
+ QuicTime receive_timestamp) override {
+ datagrams_acked_.push_back({datagram_id, receive_timestamp});
+ }
+
+ void OnMessageLost(int64_t datagram_id) override {
+ datagrams_lost_.push_back(datagram_id);
+ }
+
+ const std::vector<int64_t>& datagrams_sent() const { return datagrams_sent_; }
+ const std::vector<std::pair<int64_t, QuicTime>>& datagrams_acked() const {
+ return datagrams_acked_;
+ }
+ const std::vector<int64_t>& datagrams_lost() const { return datagrams_lost_; }
+
+ private:
+ std::vector<int64_t> datagrams_sent_;
+ std::vector<std::pair<int64_t, QuicTime>> datagrams_acked_;
+ std::vector<int64_t> datagrams_lost_;
+};
+
+class FakeReceiveDelegate : public QuartcReceiveChannel,
+ public QuartcStream::Delegate {
+ public:
+ const std::vector<std::pair<uint64_t, std::string>> messages_received()
+ const {
+ return messages_received_;
+ }
+
+ void OnIncomingStream(uint64_t channel_id, QuartcStream* stream) override {
+ stream->SetDelegate(this);
+ stream_to_channel_id_[stream] = channel_id;
+ }
+
+ void OnMessageReceived(uint64_t channel_id,
+ QuicStringPiece message) override {
+ messages_received_.emplace_back(channel_id, message);
+ }
+
+ // Stream delegate overrides.
+ size_t OnReceived(QuartcStream* stream,
+ iovec* iov,
+ size_t iov_length,
+ bool fin) override {
+ if (!fin) {
+ return 0;
+ }
+
+ size_t bytes = 0;
+ std::string message;
+ for (size_t i = 0; i < iov_length; ++i) {
+ message +=
+ std::string(static_cast<char*>(iov[i].iov_base), iov[i].iov_len);
+ bytes += iov[i].iov_len;
+ }
+ QUIC_LOG(INFO) << "Received " << bytes << " byte message on channel "
+ << stream_to_channel_id_[stream];
+ messages_received_.emplace_back(stream_to_channel_id_[stream], message);
+ return bytes;
+ }
+
+ void OnClose(QuartcStream* stream) override {
+ stream_to_channel_id_.erase(stream);
+ }
+
+ void OnBufferChanged(QuartcStream* /*stream*/) override {}
+
+ private:
+ std::vector<std::pair<uint64_t, std::string>> messages_received_;
+ QuicUnorderedMap<QuartcStream*, uint64_t> stream_to_channel_id_;
+};
+
+class QuartcMultiplexerTest : public QuicTest {
+ public:
+ QuartcMultiplexerTest()
+ : simulator_(),
+ client_transport_(&simulator_,
+ "client_transport",
+ "server_transport",
+ 10 * kDefaultMaxPacketSize),
+ server_transport_(&simulator_,
+ "server_transport",
+ "client_transport",
+ 10 * kDefaultMaxPacketSize),
+ client_filter_(&simulator_, "client_filter", &client_transport_),
+ client_server_link_(&client_filter_,
+ &server_transport_,
+ QuicBandwidth::FromKBitsPerSecond(10 * 1000),
+ kPropagationDelay),
+ client_multiplexer_(simulator_.GetStreamSendBufferAllocator(),
+ &client_session_delegate_,
+ &client_default_receiver_),
+ server_multiplexer_(simulator_.GetStreamSendBufferAllocator(),
+ &server_session_delegate_,
+ &server_default_receiver_),
+ client_endpoint_(QuicMakeUnique<QuartcClientEndpoint>(
+ simulator_.GetAlarmFactory(),
+ simulator_.GetClock(),
+ simulator_.GetRandomGenerator(),
+ &client_multiplexer_,
+ quic::QuartcSessionConfig(),
+ /*serialized_server_config=*/"")),
+ server_endpoint_(QuicMakeUnique<QuartcServerEndpoint>(
+ simulator_.GetAlarmFactory(),
+ simulator_.GetClock(),
+ simulator_.GetRandomGenerator(),
+ &server_multiplexer_,
+ quic::QuartcSessionConfig())) {
+ // TODO(b/134175506): Remove when IETF QUIC supports receive timestamps.
+ SetQuicReloadableFlag(quic_enable_version_99, false);
+ }
+
+ void Connect() {
+ client_endpoint_->Connect(&client_transport_);
+ server_endpoint_->Connect(&server_transport_);
+ ASSERT_TRUE(simulator_.RunUntil([this]() {
+ return client_session_delegate_.writable_count() > 0 &&
+ server_session_delegate_.writable_count() > 0;
+ }));
+ }
+
+ void Disconnect() {
+ client_session_delegate_.session()->CloseConnection("test");
+ server_session_delegate_.session()->CloseConnection("test");
+ }
+
+ protected:
+ QuartcMultiplexer* client_multiplexer() { return &client_multiplexer_; }
+
+ QuartcMultiplexer* server_multiplexer() { return &server_multiplexer_; }
+
+ simulator::Simulator simulator_;
+
+ simulator::SimulatedQuartcPacketTransport client_transport_;
+ simulator::SimulatedQuartcPacketTransport server_transport_;
+ simulator::CountingPacketFilter client_filter_;
+ simulator::SymmetricLink client_server_link_;
+
+ FakeSessionEventDelegate client_session_delegate_;
+ FakeSessionEventDelegate server_session_delegate_;
+
+ FakeReceiveDelegate client_default_receiver_;
+ FakeReceiveDelegate server_default_receiver_;
+
+ QuartcMultiplexer client_multiplexer_;
+ QuartcMultiplexer server_multiplexer_;
+
+ std::unique_ptr<QuartcClientEndpoint> client_endpoint_;
+ std::unique_ptr<QuartcServerEndpoint> server_endpoint_;
+};
+
+TEST_F(QuartcMultiplexerTest, MultiplexMessages) {
+ Connect();
+
+ FakeSendDelegate send_delegate_1;
+ QuartcSendChannel* send_channel_1 =
+ client_multiplexer()->CreateSendChannel(1, &send_delegate_1);
+ FakeSendDelegate send_delegate_2;
+ QuartcSendChannel* send_channel_2 =
+ client_multiplexer()->CreateSendChannel(2, &send_delegate_2);
+
+ FakeReceiveDelegate receive_delegate_1;
+ server_multiplexer()->RegisterReceiveChannel(1, &receive_delegate_1);
+
+ int num_messages = 10;
+ std::vector<std::pair<uint64_t, std::string>> messages_1;
+ messages_1.reserve(num_messages);
+ std::vector<std::pair<uint64_t, std::string>> messages_2;
+ messages_2.reserve(num_messages);
+ std::vector<int64_t> messages_sent_1;
+ std::vector<int64_t> messages_sent_2;
+ std::vector<testing::Matcher<std::pair<int64_t, QuicTime>>> ack_matchers_1;
+ std::vector<testing::Matcher<std::pair<int64_t, QuicTime>>> ack_matchers_2;
+ for (int i = 0; i < num_messages; ++i) {
+ messages_1.emplace_back(1, QuicStrCat("message for 1: ", i));
+ test::QuicTestMemSliceVector slice_1(
+ {std::make_pair(const_cast<char*>(messages_1.back().second.data()),
+ messages_1.back().second.size())});
+ send_channel_1->SendOrQueueMessage(slice_1.span(), i);
+ messages_sent_1.push_back(i);
+ ack_matchers_1.push_back(Pair(i, Gt(QuicTime::Zero())));
+
+ messages_2.emplace_back(2, QuicStrCat("message for 2: ", i));
+ test::QuicTestMemSliceVector slice_2(
+ {std::make_pair(const_cast<char*>(messages_2.back().second.data()),
+ messages_2.back().second.size())});
+ // Use i + 5 as the datagram id for channel 2, so that some of the ids
+ // overlap and some are disjoint.
+ send_channel_2->SendOrQueueMessage(slice_2.span(), i + 5);
+ messages_sent_2.push_back(i + 5);
+ ack_matchers_2.push_back(Pair(i + 5, Gt(QuicTime::Zero())));
+ }
+
+ EXPECT_TRUE(simulator_.RunUntil([&send_delegate_1, &send_delegate_2]() {
+ return send_delegate_1.datagrams_acked().size() == 10 &&
+ send_delegate_2.datagrams_acked().size() == 10;
+ }));
+
+ EXPECT_EQ(send_delegate_1.datagrams_sent(), messages_sent_1);
+ EXPECT_EQ(send_delegate_2.datagrams_sent(), messages_sent_2);
+
+ EXPECT_EQ(receive_delegate_1.messages_received(), messages_1);
+ EXPECT_EQ(server_default_receiver_.messages_received(), messages_2);
+
+ EXPECT_THAT(send_delegate_1.datagrams_acked(),
+ ElementsAreArray(ack_matchers_1));
+ EXPECT_THAT(send_delegate_2.datagrams_acked(),
+ ElementsAreArray(ack_matchers_2));
+}
+
+TEST_F(QuartcMultiplexerTest, MultiplexStreams) {
+ FakeSendDelegate send_delegate_1;
+ QuartcSendChannel* send_channel_1 =
+ client_multiplexer()->CreateSendChannel(1, &send_delegate_1);
+ FakeSendDelegate send_delegate_2;
+ QuartcSendChannel* send_channel_2 =
+ client_multiplexer()->CreateSendChannel(2, &send_delegate_2);
+
+ FakeQuartcStreamDelegate fake_send_stream_delegate;
+
+ FakeReceiveDelegate receive_delegate_1;
+ server_multiplexer()->RegisterReceiveChannel(1, &receive_delegate_1);
+
+ Connect();
+
+ int num_messages = 10;
+ std::vector<std::pair<uint64_t, std::string>> messages_1;
+ messages_1.reserve(num_messages);
+ std::vector<std::pair<uint64_t, std::string>> messages_2;
+ messages_2.reserve(num_messages);
+ for (int i = 0; i < num_messages; ++i) {
+ messages_1.emplace_back(1, QuicStrCat("message for 1: ", i));
+ test::QuicTestMemSliceVector slice_1(
+ {std::make_pair(const_cast<char*>(messages_1.back().second.data()),
+ messages_1.back().second.size())});
+ QuartcStream* stream_1 =
+ send_channel_1->CreateOutgoingBidirectionalStream();
+ stream_1->SetDelegate(&fake_send_stream_delegate);
+ stream_1->WriteMemSlices(slice_1.span(), /*fin=*/true);
+
+ messages_2.emplace_back(2, QuicStrCat("message for 2: ", i));
+ test::QuicTestMemSliceVector slice_2(
+ {std::make_pair(const_cast<char*>(messages_2.back().second.data()),
+ messages_2.back().second.size())});
+ QuartcStream* stream_2 =
+ send_channel_2->CreateOutgoingBidirectionalStream();
+ stream_2->SetDelegate(&fake_send_stream_delegate);
+ stream_2->WriteMemSlices(slice_2.span(), /*fin=*/true);
+ }
+
+ EXPECT_TRUE(simulator_.RunUntilOrTimeout(
+ [this, &receive_delegate_1]() {
+ return receive_delegate_1.messages_received().size() == 10 &&
+ server_default_receiver_.messages_received().size() == 10;
+ },
+ QuicTime::Delta::FromSeconds(5)));
+
+ EXPECT_EQ(receive_delegate_1.messages_received(), messages_1);
+ EXPECT_EQ(server_default_receiver_.messages_received(), messages_2);
+}
+
+// Tests that datagram-lost callbacks are invoked on the right send channel
+// delegate, and that they work with overlapping datagram ids.
+TEST_F(QuartcMultiplexerTest, MultiplexLostDatagrams) {
+ Connect();
+ ASSERT_TRUE(simulator_.RunUntil([this]() {
+ return client_session_delegate_.handshake_count() > 0 &&
+ server_session_delegate_.handshake_count() > 0;
+ }));
+
+ // Just drop everything we try to send.
+ client_filter_.set_packets_to_drop(30);
+
+ FakeSendDelegate send_delegate_1;
+ QuartcSendChannel* send_channel_1 =
+ client_multiplexer()->CreateSendChannel(1, &send_delegate_1);
+ FakeSendDelegate send_delegate_2;
+ QuartcSendChannel* send_channel_2 =
+ client_multiplexer()->CreateSendChannel(2, &send_delegate_2);
+
+ FakeQuartcStreamDelegate fake_send_stream_delegate;
+
+ FakeReceiveDelegate receive_delegate_1;
+ server_multiplexer()->RegisterReceiveChannel(1, &receive_delegate_1);
+
+ int num_messages = 10;
+ std::vector<std::pair<uint64_t, std::string>> messages_1;
+ messages_1.reserve(num_messages);
+ std::vector<std::pair<uint64_t, std::string>> messages_2;
+ messages_2.reserve(num_messages);
+ std::vector<int64_t> messages_sent_1;
+ std::vector<int64_t> messages_sent_2;
+ for (int i = 0; i < num_messages; ++i) {
+ messages_1.emplace_back(1, QuicStrCat("message for 1: ", i));
+ test::QuicTestMemSliceVector slice_1(
+ {std::make_pair(const_cast<char*>(messages_1.back().second.data()),
+ messages_1.back().second.size())});
+ send_channel_1->SendOrQueueMessage(slice_1.span(), i);
+ messages_sent_1.push_back(i);
+
+ messages_2.emplace_back(2, QuicStrCat("message for 2: ", i));
+ test::QuicTestMemSliceVector slice_2(
+ {std::make_pair(const_cast<char*>(messages_2.back().second.data()),
+ messages_2.back().second.size())});
+ // Use i + 5 as the datagram id for channel 2, so that some of the ids
+ // overlap and some are disjoint.
+ send_channel_2->SendOrQueueMessage(slice_2.span(), i + 5);
+ messages_sent_2.push_back(i + 5);
+ }
+
+ // Now send something retransmittable to prompt loss detection.
+ // If we never send anything retransmittable, we will never get acks, and
+ // never detect losses.
+ messages_1.emplace_back(1, QuicStrCat("message for 1: ", num_messages));
+ test::QuicTestMemSliceVector slice(
+ {std::make_pair(const_cast<char*>(messages_1.back().second.data()),
+ messages_1.back().second.size())});
+ QuartcStream* stream_1 = send_channel_1->CreateOutgoingBidirectionalStream();
+ stream_1->SetDelegate(&fake_send_stream_delegate);
+ stream_1->WriteMemSlices(slice.span(), /*fin=*/true);
+
+ EXPECT_TRUE(simulator_.RunUntilOrTimeout(
+ [&send_delegate_1, &send_delegate_2]() {
+ return send_delegate_1.datagrams_lost().size() == 10 &&
+ send_delegate_2.datagrams_lost().size() == 10;
+ },
+ QuicTime::Delta::FromSeconds(60)));
+
+ EXPECT_EQ(send_delegate_1.datagrams_lost(), messages_sent_1);
+ EXPECT_EQ(send_delegate_2.datagrams_lost(), messages_sent_2);
+
+ EXPECT_THAT(send_delegate_1.datagrams_acked(), IsEmpty());
+ EXPECT_THAT(send_delegate_2.datagrams_acked(), IsEmpty());
+
+ EXPECT_THAT(receive_delegate_1.messages_received(), IsEmpty());
+ EXPECT_THAT(server_default_receiver_.messages_received(), IsEmpty());
+}
+
+TEST_F(QuartcMultiplexerTest, UnregisterReceiveChannel) {
+ Connect();
+
+ FakeSendDelegate send_delegate;
+ QuartcSendChannel* send_channel =
+ client_multiplexer()->CreateSendChannel(1, &send_delegate);
+ FakeQuartcStreamDelegate fake_send_stream_delegate;
+
+ FakeReceiveDelegate receive_delegate;
+ server_multiplexer()->RegisterReceiveChannel(1, &receive_delegate);
+ server_multiplexer()->RegisterReceiveChannel(1, nullptr);
+
+ int num_messages = 10;
+ std::vector<std::pair<uint64_t, std::string>> messages;
+ messages.reserve(num_messages);
+ std::vector<int64_t> messages_sent;
+ std::vector<testing::Matcher<std::pair<int64_t, QuicTime>>> ack_matchers;
+ for (int i = 0; i < num_messages; ++i) {
+ messages.emplace_back(1, QuicStrCat("message for 1: ", i));
+ test::QuicTestMemSliceVector slice(
+ {std::make_pair(const_cast<char*>(messages.back().second.data()),
+ messages.back().second.size())});
+ send_channel->SendOrQueueMessage(slice.span(), i);
+ messages_sent.push_back(i);
+ ack_matchers.push_back(Pair(i, Gt(QuicTime::Zero())));
+ }
+
+ EXPECT_TRUE(simulator_.RunUntil([&send_delegate]() {
+ return send_delegate.datagrams_acked().size() == 10;
+ }));
+
+ EXPECT_EQ(send_delegate.datagrams_sent(), messages_sent);
+ EXPECT_EQ(server_default_receiver_.messages_received(), messages);
+ EXPECT_THAT(send_delegate.datagrams_acked(), ElementsAreArray(ack_matchers));
+}
+
+TEST_F(QuartcMultiplexerTest, CloseEvent) {
+ Connect();
+ Disconnect();
+
+ EXPECT_EQ(client_session_delegate_.error(), QUIC_CONNECTION_CANCELLED);
+ EXPECT_EQ(server_session_delegate_.error(), QUIC_CONNECTION_CANCELLED);
+}
+
+TEST_F(QuartcMultiplexerTest, CongestionEvent) {
+ Connect();
+ ASSERT_TRUE(simulator_.RunUntil([this]() {
+ return client_session_delegate_.handshake_count() > 0 &&
+ server_session_delegate_.handshake_count() > 0;
+ }));
+
+ EXPECT_GT(client_session_delegate_.latest_bandwidth_estimate(),
+ QuicBandwidth::Zero());
+ EXPECT_GT(client_session_delegate_.latest_pacing_rate(),
+ QuicBandwidth::Zero());
+ EXPECT_GT(client_session_delegate_.latest_rtt(), QuicTime::Delta::Zero());
+}
+
+} // namespace
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_session.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_session.cc
index 8a918caac56..117b1373363 100644
--- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_session.cc
+++ b/chromium/net/third_party/quiche/src/quic/quartc/quartc_session.cc
@@ -24,7 +24,11 @@ QuartcSession::QuartcSession(std::unique_ptr<QuicConnection> connection,
const QuicConfig& config,
const ParsedQuicVersionVector& supported_versions,
const QuicClock* clock)
- : QuicSession(connection.get(), visitor, config, supported_versions),
+ : QuicSession(connection.get(),
+ visitor,
+ config,
+ supported_versions,
+ /*num_expected_unidirectional_static_streams = */ 0),
connection_(std::move(connection)),
clock_(clock),
per_packet_options_(QuicMakeUnique<QuartcPerPacketOptions>()) {
@@ -152,10 +156,7 @@ bool QuartcSession::SendProbingData() {
void QuartcSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) {
QuicSession::OnCryptoHandshakeEvent(event);
switch (event) {
- case ENCRYPTION_FIRST_ESTABLISHED:
- case ENCRYPTION_REESTABLISHED:
- // 1-rtt setup triggers 'ENCRYPTION_REESTABLISHED' (after REJ, when the
- // CHLO is sent).
+ case ENCRYPTION_ESTABLISHED:
DCHECK(IsEncryptionEstablished());
DCHECK(session_delegate_);
session_delegate_->OnConnectionWritable();
@@ -207,7 +208,7 @@ void QuartcSession::OnCongestionWindowChange(QuicTime /*now*/) {
bool QuartcSession::ShouldKeepConnectionAlive() const {
// TODO(mellem): Quartc may want different keepalive logic than HTTP.
- return GetNumOpenDynamicStreams() > 0;
+ return GetNumActiveStreams() > 0;
}
void QuartcSession::OnConnectionClosed(const QuicConnectionCloseFrame& frame,
@@ -301,7 +302,8 @@ std::unique_ptr<QuartcStream> QuartcSession::InitializeDataStream(
// Register the stream to the QuicWriteBlockedList. |priority| is clamped
// between 0 and 7, with 0 being the highest priority and 7 the lowest
// priority.
- write_blocked_streams()->UpdateStreamPriority(stream->id(), priority);
+ write_blocked_streams()->UpdateStreamPriority(
+ stream->id(), spdy::SpdyStreamPrecedence(priority));
if (IsIncomingStream(stream->id())) {
DCHECK(session_delegate_);
diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream.cc
index 607fa432723..f18d42defc8 100644
--- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream.cc
+++ b/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream.cc
@@ -27,24 +27,28 @@ QuartcStream::QuartcStream(QuicStreamId id, QuicSession* session)
QuartcStream::~QuartcStream() {}
void QuartcStream::OnDataAvailable() {
- bool fin = sequencer()->ReadableBytes() + sequencer()->NumBytesConsumed() ==
- sequencer()->close_offset();
-
- // Upper bound on number of readable regions. Each complete block's worth of
- // data crosses at most one region boundary. The remainder may cross one more
- // boundary. Number of regions is one more than the number of region
- // boundaries crossed.
- size_t iov_length = sequencer()->ReadableBytes() /
- QuicStreamSequencerBuffer::kBlockSizeBytes +
- 2;
- std::unique_ptr<iovec[]> iovecs = QuicMakeUnique<iovec[]>(iov_length);
- iov_length = sequencer()->GetReadableRegions(iovecs.get(), iov_length);
-
- sequencer()->MarkConsumed(
- delegate_->OnReceived(this, iovecs.get(), iov_length, fin));
- if (sequencer()->IsClosed()) {
- OnFinRead();
- }
+ size_t bytes_consumed = 0;
+ do {
+ bool fin = sequencer()->ReadableBytes() + sequencer()->NumBytesConsumed() ==
+ sequencer()->close_offset();
+
+ // Upper bound on number of readable regions. Each complete block's worth
+ // of data crosses at most one region boundary. The remainder may cross one
+ // more boundary. Number of regions is one more than the number of region
+ // boundaries crossed.
+ size_t iov_length = sequencer()->ReadableBytes() /
+ QuicStreamSequencerBuffer::kBlockSizeBytes +
+ 2;
+ std::unique_ptr<iovec[]> iovecs = QuicMakeUnique<iovec[]>(iov_length);
+ iov_length = sequencer()->GetReadableRegions(iovecs.get(), iov_length);
+
+ bytes_consumed = delegate_->OnReceived(this, iovecs.get(), iov_length, fin);
+ sequencer()->MarkConsumed(bytes_consumed);
+ if (sequencer()->IsClosed()) {
+ OnFinRead();
+ break;
+ }
+ } while (bytes_consumed > 0);
}
void QuartcStream::OnClose() {
@@ -56,8 +60,9 @@ void QuartcStream::OnClose() {
void QuartcStream::OnStreamDataConsumed(size_t bytes_consumed) {
QuicStream::OnStreamDataConsumed(bytes_consumed);
- DCHECK(delegate_);
- delegate_->OnBufferChanged(this);
+ if (delegate_) {
+ delegate_->OnBufferChanged(this);
+ }
}
void QuartcStream::OnDataBuffered(
@@ -65,8 +70,9 @@ void QuartcStream::OnDataBuffered(
QuicByteCount /*data_length*/,
const QuicReferenceCountedPointer<
QuicAckListenerInterface>& /*ack_listener*/) {
- DCHECK(delegate_);
- delegate_->OnBufferChanged(this);
+ if (delegate_) {
+ delegate_->OnBufferChanged(this);
+ }
}
bool QuartcStream::OnStreamFrameAcked(QuicStreamOffset offset,
@@ -156,10 +162,6 @@ void QuartcStream::FinishWriting() {
}
void QuartcStream::SetDelegate(Delegate* delegate) {
- if (delegate_) {
- QUIC_LOG(WARNING) << "The delegate for Stream " << id()
- << " has already been set.";
- }
delegate_ = delegate;
DCHECK(delegate_);
}
diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream_test.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream_test.cc
index be23b75d5e9..eb4d4128689 100644
--- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream_test.cc
@@ -55,7 +55,8 @@ class MockQuicSession : public QuicSession {
: QuicSession(connection,
nullptr /*visitor*/,
config,
- CurrentSupportedVersions()),
+ CurrentSupportedVersions(),
+ /*num_expected_unidirectional_static_streams = */ 0),
write_buffer_(write_buffer) {}
~MockQuicSession() override {}
@@ -93,7 +94,7 @@ class MockQuicSession : public QuicSession {
const QuicCryptoStream* GetCryptoStream() const override { return nullptr; }
QuicCryptoStream* GetMutableCryptoStream() override { return nullptr; }
bool ShouldKeepConnectionAlive() const override {
- return GetNumOpenDynamicStreams() > 0;
+ return GetNumActiveStreams() > 0;
}
// Called by QuicStream when they want to close stream.
@@ -107,9 +108,9 @@ class MockQuicSession : public QuicSession {
// Tracks whether the stream is write blocked and its priority.
void RegisterReliableStream(QuicStreamId stream_id,
spdy::SpdyPriority priority) {
- write_blocked_streams()->RegisterStream(stream_id,
- /*is_static_stream=*/false,
- priority);
+ write_blocked_streams()->RegisterStream(
+ stream_id,
+ /*is_static_stream=*/false, spdy::SpdyStreamPrecedence(priority));
}
// The session take ownership of the stream.
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 095472a7b99..27e47b2172f 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
@@ -232,9 +232,6 @@ int HandshakeWithFakeServer(QuicConfig* server_quic_config,
CanAcceptClientHello(testing::_, testing::_, testing::_,
testing::_, testing::_))
.Times(testing::AnyNumber());
- EXPECT_CALL(*server_session.helper(),
- GenerateConnectionIdForReject(testing::_, testing::_))
- .Times(testing::AnyNumber());
EXPECT_CALL(*server_conn, OnCanWrite()).Times(testing::AnyNumber());
EXPECT_CALL(*client_conn, OnCanWrite()).Times(testing::AnyNumber());
@@ -679,9 +676,13 @@ void MovePackets(PacketSavingConnection* source_conn,
PacketSavingConnection* dest_conn,
Perspective dest_perspective) {
SimpleQuicFramer framer(source_conn->supported_versions(), dest_perspective);
+ QuicFramerPeer::SetLastSerializedServerConnectionId(framer.framer(),
+ TestConnectionId());
SimpleQuicFramer null_encryption_framer(source_conn->supported_versions(),
dest_perspective);
+ QuicFramerPeer::SetLastSerializedServerConnectionId(
+ null_encryption_framer.framer(), TestConnectionId());
size_t index = *inout_packet_index;
for (; index < source_conn->encrypted_packets_.size(); index++) {
@@ -691,6 +692,8 @@ void MovePackets(PacketSavingConnection* source_conn,
// them into |framer|, perform the decryption with them, and then swap ther
// back.
QuicConnectionPeer::SwapCrypters(dest_conn, framer.framer());
+ QuicConnectionPeer::AddBytesReceived(
+ dest_conn, source_conn->encrypted_packets_[index]->length());
if (!framer.ProcessPacket(*source_conn->encrypted_packets_[index])) {
// The framer will be unable to decrypt forward-secure packets sent after
// the handshake is complete. Don't treat them as handshake packets.
@@ -721,7 +724,11 @@ void MovePackets(PacketSavingConnection* source_conn,
QuicConnectionPeer::SetCurrentPacket(
dest_conn, source_conn->encrypted_packets_[index]->AsStringPiece());
for (const auto& stream_frame : framer.stream_frames()) {
- dest_stream->OnStreamFrame(*stream_frame);
+ // Ignore stream frames that are sent on other streams in the crypto
+ // event.
+ if (stream_frame->stream_id == dest_stream->id()) {
+ dest_stream->OnStreamFrame(*stream_frame);
+ }
}
for (const auto& crypto_frame : framer.crypto_frames()) {
dest_stream->OnCryptoFrame(*crypto_frame);
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_session_visitor.h b/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_session_visitor.h
index 11dc24a724c..0954bb71390 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_session_visitor.h
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_session_visitor.h
@@ -39,9 +39,6 @@ class MockQuicCryptoServerStreamHelper : public QuicCryptoServerStream::Helper {
MockQuicCryptoServerStreamHelper& operator=(
const MockQuicCryptoServerStreamHelper&) = delete;
~MockQuicCryptoServerStreamHelper() override;
- MOCK_CONST_METHOD2(GenerateConnectionIdForReject,
- QuicConnectionId(QuicTransportVersion version,
- QuicConnectionId connection_id));
MOCK_CONST_METHOD5(CanAcceptClientHello,
bool(const CryptoHandshakeMessage& message,
const QuicSocketAddress& client_address,
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 b46e68b1d49..6b2b6d0968f 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
@@ -45,10 +45,11 @@ class MockTimeWaitListManager : public QuicTimeWaitListManager {
PacketHeaderFormat header_format,
std::unique_ptr<QuicPerPacketContext> packet_context));
- MOCK_METHOD7(SendVersionNegotiationPacket,
+ MOCK_METHOD8(SendVersionNegotiationPacket,
void(QuicConnectionId server_connection_id,
QuicConnectionId client_connection_id,
bool ietf_quic,
+ bool has_length_prefix,
const ParsedQuicVersionVector& supported_versions,
const QuicSocketAddress& server_address,
const QuicSocketAddress& client_address,
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/packet_dropping_test_writer.h b/chromium/net/third_party/quiche/src/quic/test_tools/packet_dropping_test_writer.h
index 92c895627ff..4b3e8af28ea 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/packet_dropping_test_writer.h
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/packet_dropping_test_writer.h
@@ -161,14 +161,14 @@ class PacketDroppingTestWriter : public QuicPacketWriterWrapper {
uint64_t num_calls_to_write_;
QuicMutex config_mutex_;
- int32_t fake_packet_loss_percentage_ GUARDED_BY(config_mutex_);
- int32_t fake_drop_first_n_packets_ GUARDED_BY(config_mutex_);
- int32_t fake_blocked_socket_percentage_ GUARDED_BY(config_mutex_);
- int32_t fake_packet_reorder_percentage_ GUARDED_BY(config_mutex_);
- QuicTime::Delta fake_packet_delay_ GUARDED_BY(config_mutex_);
- QuicBandwidth fake_bandwidth_ GUARDED_BY(config_mutex_);
- QuicByteCount buffer_size_ GUARDED_BY(config_mutex_);
- int32_t num_consecutive_packet_lost_ GUARDED_BY(config_mutex_);
+ int32_t fake_packet_loss_percentage_ QUIC_GUARDED_BY(config_mutex_);
+ int32_t fake_drop_first_n_packets_ QUIC_GUARDED_BY(config_mutex_);
+ int32_t fake_blocked_socket_percentage_ QUIC_GUARDED_BY(config_mutex_);
+ int32_t fake_packet_reorder_percentage_ QUIC_GUARDED_BY(config_mutex_);
+ QuicTime::Delta fake_packet_delay_ QUIC_GUARDED_BY(config_mutex_);
+ QuicBandwidth fake_bandwidth_ QUIC_GUARDED_BY(config_mutex_);
+ QuicByteCount buffer_size_ QUIC_GUARDED_BY(config_mutex_);
+ int32_t num_consecutive_packet_lost_ QUIC_GUARDED_BY(config_mutex_);
};
} // namespace test
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/qpack_encoder_peer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/qpack_encoder_peer.cc
new file mode 100644
index 00000000000..9719bdb9b7a
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/qpack_encoder_peer.cc
@@ -0,0 +1,30 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/test_tools/qpack_encoder_peer.h"
+
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h"
+
+namespace quic {
+namespace test {
+
+// static
+QpackHeaderTable* QpackEncoderPeer::header_table(QpackEncoder* encoder) {
+ return &encoder->header_table_;
+}
+
+// static
+uint64_t QpackEncoderPeer::maximum_blocked_streams(
+ const QpackEncoder* encoder) {
+ return encoder->maximum_blocked_streams_;
+}
+
+// static
+uint64_t QpackEncoderPeer::smallest_blocking_index(
+ const QpackEncoder* encoder) {
+ return encoder->blocking_manager_.smallest_blocking_index();
+}
+
+} // namespace test
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/qpack_encoder_peer.h b/chromium/net/third_party/quiche/src/quic/test_tools/qpack_encoder_peer.h
new file mode 100644
index 00000000000..2edf4274611
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/qpack_encoder_peer.h
@@ -0,0 +1,30 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_QPACK_ENCODER_PEER_H_
+#define QUICHE_QUIC_TEST_TOOLS_QPACK_ENCODER_PEER_H_
+
+#include <cstdint>
+
+namespace quic {
+
+class QpackEncoder;
+class QpackHeaderTable;
+
+namespace test {
+
+class QpackEncoderPeer {
+ public:
+ QpackEncoderPeer() = delete;
+
+ static QpackHeaderTable* header_table(QpackEncoder* encoder);
+ static uint64_t maximum_blocked_streams(const QpackEncoder* encoder);
+ static uint64_t smallest_blocking_index(const QpackEncoder* encoder);
+};
+
+} // namespace test
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_TEST_TOOLS_QPACK_ENCODER_PEER_H_
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/qpack_header_table_peer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/qpack_header_table_peer.cc
new file mode 100644
index 00000000000..bb18731dae7
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/qpack_header_table_peer.cc
@@ -0,0 +1,25 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/test_tools/qpack_header_table_peer.h"
+
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_header_table.h"
+
+namespace quic {
+namespace test {
+
+// static
+uint64_t QpackHeaderTablePeer::dynamic_table_capacity(
+ const QpackHeaderTable* header_table) {
+ return header_table->dynamic_table_capacity_;
+}
+
+// static
+uint64_t QpackHeaderTablePeer::maximum_dynamic_table_capacity(
+ const QpackHeaderTable* header_table) {
+ return header_table->maximum_dynamic_table_capacity_;
+}
+
+} // namespace test
+} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/qpack_header_table_peer.h b/chromium/net/third_party/quiche/src/quic/test_tools/qpack_header_table_peer.h
new file mode 100644
index 00000000000..cbf3f448a28
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/qpack_header_table_peer.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_QPACK_HEADER_TABLE_PEER_H_
+#define QUICHE_QUIC_TEST_TOOLS_QPACK_HEADER_TABLE_PEER_H_
+
+#include <cstdint>
+
+namespace quic {
+
+class QpackHeaderTable;
+
+namespace test {
+
+class QpackHeaderTablePeer {
+ public:
+ QpackHeaderTablePeer() = delete;
+
+ static uint64_t dynamic_table_capacity(const QpackHeaderTable* header_table);
+ static uint64_t maximum_dynamic_table_capacity(
+ const QpackHeaderTable* header_table);
+};
+
+} // namespace test
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_TEST_TOOLS_QPACK_HEADER_TABLE_PEER_H_
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.cc
index 66d1a51434e..ef2ffb39c02 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
@@ -332,5 +332,18 @@ void QuicConnectionPeer::SetLastHeaderFormat(QuicConnection* connection,
connection->last_header_.form = format;
}
+// static
+void QuicConnectionPeer::AddBytesReceived(QuicConnection* connection,
+ size_t length) {
+ if (connection->EnforceAntiAmplificationLimit()) {
+ connection->bytes_received_before_address_validation_ += length;
+ }
+}
+
+// static
+void QuicConnectionPeer::SetAddressValidated(QuicConnection* connection) {
+ connection->address_validated_ = true;
+}
+
} // 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 d0797f52adf..f329a1cb833 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
@@ -133,6 +133,8 @@ class QuicConnectionPeer {
QuicConnection* connection);
static void SetLastHeaderFormat(QuicConnection* connection,
PacketHeaderFormat format);
+ static void AddBytesReceived(QuicConnection* connection, size_t length);
+ static void SetAddressValidated(QuicConnection* connection);
};
} // namespace test
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_crypto_server_config_peer.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_crypto_server_config_peer.h
index 3f5a9840a33..baaa9b8bffb 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_crypto_server_config_peer.h
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_crypto_server_config_peer.h
@@ -73,7 +73,7 @@ class QuicCryptoServerConfigPeer {
// ConfigsDebug returns a std::string that contains debugging information
// about the set of Configs loaded in |server_config_| and their status.
std::string ConfigsDebug()
- SHARED_LOCKS_REQUIRED(server_config_->configs_lock_);
+ QUIC_SHARED_LOCKS_REQUIRED(server_config_->configs_lock_);
void SelectNewPrimaryConfig(int seconds);
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_framer_peer.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_framer_peer.h
index 8496718fc29..24b8818a804 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_framer_peer.h
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_framer_peer.h
@@ -179,6 +179,12 @@ class QuicFramerPeer {
uint8_t* destination_connection_id_length,
uint8_t* source_connection_id_length,
std::string* detailed_error);
+
+ static void set_current_received_frame_type(
+ QuicFramer* framer,
+ uint64_t current_received_frame_type) {
+ framer->current_received_frame_type_ = current_received_frame_type;
+ }
};
} // namespace test
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.cc
index e78b0597284..ab4e5af1ebc 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.cc
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.cc
@@ -161,8 +161,7 @@ void QuicSessionPeer::ActivateStream(QuicSession* session,
// static
void QuicSessionPeer::RegisterStaticStream(QuicSession* session,
std::unique_ptr<QuicStream> stream) {
- return session->RegisterStaticStream(std::move(stream),
- /*stream_already_counted = */ false);
+ return session->RegisterStaticStream(std::move(stream));
}
// static
@@ -243,5 +242,12 @@ void QuicSessionPeer::SendRstStreamInner(QuicSession* session,
session->SendRstStreamInner(id, error, bytes_written, close_write_side_only);
}
+// static
+PendingStream* QuicSessionPeer::GetPendingStream(QuicSession* session,
+ QuicStreamId stream_id) {
+ auto it = session->pending_stream_map_.find(stream_id);
+ return it == session->pending_stream_map_.end() ? nullptr : it->second.get();
+}
+
} // namespace test
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.h
index f027eb564a6..decc4b93f45 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.h
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.h
@@ -86,6 +86,8 @@ class QuicSessionPeer {
QuicRstStreamErrorCode error,
QuicStreamOffset bytes_written,
bool close_write_side_only);
+ static PendingStream* GetPendingStream(QuicSession* session,
+ QuicStreamId stream_id);
};
} // 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 68552a83a0f..85237c454e1 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
@@ -5,6 +5,7 @@
#include "net/third_party/quiche/src/quic/test_tools/quic_spdy_session_peer.h"
#include "net/third_party/quiche/src/quic/core/http/quic_spdy_session.h"
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_receive_stream.h"
#include "net/third_party/quiche/src/quic/core/quic_utils.h"
namespace quic {
@@ -13,11 +14,13 @@ namespace test {
// static
QuicHeadersStream* QuicSpdySessionPeer::GetHeadersStream(
QuicSpdySession* session) {
+ DCHECK(!VersionUsesQpack(session->connection()->transport_version()));
return session->headers_stream();
}
void QuicSpdySessionPeer::SetHeadersStream(QuicSpdySession* session,
QuicHeadersStream* headers_stream) {
+ DCHECK(!VersionUsesQpack(session->connection()->transport_version()));
for (auto& it : session->stream_map()) {
if (it.first == QuicUtils::GetHeadersStreamId(
session->connection()->transport_version())) {
@@ -58,10 +61,10 @@ size_t QuicSpdySessionPeer::WriteHeadersOnHeadersStream(
QuicStreamId id,
spdy::SpdyHeaderBlock headers,
bool fin,
- spdy::SpdyPriority priority,
+ const spdy::SpdyStreamPrecedence& precedence,
QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) {
return session->WriteHeadersOnHeadersStream(
- id, std::move(headers), fin, priority, std::move(ack_listener));
+ id, std::move(headers), fin, precedence, std::move(ack_listener));
}
// static
@@ -82,5 +85,29 @@ QuicSendControlStream* QuicSpdySessionPeer::GetSendControlStream(
return session->send_control_stream_;
}
+// static
+QpackSendStream* QuicSpdySessionPeer::GetQpackDecoderSendStream(
+ QuicSpdySession* session) {
+ return session->qpack_decoder_send_stream_;
+}
+
+// static
+QpackSendStream* QuicSpdySessionPeer::GetQpackEncoderSendStream(
+ QuicSpdySession* session) {
+ return session->qpack_encoder_send_stream_;
+}
+
+// static
+QpackReceiveStream* QuicSpdySessionPeer::GetQpackDecoderReceiveStream(
+ QuicSpdySession* session) {
+ return session->qpack_decoder_receive_stream_;
+}
+
+// static
+QpackReceiveStream* QuicSpdySessionPeer::GetQpackEncoderReceiveStream(
+ QuicSpdySession* session) {
+ return session->qpack_encoder_receive_stream_;
+}
+
} // namespace test
} // namespace quic
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 aacf712ae2f..1cfd45f252c 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,8 @@
#include "net/third_party/quiche/src/quic/core/http/quic_receive_control_stream.h"
#include "net/third_party/quiche/src/quic/core/http/quic_send_control_stream.h"
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_receive_stream.h"
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_send_stream.h"
#include "net/third_party/quiche/src/quic/core/quic_packets.h"
#include "net/third_party/quiche/src/quic/core/quic_write_blocked_list.h"
#include "net/third_party/quiche/src/spdy/core/spdy_framer.h"
@@ -41,7 +43,7 @@ class QuicSpdySessionPeer {
QuicStreamId id,
spdy::SpdyHeaderBlock headers,
bool fin,
- spdy::SpdyPriority priority,
+ const spdy::SpdyStreamPrecedence& precedence,
QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener);
// |session| can't be nullptr.
static QuicStreamId GetNextOutgoingUnidirectionalStreamId(
@@ -49,6 +51,12 @@ class QuicSpdySessionPeer {
static QuicReceiveControlStream* GetReceiveControlStream(
QuicSpdySession* session);
static QuicSendControlStream* GetSendControlStream(QuicSpdySession* session);
+ static QpackSendStream* GetQpackDecoderSendStream(QuicSpdySession* session);
+ static QpackSendStream* GetQpackEncoderSendStream(QuicSpdySession* session);
+ static QpackReceiveStream* GetQpackDecoderReceiveStream(
+ QuicSpdySession* session);
+ static QpackReceiveStream* GetQpackEncoderReceiveStream(
+ QuicSpdySession* session);
};
} // namespace test
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_client.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_client.cc
index e2e33c7a3bf..402a2311882 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_client.cc
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_client.cc
@@ -233,9 +233,14 @@ MockableQuicClient::mockable_network_helper() const {
}
QuicConnectionId MockableQuicClient::GenerateNewConnectionId() {
- return server_connection_id_overridden_
- ? override_server_connection_id_
- : QuicClient::GenerateNewConnectionId();
+ if (server_connection_id_overridden_) {
+ return override_server_connection_id_;
+ }
+ if (override_server_connection_id_length_ >= 0) {
+ return QuicUtils::CreateRandomConnectionId(
+ override_server_connection_id_length_);
+ }
+ return QuicClient::GenerateNewConnectionId();
}
void MockableQuicClient::UseConnectionId(
@@ -244,9 +249,20 @@ void MockableQuicClient::UseConnectionId(
override_server_connection_id_ = server_connection_id;
}
+void MockableQuicClient::UseConnectionIdLength(
+ int server_connection_id_length) {
+ override_server_connection_id_length_ = server_connection_id_length;
+}
+
QuicConnectionId MockableQuicClient::GetClientConnectionId() {
- return client_connection_id_overridden_ ? override_client_connection_id_
- : QuicClient::GetClientConnectionId();
+ if (client_connection_id_overridden_) {
+ return override_client_connection_id_;
+ }
+ if (override_client_connection_id_length_ >= 0) {
+ return QuicUtils::CreateRandomConnectionId(
+ override_client_connection_id_length_);
+ }
+ return QuicClient::GetClientConnectionId();
}
void MockableQuicClient::UseClientConnectionId(
@@ -255,6 +271,11 @@ void MockableQuicClient::UseClientConnectionId(
override_client_connection_id_ = client_connection_id;
}
+void MockableQuicClient::UseClientConnectionIdLength(
+ int client_connection_id_length) {
+ override_client_connection_id_length_ = client_connection_id_length;
+}
+
void MockableQuicClient::UseWriter(QuicPacketWriterWrapper* writer) {
mockable_network_helper()->UseWriter(writer);
}
@@ -526,7 +547,8 @@ QuicSpdyClientStream* QuicTestClient::GetOrCreateStream() {
if (!latest_created_stream_) {
SetLatestCreatedStream(client_->CreateClientStream());
if (latest_created_stream_) {
- latest_created_stream_->SetPriority(priority_);
+ latest_created_stream_->SetPriority(
+ spdy::SpdyStreamPrecedence(priority_));
}
}
@@ -769,12 +791,23 @@ void QuicTestClient::UseConnectionId(QuicConnectionId server_connection_id) {
client_->UseConnectionId(server_connection_id);
}
+void QuicTestClient::UseConnectionIdLength(int server_connection_id_length) {
+ DCHECK(!connected());
+ client_->UseConnectionIdLength(server_connection_id_length);
+}
+
void QuicTestClient::UseClientConnectionId(
QuicConnectionId client_connection_id) {
DCHECK(!connected());
client_->UseClientConnectionId(client_connection_id);
}
+void QuicTestClient::UseClientConnectionIdLength(
+ int client_connection_id_length) {
+ DCHECK(!connected());
+ client_->UseClientConnectionIdLength(client_connection_id_length);
+}
+
bool QuicTestClient::MigrateSocket(const QuicIpAddress& new_host) {
return client_->MigrateSocket(new_host);
}
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_client.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_client.h
index 7b835620557..cd5b09f7d77 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_client.h
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_client.h
@@ -56,8 +56,10 @@ class MockableQuicClient : public QuicClient {
QuicConnectionId GenerateNewConnectionId() override;
void UseConnectionId(QuicConnectionId server_connection_id);
+ void UseConnectionIdLength(int server_connection_id_length);
QuicConnectionId GetClientConnectionId() override;
void UseClientConnectionId(QuicConnectionId client_connection_id);
+ void UseClientConnectionIdLength(int client_connection_id_length);
void UseWriter(QuicPacketWriterWrapper* writer);
void set_peer_address(const QuicSocketAddress& address);
@@ -74,9 +76,11 @@ class MockableQuicClient : public QuicClient {
// Server connection ID to use, if server_connection_id_overridden_
QuicConnectionId override_server_connection_id_;
bool server_connection_id_overridden_;
+ int override_server_connection_id_length_ = -1;
// Client connection ID to use, if client_connection_id_overridden_
QuicConnectionId override_client_connection_id_;
bool client_connection_id_overridden_;
+ int override_client_connection_id_length_ = -1;
CachedNetworkParameters cached_network_paramaters_;
};
@@ -227,9 +231,15 @@ class QuicTestClient : public QuicSpdyStream::Visitor,
// Configures client_ to use a specific server connection ID instead of a
// random one.
void UseConnectionId(QuicConnectionId server_connection_id);
+ // Configures client_ to use a specific server connection ID length instead
+ // of the default of kQuicDefaultConnectionIdLength.
+ void UseConnectionIdLength(int server_connection_id_length);
// Configures client_ to use a specific client connection ID instead of an
// empty one.
void UseClientConnectionId(QuicConnectionId client_connection_id);
+ // Configures client_ to use a specific client connection ID length instead
+ // of the default of zero.
+ void UseClientConnectionIdLength(int client_connection_id_length);
// Returns nullptr if the maximum number of streams have already been created.
QuicSpdyClientStream* GetOrCreateStream();
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_server.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_server.cc
index 68c500e67b7..19b986e8dba 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_server.cc
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_server.cc
@@ -184,7 +184,7 @@ QuicDispatcher* QuicTestServer::CreateQuicDispatcher() {
QuicMakeUnique<QuicEpollConnectionHelper>(epoll_server(),
QuicAllocator::BUFFER_POOL),
std::unique_ptr<QuicCryptoServerStream::Helper>(
- new QuicSimpleCryptoServerStreamHelper(QuicRandom::GetInstance())),
+ new QuicSimpleCryptoServerStreamHelper()),
QuicMakeUnique<QuicEpollAlarmFactory>(epoll_server()), server_backend(),
expected_server_connection_id_length());
}
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 99c7511daee..5ff5e05a9b0 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
@@ -259,6 +259,11 @@ bool NoOpFramerVisitor::OnPacketHeader(const QuicPacketHeader& /*header*/) {
void NoOpFramerVisitor::OnCoalescedPacket(
const QuicEncryptedPacket& /*packet*/) {}
+void NoOpFramerVisitor::OnUndecryptablePacket(
+ const QuicEncryptedPacket& /*packet*/,
+ EncryptionLevel /*decryption_level*/,
+ bool /*has_decryption_key*/) {}
+
bool NoOpFramerVisitor::OnStreamFrame(const QuicStreamFrame& /*frame*/) {
return true;
}
@@ -524,7 +529,8 @@ MockQuicSession::MockQuicSession(QuicConnection* connection,
: QuicSession(connection,
nullptr,
DefaultQuicConfig(),
- connection->supported_versions()) {
+ connection->supported_versions(),
+ /*num_expected_unidirectional_static_streams = */ 0) {
if (create_mock_crypto_stream) {
crypto_stream_ = QuicMakeUnique<MockQuicCryptoStream>(this);
}
@@ -633,9 +639,6 @@ TestQuicSpdyServerSession::TestQuicSpdyServerSession(
crypto_config,
compressed_certs_cache) {
Initialize();
- ON_CALL(helper_, GenerateConnectionIdForReject(_, _))
- .WillByDefault(testing::Return(
- QuicUtils::CreateRandomConnectionId(connection->random_generator())));
ON_CALL(helper_, CanAcceptClientHello(_, _, _, _, _))
.WillByDefault(testing::Return(true));
}
@@ -1158,8 +1161,8 @@ QuicStreamId GetNthClientInitiatedBidirectionalStreamId(
QuicTransportVersion version,
int n) {
int num = n;
- if (!VersionLacksHeadersStream(version)) {
- num++; // + 1 because spdy_session contains headers stream.
+ if (!VersionUsesQpack(version)) {
+ num++;
}
return QuicUtils::GetFirstBidirectionalStreamId(version,
Perspective::IS_CLIENT) +
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 20494d7f3f0..5750b9bc61d 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
@@ -261,6 +261,10 @@ class MockFramerVisitor : public QuicFramerVisitorInterface {
MOCK_METHOD1(OnDecryptedPacket, void(EncryptionLevel level));
MOCK_METHOD1(OnPacketHeader, bool(const QuicPacketHeader& header));
MOCK_METHOD1(OnCoalescedPacket, void(const QuicEncryptedPacket& packet));
+ MOCK_METHOD3(OnUndecryptablePacket,
+ void(const QuicEncryptedPacket& packet,
+ EncryptionLevel decryption_level,
+ bool has_decryption_key));
MOCK_METHOD1(OnStreamFrame, bool(const QuicStreamFrame& frame));
MOCK_METHOD1(OnCryptoFrame, bool(const QuicCryptoFrame& frame));
MOCK_METHOD2(OnAckFrameStart, bool(QuicPacketNumber, QuicTime::Delta));
@@ -314,6 +318,9 @@ class NoOpFramerVisitor : public QuicFramerVisitorInterface {
void OnDecryptedPacket(EncryptionLevel /*level*/) override {}
bool OnPacketHeader(const QuicPacketHeader& header) override;
void OnCoalescedPacket(const QuicEncryptedPacket& packet) override;
+ void OnUndecryptablePacket(const QuicEncryptedPacket& packet,
+ EncryptionLevel decryption_level,
+ bool has_decryption_key) override;
bool OnStreamFrame(const QuicStreamFrame& frame) override;
bool OnCryptoFrame(const QuicCryptoFrame& frame) override;
bool OnAckFrameStart(QuicPacketNumber largest_acked,
@@ -375,9 +382,10 @@ class MockQuicConnectionVisitor : public QuicConnectionVisitorInterface {
MOCK_CONST_METHOD0(ShouldKeepConnectionAlive, bool());
MOCK_METHOD1(OnSuccessfulVersionNegotiation,
void(const ParsedQuicVersion& version));
- MOCK_METHOD2(OnConnectivityProbeReceived,
+ MOCK_METHOD3(OnPacketReceived,
void(const QuicSocketAddress& self_address,
- const QuicSocketAddress& peer_address));
+ const QuicSocketAddress& peer_address,
+ bool is_connectivity_probe));
MOCK_METHOD0(OnConfigNegotiated, void());
MOCK_METHOD0(OnAckNeedsRetransmittableFrame, void());
MOCK_METHOD0(SendPing, void());
@@ -624,6 +632,12 @@ class MockQuicSession : public QuicSession {
MOCK_CONST_METHOD0(IsCryptoHandshakeConfirmed, bool());
MOCK_CONST_METHOD0(ShouldKeepConnectionAlive, bool());
MOCK_METHOD2(SendStopSending, void(uint16_t code, QuicStreamId stream_id));
+ MOCK_METHOD1(OnCryptoHandshakeEvent, void(QuicSession::CryptoHandshakeEvent));
+ MOCK_CONST_METHOD0(GetAlpnsToOffer, std::vector<std::string>());
+ MOCK_CONST_METHOD1(SelectAlpn,
+ std::vector<QuicStringPiece>::const_iterator(
+ const std::vector<QuicStringPiece>&));
+ MOCK_METHOD1(OnAlpnSelected, void(QuicStringPiece));
using QuicSession::ActivateStream;
@@ -676,6 +690,8 @@ class MockQuicSpdySession : public QuicSpdySession {
QuicSession::OnConnectionClosed(frame, source);
}
+ using QuicSession::RegisterStaticStream;
+
// From QuicSession.
MOCK_METHOD2(OnConnectionClosed,
void(const QuicConnectionCloseFrame& frame,
@@ -702,7 +718,8 @@ class MockQuicSpdySession : public QuicSpdySession {
MOCK_METHOD2(OnStreamHeaders,
void(QuicStreamId stream_id, QuicStringPiece headers_data));
MOCK_METHOD2(OnStreamHeadersPriority,
- void(QuicStreamId stream_id, spdy::SpdyPriority priority));
+ void(QuicStreamId stream_id,
+ const spdy::SpdyStreamPrecedence& precedence));
MOCK_METHOD3(OnStreamHeadersComplete,
void(QuicStreamId stream_id, bool fin, size_t frame_len));
MOCK_METHOD4(OnStreamHeaderList,
@@ -723,7 +740,8 @@ class MockQuicSpdySession : public QuicSpdySession {
size_t frame_len,
const QuicHeaderList& header_list));
MOCK_METHOD2(OnPriorityFrame,
- void(QuicStreamId id, spdy::SpdyPriority priority));
+ void(QuicStreamId id,
+ const spdy::SpdyStreamPrecedence& precedence));
MOCK_METHOD1(OnHeadersHeadOfLineBlocking, void(QuicTime::Delta delta));
MOCK_METHOD4(
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/server_thread.h b/chromium/net/third_party/quiche/src/quic/test_tools/server_thread.h
index ffbce7f15a9..d430297f30b 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/server_thread.h
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/server_thread.h
@@ -73,13 +73,13 @@ class ServerThread : public QuicThread {
std::unique_ptr<QuicServer> server_;
QuicSocketAddress address_;
mutable QuicMutex port_lock_;
- int port_ GUARDED_BY(port_lock_);
+ int port_ QUIC_GUARDED_BY(port_lock_);
bool initialized_;
QuicMutex scheduled_actions_lock_;
QuicDeque<std::function<void()>> scheduled_actions_
- GUARDED_BY(scheduled_actions_lock_);
+ QUIC_GUARDED_BY(scheduled_actions_lock_);
};
} // namespace test
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simple_quic_framer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/simple_quic_framer.cc
index 547f6d26c8d..ad7e7bb32a1 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/simple_quic_framer.cc
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/simple_quic_framer.cc
@@ -60,6 +60,10 @@ class SimpleFramerVisitor : public QuicFramerVisitorInterface {
void OnCoalescedPacket(const QuicEncryptedPacket& /*packet*/) override {}
+ void OnUndecryptablePacket(const QuicEncryptedPacket& /*packet*/,
+ EncryptionLevel /*decryption_level*/,
+ bool /*has_decryption_key*/) override {}
+
bool OnStreamFrame(const QuicStreamFrame& frame) override {
// Save a copy of the data so it is valid after the packet is processed.
std::string* string_data =
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 16c441c8c32..72a23d73178 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
@@ -175,6 +175,14 @@ void SimpleSessionNotifier::OnCanWrite() {
}
}
+void SimpleSessionNotifier::OnStreamReset(QuicStreamId id,
+ QuicRstStreamErrorCode error) {
+ if (error != QUIC_STREAM_NO_ERROR) {
+ // Delete stream to avoid retransmissions.
+ stream_map_.erase(id);
+ }
+}
+
bool SimpleSessionNotifier::WillingToWrite() const {
QUIC_DVLOG(1) << "has_buffered_control_frames: " << HasBufferedControlFrames()
<< " as_lost_control_frames: " << !lost_control_frames_.empty()
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 74240539ae7..b3d5d729e82 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
@@ -45,6 +45,9 @@ class SimpleSessionNotifier : public SessionNotifierInterface {
// Called when connection_ becomes writable.
void OnCanWrite();
+ // Called to reset stream.
+ void OnStreamReset(QuicStreamId id, QuicRstStreamErrorCode error);
+
// Returns true if there are 1) unsent control frames and stream data, or 2)
// lost control frames and stream data.
bool WillingToWrite() const;
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier_test.cc b/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier_test.cc
index 8b931fed34d..63da6397209 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier_test.cc
@@ -251,8 +251,10 @@ TEST_F(SimpleSessionNotifierTest, OnCanWriteCryptoFrames) {
.WillOnce(Invoke(&connection_,
&MockQuicConnection::QuicConnection_SendCryptoData));
EXPECT_CALL(connection_, CloseConnection(QUIC_PACKET_WRITE_ERROR, _, _));
- producer.SaveCryptoData(ENCRYPTION_INITIAL, 0, std::string(1024, 'a'));
- producer.SaveCryptoData(ENCRYPTION_INITIAL, 500, std::string(524, 'a'));
+ std::string crypto_data1(1024, 'a');
+ producer.SaveCryptoData(ENCRYPTION_INITIAL, 0, crypto_data1);
+ std::string crypto_data2(524, 'a');
+ producer.SaveCryptoData(ENCRYPTION_INITIAL, 500, crypto_data2);
notifier_.WriteCryptoData(ENCRYPTION_INITIAL, 1024, 0);
// Send crypto data [1024, 2048) in ENCRYPTION_ZERO_RTT.
connection_.SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
@@ -261,7 +263,8 @@ TEST_F(SimpleSessionNotifierTest, OnCanWriteCryptoFrames) {
EXPECT_CALL(connection_, SendCryptoData(ENCRYPTION_ZERO_RTT, 1024, 0))
.WillOnce(Invoke(&connection_,
&MockQuicConnection::QuicConnection_SendCryptoData));
- producer.SaveCryptoData(ENCRYPTION_ZERO_RTT, 0, std::string(1024, 'a'));
+ std::string crypto_data3(1024, 'a');
+ producer.SaveCryptoData(ENCRYPTION_ZERO_RTT, 0, crypto_data3);
notifier_.WriteCryptoData(ENCRYPTION_ZERO_RTT, 1024, 0);
// Send stream 3 [0, 1024) and connection is blocked.
EXPECT_CALL(connection_, SendStreamData(3, 1024, 0, FIN))
diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.h b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.h
index 7481ddc6b1f..43fce53bb4c 100644
--- a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.h
+++ b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.h
@@ -97,9 +97,9 @@ class QuicEndpoint : public Endpoint,
void OnWriteBlocked() override {}
void OnSuccessfulVersionNegotiation(
const ParsedQuicVersion& /*version*/) override {}
- void OnConnectivityProbeReceived(
- const QuicSocketAddress& /*self_address*/,
- const QuicSocketAddress& /*peer_address*/) override {}
+ void OnPacketReceived(const QuicSocketAddress& /*self_address*/,
+ const QuicSocketAddress& /*peer_address*/,
+ bool /*is_connectivity_probe*/) override {}
void OnCongestionWindowChange(QuicTime /*now*/) override {}
void OnConnectionMigration(AddressChangeType /*type*/) override {}
void OnPathDegrading() override {}
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_client.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_client.cc
index e7fe6b4830e..123cf1ee30f 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_client.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_client.cc
@@ -5,10 +5,12 @@
#include "net/third_party/quiche/src/quic/tools/quic_client.h"
#include <errno.h>
+#include <netdb.h>
#include <netinet/in.h>
#include <string.h>
#include <sys/epoll.h>
#include <sys/socket.h>
+#include <sys/types.h>
#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h"
#include "net/third_party/quiche/src/quic/core/http/spdy_utils.h"
@@ -21,6 +23,7 @@
#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
#include "net/quic/platform/impl/quic_socket_utils.h"
#include "net/third_party/quiche/src/quic/tools/quic_simple_client_session.h"
@@ -30,6 +33,29 @@
namespace quic {
+namespace tools {
+
+QuicSocketAddress LookupAddress(std::string host, std::string port) {
+ addrinfo hint;
+ memset(&hint, 0, sizeof(hint));
+ hint.ai_protocol = IPPROTO_UDP;
+
+ addrinfo* info_list = nullptr;
+ int result = getaddrinfo(host.c_str(), port.c_str(), &hint, &info_list);
+ if (result != 0) {
+ QUIC_LOG(ERROR) << "Failed to look up " << host << ": "
+ << gai_strerror(result);
+ return QuicSocketAddress();
+ }
+
+ CHECK(info_list != nullptr);
+ std::unique_ptr<addrinfo, void (*)(addrinfo*)> info_list_owned(info_list,
+ freeaddrinfo);
+ return QuicSocketAddress(info_list->ai_addr, info_list->ai_addrlen);
+}
+
+} // namespace tools
+
QuicClient::QuicClient(QuicSocketAddress server_address,
const QuicServerId& server_id,
const ParsedQuicVersionVector& supported_versions,
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_client.h b/chromium/net/third_party/quiche/src/quic/tools/quic_client.h
index e5d21700418..8e43be8498b 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_client.h
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_client.h
@@ -29,6 +29,12 @@ namespace test {
class QuicClientPeer;
} // namespace test
+namespace tools {
+
+QuicSocketAddress LookupAddress(std::string host, std::string port);
+
+} // namespace tools
+
class QuicClient : public QuicSpdyClientBase {
public:
// This will create its own QuicClientEpollNetworkHelper.
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_client_interop_test_bin.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_client_interop_test_bin.cc
new file mode 100644
index 00000000000..39f8ff9abe7
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_client_interop_test_bin.cc
@@ -0,0 +1,164 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <iostream>
+#include <memory>
+#include <string>
+
+#include "net/third_party/quiche/src/quic/core/quic_versions.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_epoll.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_system_event_loop.h"
+#include "net/third_party/quiche/src/quic/tools/fake_proof_verifier.h"
+#include "net/third_party/quiche/src/quic/tools/quic_client.h"
+
+DEFINE_QUIC_COMMAND_LINE_FLAG(std::string,
+ host,
+ "",
+ "The IP or hostname to connect to.");
+
+DEFINE_QUIC_COMMAND_LINE_FLAG(int32_t, port, 0, "The port to connect to.");
+
+namespace quic {
+
+enum class Feature {
+ // A version negotiation response is elicited and acted on.
+ kVersionNegotiation,
+ // The handshake completes successfully.
+ kHandshake,
+ // Stream data is being exchanged and ACK'ed.
+ kStreamData,
+ // The connection close procedcure completes with a zero error code.
+ kConnectionClose,
+ // An H3 transaction succeeded.
+ kHttp3,
+ // TODO(nharper): Add Retry to list of tested features.
+};
+
+char MatrixLetter(Feature f) {
+ switch (f) {
+ case Feature::kVersionNegotiation:
+ return 'V';
+ case Feature::kHandshake:
+ return 'H';
+ case Feature::kStreamData:
+ return 'D';
+ case Feature::kConnectionClose:
+ return 'C';
+ case Feature::kHttp3:
+ return '3';
+ }
+}
+
+std::set<Feature> AttemptRequest(QuicSocketAddress addr,
+ std::string authority,
+ QuicServerId server_id,
+ ParsedQuicVersionVector versions) {
+ std::set<Feature> features;
+ auto proof_verifier = QuicMakeUnique<FakeProofVerifier>();
+ QuicEpollServer epoll_server;
+ auto client = QuicMakeUnique<QuicClient>(
+ addr, server_id, versions, &epoll_server, std::move(proof_verifier));
+ if (!client->Initialize()) {
+ return features;
+ }
+ if (!client->Connect()) {
+ QuicErrorCode error = client->session()->error();
+ if (error == QUIC_INVALID_VERSION) {
+ // QuicFramer::ProcessPacket returns RaiseError(QUIC_INVALID_VERSION) if
+ // it receives a packet containing a version in the header that is not our
+ // version. It might be possible that we didn't actually process a VN
+ // packet here.
+ features.insert(Feature::kVersionNegotiation);
+ return features;
+ }
+ return features;
+ }
+ if (!client->session()->IsCryptoHandshakeConfirmed()) {
+ return features;
+ }
+ features.insert(Feature::kHandshake);
+
+ // Construct and send a request.
+ spdy::SpdyHeaderBlock header_block;
+ header_block[":method"] = "GET";
+ header_block[":scheme"] = "https";
+ header_block[":authority"] = authority;
+ header_block[":path"] = "/";
+ client->set_store_response(true);
+ client->SendRequest(header_block, "", /*fin=*/true);
+
+ // TODO(nharper): After some period of time, time out and don't report
+ // success.
+ while (client->WaitForEvents()) {
+ }
+
+ if (!client->connected()) {
+ return features;
+ }
+
+ if (client->latest_response_code() != -1) {
+ features.insert(Feature::kHttp3);
+ }
+
+ // TODO(nharper): Properly check that we actually sent stream data and
+ // received ACKs for it.
+ features.insert(Feature::kStreamData);
+ // TODO(nharper): Check that we sent/received (which one?) a CONNECTION_CLOSE
+ // with error code 0.
+ features.insert(Feature::kConnectionClose);
+ return features;
+}
+
+std::set<Feature> ServerSupport(std::string host, int port) {
+ // Configure version list.
+ QuicVersionInitializeSupportForIetfDraft();
+ ParsedQuicVersion version =
+ ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_99);
+ ParsedQuicVersionVector versions = {version};
+ QuicEnableVersion(version);
+
+ // Build the client, and try to connect.
+ QuicSocketAddress addr = tools::LookupAddress(host, QuicStrCat(port));
+ QuicServerId server_id(host, port, false);
+ std::string authority = QuicStrCat(host, ":", port);
+
+ ParsedQuicVersionVector versions_with_negotiation = versions;
+ versions_with_negotiation.insert(versions_with_negotiation.begin(),
+ QuicVersionReservedForNegotiation());
+ auto supported_features =
+ AttemptRequest(addr, authority, server_id, versions_with_negotiation);
+ if (!supported_features.empty()) {
+ supported_features.insert(Feature::kVersionNegotiation);
+ } else {
+ supported_features = AttemptRequest(addr, authority, server_id, versions);
+ }
+ return supported_features;
+}
+
+} // namespace quic
+
+int main(int argc, char* argv[]) {
+ QuicSystemEventLoop event_loop("quic_client");
+ const char* usage = "Usage: quic_client_interop_test [options]";
+
+ std::vector<std::string> args =
+ quic::QuicParseCommandLineFlags(usage, argc, argv);
+ if (!args.empty()) {
+ quic::QuicPrintCommandLineFlagHelp(usage);
+ exit(1);
+ }
+ std::string host = GetQuicFlag(FLAGS_host);
+ int port = GetQuicFlag(FLAGS_port);
+ if (host.empty() || port == 0) {
+ quic::QuicPrintCommandLineFlagHelp(usage);
+ exit(1);
+ }
+
+ auto supported_features = quic::ServerSupport(host, port);
+ std::cout << "Supported features: ";
+ for (auto feature : supported_features) {
+ std::cout << MatrixLetter(feature);
+ }
+ std::cout << std::endl;
+}
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_client_test.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_client_test.cc
index 12a687c1671..e2d7f1413c8 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_client_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_client_test.cc
@@ -52,43 +52,49 @@ size_t NumOpenSocketFDs() {
return socket_count;
}
-// Creates a new QuicClient and Initializes it. Caller is responsible for
-// deletion.
-std::unique_ptr<QuicClient> CreateAndInitializeQuicClient(QuicEpollServer* eps,
- uint16_t port) {
- QuicSocketAddress server_address(QuicSocketAddress(TestLoopback(), port));
- QuicServerId server_id("hostname", server_address.port(), false);
- ParsedQuicVersionVector versions = AllSupportedVersions();
- auto client =
- QuicMakeUnique<QuicClient>(server_address, server_id, versions, eps,
- crypto_test_utils::ProofVerifierForTesting());
- EXPECT_TRUE(client->Initialize());
- return client;
-}
+class QuicClientTest : public QuicTest {
+ public:
+ QuicClientTest() {
+ // Creates and destroys a single client first which may open persistent
+ // sockets when initializing platform dependencies like certificate
+ // verifier. Future creation of addtional clients will deterministically
+ // open one socket per client.
+ CreateAndInitializeQuicClient();
+ }
+
+ // Creates a new QuicClient and Initializes it on an unused port.
+ // Caller is responsible for deletion.
+ std::unique_ptr<QuicClient> CreateAndInitializeQuicClient() {
+ uint16_t port = QuicPickServerPortForTestsOrDie();
+ QuicSocketAddress server_address(QuicSocketAddress(TestLoopback(), port));
+ QuicServerId server_id("hostname", server_address.port(), false);
+ ParsedQuicVersionVector versions = AllSupportedVersions();
+ auto client = QuicMakeUnique<QuicClient>(
+ server_address, server_id, versions, &epoll_server_,
+ crypto_test_utils::ProofVerifierForTesting());
+ EXPECT_TRUE(client->Initialize());
+ return client;
+ }
-class QuicClientTest : public QuicTest {};
+ private:
+ QuicEpollServer epoll_server_;
+};
TEST_F(QuicClientTest, DoNotLeakSocketFDs) {
// Make sure that the QuicClient doesn't leak socket FDs. Doing so could cause
// port exhaustion in long running processes which repeatedly create clients.
- // Record initial number of FDs, after creating EpollServer and creating and
- // destroying a single client (the latter is needed since initializing
- // platform dependencies like certificate verifier may open a persistent
- // socket).
- QuicEpollServer eps;
- CreateAndInitializeQuicClient(&eps, QuicPickUnusedPortOrDie());
+ // Record the initial number of FDs.
size_t number_of_open_fds = NumOpenSocketFDs();
// Create a number of clients, initialize them, and verify this has resulted
// in additional FDs being opened.
const int kNumClients = 50;
for (int i = 0; i < kNumClients; ++i) {
- std::unique_ptr<QuicClient> client(
- CreateAndInitializeQuicClient(&eps, QuicPickUnusedPortOrDie()));
-
+ EXPECT_EQ(number_of_open_fds, NumOpenSocketFDs());
+ std::unique_ptr<QuicClient> client(CreateAndInitializeQuicClient());
// Initializing the client will create a new FD.
- EXPECT_LT(number_of_open_fds, NumOpenSocketFDs());
+ EXPECT_EQ(number_of_open_fds + 1, NumOpenSocketFDs());
}
// The FDs created by the QuicClients should now be closed.
@@ -96,12 +102,12 @@ TEST_F(QuicClientTest, DoNotLeakSocketFDs) {
}
TEST_F(QuicClientTest, CreateAndCleanUpUDPSockets) {
- QuicEpollServer eps;
size_t number_of_open_fds = NumOpenSocketFDs();
- std::unique_ptr<QuicClient> client(
- CreateAndInitializeQuicClient(&eps, QuicPickUnusedPortOrDie()));
+ std::unique_ptr<QuicClient> client(CreateAndInitializeQuicClient());
+ // Creating and initializing a client will result in one socket being opened.
EXPECT_EQ(number_of_open_fds + 1, NumOpenSocketFDs());
+
// Create more UDP sockets.
EXPECT_TRUE(QuicClientPeer::CreateUDPSocketAndBind(client.get()));
EXPECT_EQ(number_of_open_fds + 2, NumOpenSocketFDs());
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.cc
index a74fba36397..7cfb00a62b2 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.cc
@@ -14,36 +14,14 @@
namespace quic {
-namespace {
-
-QuicSocketAddress LookupAddress(std::string host, std::string port) {
- addrinfo hint;
- memset(&hint, 0, sizeof(hint));
- hint.ai_protocol = IPPROTO_UDP;
-
- addrinfo* info_list = nullptr;
- int result = getaddrinfo(host.c_str(), port.c_str(), &hint, &info_list);
- if (result != 0) {
- QUIC_LOG(ERROR) << "Failed to look up " << host << ": "
- << gai_strerror(result);
- return QuicSocketAddress();
- }
-
- CHECK(info_list != nullptr);
- std::unique_ptr<addrinfo, void (*)(addrinfo*)> info_list_owned(info_list,
- freeaddrinfo);
- return QuicSocketAddress(info_list->ai_addr, info_list->ai_addrlen);
-}
-
-} // namespace
-
std::unique_ptr<QuicSpdyClientBase> QuicEpollClientFactory::CreateClient(
std::string host_for_handshake,
std::string host_for_lookup,
uint16_t port,
ParsedQuicVersionVector versions,
std::unique_ptr<ProofVerifier> verifier) {
- QuicSocketAddress addr = LookupAddress(host_for_lookup, QuicStrCat(port));
+ QuicSocketAddress addr =
+ tools::LookupAddress(host_for_lookup, QuicStrCat(port));
if (!addr.IsInitialized()) {
QUIC_LOG(ERROR) << "Unable to resolve address: " << host_for_lookup;
return nullptr;
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.h b/chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.h
index ff76c9ad41b..8e202c04399 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.h
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.h
@@ -177,15 +177,15 @@ class QuicMemoryCacheBackend : public QuicSimpleServerBackend {
// Cached responses.
QuicUnorderedMap<std::string, std::unique_ptr<QuicBackendResponse>> responses_
- GUARDED_BY(response_mutex_);
+ QUIC_GUARDED_BY(response_mutex_);
// The default response for cache misses, if set.
std::unique_ptr<QuicBackendResponse> default_response_
- GUARDED_BY(response_mutex_);
+ QUIC_GUARDED_BY(response_mutex_);
// A map from request URL to associated server push responses (if any).
std::multimap<std::string, QuicBackendResponse::ServerPushInfo>
- server_push_resources_ GUARDED_BY(response_mutex_);
+ server_push_resources_ QUIC_GUARDED_BY(response_mutex_);
// Protects against concurrent access from test threads setting responses, and
// server threads accessing those responses.
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_packet_printer_bin.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_packet_printer_bin.cc
index a87f10eadf1..7738ea7938f 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_packet_printer_bin.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_packet_printer_bin.cc
@@ -88,6 +88,11 @@ class QuicPacketPrinter : public QuicFramerVisitorInterface {
void OnCoalescedPacket(const QuicEncryptedPacket& /*packet*/) override {
std::cerr << "OnCoalescedPacket\n";
}
+ void OnUndecryptablePacket(const QuicEncryptedPacket& /*packet*/,
+ EncryptionLevel /*decryption_level*/,
+ bool /*has_decryption_key*/) override {
+ std::cerr << "OnUndecryptablePacket\n";
+ }
bool OnStreamFrame(const QuicStreamFrame& frame) override {
std::cerr << "OnStreamFrame: " << frame;
std::cerr << " data: { "
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_server.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_server.cc
index 8820040e565..46b04a5dadc 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_server.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_server.cc
@@ -155,7 +155,7 @@ QuicDispatcher* QuicServer::CreateQuicDispatcher() {
std::unique_ptr<QuicEpollConnectionHelper>(new QuicEpollConnectionHelper(
&epoll_server_, QuicAllocator::BUFFER_POOL)),
std::unique_ptr<QuicCryptoServerStream::Helper>(
- new QuicSimpleCryptoServerStreamHelper(QuicRandom::GetInstance())),
+ new QuicSimpleCryptoServerStreamHelper()),
std::unique_ptr<QuicEpollAlarmFactory>(
new QuicEpollAlarmFactory(&epoll_server_)),
quic_simple_server_backend_, expected_server_connection_id_length_);
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_server_test.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_server_test.cc
index b1a88a6f13f..8c894434dee 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_server_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_server_test.cc
@@ -72,7 +72,7 @@ class TestQuicServer : public QuicServer {
new QuicEpollConnectionHelper(epoll_server(),
QuicAllocator::BUFFER_POOL)),
std::unique_ptr<QuicCryptoServerStream::Helper>(
- new QuicSimpleCryptoServerStreamHelper(QuicRandom::GetInstance())),
+ new QuicSimpleCryptoServerStreamHelper()),
std::unique_ptr<QuicEpollAlarmFactory>(
new QuicEpollAlarmFactory(epoll_server())),
&quic_simple_server_backend_);
@@ -86,11 +86,13 @@ class TestQuicServer : public QuicServer {
class QuicServerEpollInTest : public QuicTest {
public:
QuicServerEpollInTest()
- : port_(QuicPickUnusedPortOrDie()),
+ : port_(QuicPickServerPortForTestsOrDie()),
server_address_(TestLoopback(), port_) {}
void StartListening() {
server_.CreateUDPSocketAndListen(server_address_);
+ server_address_ = QuicSocketAddress(server_address_.host(), server_.port());
+
ASSERT_TRUE(QuicServerPeer::SetSmallSocket(&server_));
if (!server_.overflow_supported()) {
@@ -163,8 +165,7 @@ class QuicServerDispatchPacketTest : public QuicTest {
new QuicEpollConnectionHelper(&eps_,
QuicAllocator::BUFFER_POOL)),
std::unique_ptr<QuicCryptoServerStream::Helper>(
- new QuicSimpleCryptoServerStreamHelper(
- QuicRandom::GetInstance())),
+ new QuicSimpleCryptoServerStreamHelper()),
std::unique_ptr<QuicEpollAlarmFactory>(
new QuicEpollAlarmFactory(&eps_)),
&quic_simple_server_backend_) {
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_crypto_server_stream_helper.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_crypto_server_stream_helper.cc
index 9d556008eb3..d27506ea06c 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_crypto_server_stream_helper.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_crypto_server_stream_helper.cc
@@ -8,20 +8,12 @@
namespace quic {
-QuicSimpleCryptoServerStreamHelper::QuicSimpleCryptoServerStreamHelper(
- QuicRandom* random)
- : random_(random) {}
+QuicSimpleCryptoServerStreamHelper::QuicSimpleCryptoServerStreamHelper() =
+ default;
QuicSimpleCryptoServerStreamHelper::~QuicSimpleCryptoServerStreamHelper() =
default;
-QuicConnectionId
-QuicSimpleCryptoServerStreamHelper::GenerateConnectionIdForReject(
- QuicTransportVersion /*version*/,
- QuicConnectionId /*connection_id*/) const {
- return QuicUtils::CreateRandomConnectionId(random_);
-}
-
bool QuicSimpleCryptoServerStreamHelper::CanAcceptClientHello(
const CryptoHandshakeMessage& /*message*/,
const QuicSocketAddress& /*client_address*/,
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_crypto_server_stream_helper.h b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_crypto_server_stream_helper.h
index 3480776ff1a..c4dcb08daee 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_crypto_server_stream_helper.h
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_crypto_server_stream_helper.h
@@ -15,22 +15,15 @@ namespace quic {
class QuicSimpleCryptoServerStreamHelper
: public QuicCryptoServerStream::Helper {
public:
- explicit QuicSimpleCryptoServerStreamHelper(QuicRandom* random);
+ QuicSimpleCryptoServerStreamHelper();
~QuicSimpleCryptoServerStreamHelper() override;
- QuicConnectionId GenerateConnectionIdForReject(
- QuicTransportVersion /*version*/,
- QuicConnectionId /*connection_id*/) const override;
-
bool CanAcceptClientHello(const CryptoHandshakeMessage& message,
const QuicSocketAddress& client_address,
const QuicSocketAddress& peer_address,
const QuicSocketAddress& self_address,
std::string* error_details) const override;
-
- private:
- QuicRandom* random_; // Unowned.
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_crypto_server_stream_helper_test.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_crypto_server_stream_helper_test.cc
deleted file mode 100644
index 4ede5889a9f..00000000000
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_crypto_server_stream_helper_test.cc
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/third_party/quiche/src/quic/tools/quic_simple_crypto_server_stream_helper.h"
-
-#include "net/third_party/quiche/src/quic/core/quic_utils.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
-#include "net/third_party/quiche/src/quic/test_tools/mock_random.h"
-#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
-
-namespace quic {
-
-class QuicSimpleCryptoServerStreamHelperTest : public QuicTest {};
-
-TEST_F(QuicSimpleCryptoServerStreamHelperTest, GenerateConnectionIdForReject) {
- test::MockRandom random;
- QuicSimpleCryptoServerStreamHelper helper(&random);
-
- EXPECT_EQ(QuicUtils::CreateRandomConnectionId(&random),
- helper.GenerateConnectionIdForReject(QUIC_VERSION_99,
- test::TestConnectionId()));
-}
-
-} // namespace quic
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 2e98cdd3e01..d06cd4b28a1 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
@@ -6,6 +6,7 @@
#include <utility>
+#include "net/third_party/quiche/src/quic/core/http/quic_spdy_session.h"
#include "net/third_party/quiche/src/quic/core/quic_connection.h"
#include "net/third_party/quiche/src/quic/core/quic_utils.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
@@ -32,11 +33,7 @@ QuicSimpleServerSession::QuicSimpleServerSession(
crypto_config,
compressed_certs_cache),
highest_promised_stream_id_(
- VersionHasStreamType(connection->transport_version())
- ? QuicUtils::GetFirstUnidirectionalStreamId(
- connection->transport_version(),
- Perspective::IS_SERVER)
- : QuicUtils::GetInvalidStreamId(connection->transport_version())),
+ QuicUtils::GetInvalidStreamId(connection->transport_version())),
quic_simple_server_backend_(quic_simple_server_backend) {
DCHECK(quic_simple_server_backend_);
}
@@ -68,6 +65,7 @@ void QuicSimpleServerSession::PromisePushResources(
const std::string& request_url,
const std::list<QuicBackendResponse::ServerPushInfo>& resources,
QuicStreamId original_stream_id,
+ const spdy::SpdyStreamPrecedence& original_precedence,
const spdy::SpdyHeaderBlock& original_request_headers) {
if (!server_push_enabled()) {
return;
@@ -78,10 +76,17 @@ void QuicSimpleServerSession::PromisePushResources(
request_url, resource, original_request_headers);
highest_promised_stream_id_ +=
QuicUtils::StreamIdDelta(connection()->transport_version());
+ if (VersionHasIetfQuicFrames(connection()->transport_version()) &&
+ highest_promised_stream_id_ > max_allowed_push_id()) {
+ return;
+ }
SendPushPromise(original_stream_id, highest_promised_stream_id_,
headers.Clone());
promised_streams_.push_back(PromisedStreamInfo(
- std::move(headers), highest_promised_stream_id_, resource.priority));
+ std::move(headers), highest_promised_stream_id_,
+ use_http2_priority_write_scheduler()
+ ? original_precedence
+ : spdy::SpdyStreamPrecedence(resource.priority)));
}
// Procese promised push request as many as possible.
@@ -216,7 +221,7 @@ void QuicSimpleServerSession::HandlePromisedPushRequests() {
DCHECK_EQ(promised_info.stream_id, promised_stream->id());
QUIC_DLOG(INFO) << "created server push stream " << promised_stream->id();
- promised_stream->SetPriority(promised_info.priority);
+ promised_stream->SetPriority(promised_info.precedence);
spdy::SpdyHeaderBlock request_headers(
std::move(promised_info.request_headers));
@@ -228,8 +233,19 @@ void QuicSimpleServerSession::HandlePromisedPushRequests() {
void QuicSimpleServerSession::OnCanCreateNewOutgoingStream(
bool unidirectional) {
+ QuicSpdySession::OnCanCreateNewOutgoingStream(unidirectional);
if (unidirectional) {
HandlePromisedPushRequests();
}
}
+
+void QuicSimpleServerSession::MaybeInitializeHttp3UnidirectionalStreams() {
+ size_t previous_static_stream_count = num_outgoing_static_streams();
+ QuicSpdySession::MaybeInitializeHttp3UnidirectionalStreams();
+ size_t current_static_stream_count = num_outgoing_static_streams();
+ DCHECK_GE(current_static_stream_count, previous_static_stream_count);
+ highest_promised_stream_id_ +=
+ QuicUtils::StreamIdDelta(transport_version()) *
+ (current_static_stream_count - previous_static_stream_count);
+}
} // namespace quic
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 d8cd6b5c539..d485e7c28dc 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
@@ -40,14 +40,14 @@ class QuicSimpleServerSession : public QuicServerSessionBase {
public:
PromisedStreamInfo(spdy::SpdyHeaderBlock request_headers,
QuicStreamId stream_id,
- spdy::SpdyPriority priority)
+ const spdy::SpdyStreamPrecedence& precedence)
: request_headers(std::move(request_headers)),
stream_id(stream_id),
- priority(priority),
+ precedence(precedence),
is_cancelled(false) {}
spdy::SpdyHeaderBlock request_headers;
QuicStreamId stream_id;
- spdy::SpdyPriority priority;
+ spdy::SpdyStreamPrecedence precedence;
bool is_cancelled;
};
@@ -76,6 +76,7 @@ class QuicSimpleServerSession : public QuicServerSessionBase {
const std::string& request_url,
const std::list<QuicBackendResponse::ServerPushInfo>& resources,
QuicStreamId original_stream_id,
+ const spdy::SpdyStreamPrecedence& original_precedence,
const spdy::SpdyHeaderBlock& original_request_headers);
void OnCanCreateNewOutgoingStream(bool unidirectional) override;
@@ -101,6 +102,8 @@ class QuicSimpleServerSession : public QuicServerSessionBase {
return quic_simple_server_backend_;
}
+ void MaybeInitializeHttp3UnidirectionalStreams() override;
+
private:
friend class test::QuicSimpleServerSessionPeer;
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session_test.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session_test.cc
index cef24b79a31..6cc97ed7098 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session_test.cc
@@ -198,13 +198,18 @@ class QuicSimpleServerSessionTest
QuicConfigPeer::SetReceivedMaxIncomingBidirectionalStreams(
&config_, kMaxStreamsForTest);
config_.SetMaxIncomingUnidirectionalStreamsToSend(kMaxStreamsForTest);
- QuicConfigPeer::SetReceivedMaxIncomingUnidirectionalStreams(
- &config_, kMaxStreamsForTest);
config_.SetInitialStreamFlowControlWindowToSend(
kInitialStreamFlowControlWindowForTest);
config_.SetInitialSessionFlowControlWindowToSend(
kInitialSessionFlowControlWindowForTest);
+ if (VersionUsesQpack(GetParam().transport_version)) {
+ QuicConfigPeer::SetReceivedMaxIncomingUnidirectionalStreams(
+ &config_, kMaxStreamsForTest + 3);
+ } else {
+ QuicConfigPeer::SetReceivedMaxIncomingUnidirectionalStreams(
+ &config_, kMaxStreamsForTest);
+ }
ParsedQuicVersionVector supported_versions = SupportedVersions(GetParam());
connection_ = new StrictMock<MockQuicConnectionWithSendStreamData>(
@@ -471,9 +476,11 @@ TEST_P(QuicSimpleServerSessionTest, CreateOutgoingDynamicStreamUptoLimit) {
EXPECT_EQ(1u, session_->GetNumOpenIncomingStreams());
EXPECT_EQ(0u, session_->GetNumOpenOutgoingStreams());
- session_->UnregisterStreamPriority(
- QuicUtils::GetHeadersStreamId(connection_->transport_version()),
- /*is_static=*/true);
+ if (!VersionUsesQpack(connection_->transport_version())) {
+ session_->UnregisterStreamPriority(
+ QuicUtils::GetHeadersStreamId(connection_->transport_version()),
+ /*is_static=*/true);
+ }
// Assume encryption already established.
QuicSimpleServerSessionPeer::SetCryptoStream(session_.get(), nullptr);
MockQuicCryptoServerStream* crypto_stream =
@@ -481,9 +488,12 @@ TEST_P(QuicSimpleServerSessionTest, CreateOutgoingDynamicStreamUptoLimit) {
session_.get(), &stream_helper_);
crypto_stream->set_encryption_established(true);
QuicSimpleServerSessionPeer::SetCryptoStream(session_.get(), crypto_stream);
- session_->RegisterStreamPriority(
- QuicUtils::GetHeadersStreamId(connection_->transport_version()),
- /*is_static=*/true, QuicStream::kDefaultPriority);
+ if (!VersionUsesQpack(connection_->transport_version())) {
+ session_->RegisterStreamPriority(
+ QuicUtils::GetHeadersStreamId(connection_->transport_version()),
+ /*is_static=*/true,
+ spdy::SpdyStreamPrecedence(QuicStream::kDefaultPriority));
+ }
// Create push streams till reaching the upper limit of allowed open streams.
for (size_t i = 0; i < kMaxStreamsForTest; ++i) {
@@ -491,7 +501,7 @@ TEST_P(QuicSimpleServerSessionTest, CreateOutgoingDynamicStreamUptoLimit) {
QuicSimpleServerSessionPeer::CreateOutgoingUnidirectionalStream(
session_.get());
if (VersionHasStreamType(connection_->transport_version())) {
- EXPECT_EQ(GetNthServerInitiatedUnidirectionalId(i + 1),
+ EXPECT_EQ(GetNthServerInitiatedUnidirectionalId(i + 3),
created_stream->id());
} else {
EXPECT_EQ(GetNthServerInitiatedUnidirectionalId(i), created_stream->id());
@@ -528,7 +538,7 @@ TEST_P(QuicSimpleServerSessionTest, GetEvenIncomingError) {
"Data for nonexistent stream", _));
EXPECT_EQ(nullptr,
QuicSessionPeer::GetOrCreateStream(
- session_.get(), GetNthServerInitiatedUnidirectionalId(1)));
+ session_.get(), GetNthServerInitiatedUnidirectionalId(3)));
}
// In order to test the case where server push stream creation goes beyond
@@ -574,9 +584,11 @@ class QuicSimpleServerSessionServerPushTest
visitor_ = QuicConnectionPeer::GetVisitor(connection_);
- session_->UnregisterStreamPriority(
- QuicUtils::GetHeadersStreamId(connection_->transport_version()),
- /*is_static=*/true);
+ if (!VersionUsesQpack(connection_->transport_version())) {
+ session_->UnregisterStreamPriority(
+ QuicUtils::GetHeadersStreamId(connection_->transport_version()),
+ /*is_static=*/true);
+ }
QuicSimpleServerSessionPeer::SetCryptoStream(session_.get(), nullptr);
// Assume encryption already established.
MockQuicCryptoServerStream* crypto_stream = new MockQuicCryptoServerStream(
@@ -585,9 +597,12 @@ class QuicSimpleServerSessionServerPushTest
crypto_stream->set_encryption_established(true);
QuicSimpleServerSessionPeer::SetCryptoStream(session_.get(), crypto_stream);
- session_->RegisterStreamPriority(
- QuicUtils::GetHeadersStreamId(connection_->transport_version()),
- /*is_static=*/true, QuicStream::kDefaultPriority);
+ if (!VersionUsesQpack(connection_->transport_version())) {
+ session_->RegisterStreamPriority(
+ QuicUtils::GetHeadersStreamId(connection_->transport_version()),
+ /*is_static=*/true,
+ spdy::SpdyStreamPrecedence(QuicStream::kDefaultPriority));
+ }
}
// Given |num_resources|, create this number of fake push resources and push
@@ -612,7 +627,7 @@ class QuicSimpleServerSessionServerPushTest
for (unsigned int i = 1; i <= num_resources; ++i) {
QuicStreamId stream_id;
if (VersionHasStreamType(connection_->transport_version())) {
- stream_id = GetNthServerInitiatedUnidirectionalId(i);
+ stream_id = GetNthServerInitiatedUnidirectionalId(i + 2);
} else {
stream_id = GetNthServerInitiatedUnidirectionalId(i - 1);
}
@@ -675,9 +690,10 @@ class QuicSimpleServerSessionServerPushTest
EXPECT_CALL(*session_, SendBlocked(stream_id));
}
}
- session_->PromisePushResources(request_url, push_resources,
- GetNthClientInitiatedBidirectionalId(0),
- request_headers);
+ session_->PromisePushResources(
+ request_url, push_resources, GetNthClientInitiatedBidirectionalId(0),
+ spdy::SpdyStreamPrecedence(0, spdy::kHttp2DefaultStreamWeight, false),
+ request_headers);
return data_frame_header_length;
}
@@ -700,6 +716,7 @@ INSTANTIATE_TEST_SUITE_P(Tests,
// opened and send push response.
TEST_P(QuicSimpleServerSessionServerPushTest, TestPromisePushResources) {
MaybeConsumeHeadersStreamData();
+ session_->set_max_allowed_push_id(kMaxQuicStreamId);
size_t num_resources = kMaxStreamsForTest + 5;
PromisePushResources(num_resources);
EXPECT_EQ(kMaxStreamsForTest, session_->GetNumOpenOutgoingStreams());
@@ -710,12 +727,13 @@ TEST_P(QuicSimpleServerSessionServerPushTest, TestPromisePushResources) {
TEST_P(QuicSimpleServerSessionServerPushTest,
HandlePromisedPushRequestsAfterStreamDraining) {
MaybeConsumeHeadersStreamData();
+ session_->set_max_allowed_push_id(kMaxQuicStreamId);
size_t num_resources = kMaxStreamsForTest + 1;
QuicByteCount data_frame_header_length = PromisePushResources(num_resources);
QuicStreamId next_out_going_stream_id;
if (VersionHasStreamType(connection_->transport_version())) {
next_out_going_stream_id =
- GetNthServerInitiatedUnidirectionalId(kMaxStreamsForTest + 1);
+ GetNthServerInitiatedUnidirectionalId(kMaxStreamsForTest + 3);
} else {
next_out_going_stream_id =
GetNthServerInitiatedUnidirectionalId(kMaxStreamsForTest);
@@ -760,11 +778,11 @@ TEST_P(QuicSimpleServerSessionServerPushTest,
// Version 99 also has unidirectional static streams, so we need to send
// MaxStreamFrame of the number of resources + number of static streams.
session_->OnMaxStreamsFrame(
- QuicMaxStreamsFrame(0, num_resources + 1, /*unidirectional=*/true));
+ QuicMaxStreamsFrame(0, num_resources + 3, /*unidirectional=*/true));
}
if (VersionHasStreamType(connection_->transport_version())) {
- session_->StreamDraining(GetNthServerInitiatedUnidirectionalId(1));
+ session_->StreamDraining(GetNthServerInitiatedUnidirectionalId(3));
} else {
session_->StreamDraining(GetNthServerInitiatedUnidirectionalId(0));
}
@@ -778,6 +796,7 @@ TEST_P(QuicSimpleServerSessionServerPushTest,
TEST_P(QuicSimpleServerSessionServerPushTest,
ResetPromisedStreamToCancelServerPush) {
MaybeConsumeHeadersStreamData();
+ session_->set_max_allowed_push_id(kMaxQuicStreamId);
// Having two extra resources to be send later. One of them will be reset, so
// when opened stream become close, only one will become open.
@@ -795,7 +814,7 @@ TEST_P(QuicSimpleServerSessionServerPushTest,
QuicStreamId stream_got_reset;
if (VersionHasStreamType(connection_->transport_version())) {
stream_got_reset =
- GetNthServerInitiatedUnidirectionalId(kMaxStreamsForTest + 2);
+ GetNthServerInitiatedUnidirectionalId(kMaxStreamsForTest + 4);
} else {
stream_got_reset =
GetNthServerInitiatedUnidirectionalId(kMaxStreamsForTest + 1);
@@ -815,7 +834,7 @@ TEST_P(QuicSimpleServerSessionServerPushTest,
QuicStreamId stream_not_reset;
if (VersionHasStreamType(connection_->transport_version())) {
stream_not_reset =
- GetNthServerInitiatedUnidirectionalId(kMaxStreamsForTest + 1);
+ GetNthServerInitiatedUnidirectionalId(kMaxStreamsForTest + 3);
} else {
stream_not_reset =
GetNthServerInitiatedUnidirectionalId(kMaxStreamsForTest);
@@ -855,10 +874,10 @@ TEST_P(QuicSimpleServerSessionServerPushTest,
// For pre-v-99, the node monitors its own stream usage and makes streams
// available as it closes/etc them.
session_->OnMaxStreamsFrame(
- QuicMaxStreamsFrame(0, num_resources + 1, /*unidirectional=*/true));
+ QuicMaxStreamsFrame(0, num_resources + 3, /*unidirectional=*/true));
}
- session_->StreamDraining(GetNthServerInitiatedUnidirectionalId(1));
- session_->StreamDraining(GetNthServerInitiatedUnidirectionalId(2));
+ session_->StreamDraining(GetNthServerInitiatedUnidirectionalId(3));
+ session_->StreamDraining(GetNthServerInitiatedUnidirectionalId(4));
}
// Tests that closing a open outgoing stream can trigger a promised resource in
@@ -866,6 +885,7 @@ TEST_P(QuicSimpleServerSessionServerPushTest,
TEST_P(QuicSimpleServerSessionServerPushTest,
CloseStreamToHandleMorePromisedStream) {
MaybeConsumeHeadersStreamData();
+ session_->set_max_allowed_push_id(kMaxQuicStreamId);
size_t num_resources = kMaxStreamsForTest + 1;
if (VersionHasIetfQuicFrames(transport_version())) {
// V99 will send out a stream-id-blocked frame when the we desired to exceed
@@ -878,14 +898,14 @@ TEST_P(QuicSimpleServerSessionServerPushTest,
QuicStreamId stream_to_open;
if (VersionHasStreamType(connection_->transport_version())) {
stream_to_open =
- GetNthServerInitiatedUnidirectionalId(kMaxStreamsForTest + 1);
+ GetNthServerInitiatedUnidirectionalId(kMaxStreamsForTest + 3);
} else {
stream_to_open = GetNthServerInitiatedUnidirectionalId(kMaxStreamsForTest);
}
// Resetting an open stream will close the stream and give space for extra
// stream to be opened.
- QuicStreamId stream_got_reset = GetNthServerInitiatedUnidirectionalId(1);
+ QuicStreamId stream_got_reset = GetNthServerInitiatedUnidirectionalId(3);
EXPECT_CALL(owner_, OnRstStreamReceived(_)).Times(1);
EXPECT_CALL(*connection_, SendControlFrame(_));
if (!VersionHasIetfQuicFrames(transport_version())) {
@@ -929,7 +949,7 @@ TEST_P(QuicSimpleServerSessionServerPushTest,
// For pre-v-99, the node monitors its own stream usage and makes streams
// available as it closes/etc them.
session_->OnMaxStreamsFrame(
- QuicMaxStreamsFrame(0, num_resources + 1, /*unidirectional=*/true));
+ QuicMaxStreamsFrame(0, num_resources + 3, /*unidirectional=*/true));
}
visitor_->OnRstStream(rst);
// Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a
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 f8522060af2..26ea62afc8f 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
@@ -239,7 +239,7 @@ void QuicSimpleServerStream::OnResponseBackendComplete(
<< " push resources.";
QuicSimpleServerSession* session =
static_cast<QuicSimpleServerSession*>(spdy_session());
- session->PromisePushResources(request_url, resources, id(),
+ session->PromisePushResources(request_url, resources, id(), precedence(),
request_headers_);
}
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 7bac18ec95b..55ea842e69f 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
@@ -133,7 +133,8 @@ class MockQuicSimpleServerSession : public QuicSimpleServerSession {
size_t frame_len,
const QuicHeaderList& header_list));
MOCK_METHOD2(OnStreamHeadersPriority,
- void(QuicStreamId stream_id, spdy::SpdyPriority priority));
+ void(QuicStreamId stream_id,
+ const spdy::SpdyStreamPrecedence& precedence));
MOCK_METHOD3(SendRstStream,
void(QuicStreamId stream_id,
QuicRstStreamErrorCode error,
@@ -144,15 +145,17 @@ class MockQuicSimpleServerSession : public QuicSimpleServerSession {
const std::string& request_url,
const std::list<QuicBackendResponse::ServerPushInfo>& resources,
QuicStreamId original_stream_id,
+ const spdy::SpdyStreamPrecedence& original_precedence,
const spdy::SpdyHeaderBlock& original_request_headers) override {
original_request_headers_ = original_request_headers.Clone();
PromisePushResourcesMock(request_url, resources, original_stream_id,
- original_request_headers);
+ original_precedence, original_request_headers);
}
- MOCK_METHOD4(PromisePushResourcesMock,
+ MOCK_METHOD5(PromisePushResourcesMock,
void(const std::string&,
const std::list<QuicBackendResponse::ServerPushInfo>&,
QuicStreamId,
+ const spdy::SpdyStreamPrecedence&,
const spdy::SpdyHeaderBlock&));
using QuicSession::ActivateStream;
@@ -201,6 +204,7 @@ class QuicSimpleServerStreamTest : public QuicTestWithParam<ParsedQuicVersion> {
kInitialStreamFlowControlWindowForTest);
session_.config()->SetInitialSessionFlowControlWindowToSend(
kInitialSessionFlowControlWindowForTest);
+ session_.Initialize();
stream_ = new StrictMock<TestStream>(
GetNthClientInitiatedBidirectionalStreamId(
connection_->transport_version(), 0),
@@ -413,7 +417,7 @@ TEST_P(QuicSimpleServerStreamTest, SendPushResponseWith404Response) {
// Create a new promised stream with even id().
auto promised_stream = new StrictMock<TestStream>(
GetNthServerInitiatedUnidirectionalStreamId(
- connection_->transport_version(), 0),
+ connection_->transport_version(), 3),
&session_, WRITE_UNIDIRECTIONAL, &memory_cache_backend_);
session_.ActivateStream(QuicWrapUnique(promised_stream));
@@ -514,7 +518,7 @@ TEST_P(QuicSimpleServerStreamTest, SendResponseWithPushResources) {
host + request_path, _,
GetNthClientInitiatedBidirectionalStreamId(
connection_->transport_version(), 0),
- _));
+ _, _));
EXPECT_CALL(*stream_, WriteHeadersMock(false));
if (HasFrameHeader()) {
EXPECT_CALL(session_, WritevData(_, _, header_length, _, NO_FIN));
@@ -549,7 +553,7 @@ TEST_P(QuicSimpleServerStreamTest, PushResponseOnServerInitiatedStream) {
// Create a stream with even stream id and test against this stream.
const QuicStreamId kServerInitiatedStreamId =
GetNthServerInitiatedUnidirectionalStreamId(
- connection_->transport_version(), 0);
+ connection_->transport_version(), 3);
// Create a server initiated stream and pass it to session_.
auto server_initiated_stream =
new StrictMock<TestStream>(kServerInitiatedStreamId, &session_,
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_spdy_client_base.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_spdy_client_base.cc
index 3a3bafe2f3e..09a1998a802 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_spdy_client_base.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_spdy_client_base.cc
@@ -174,7 +174,8 @@ QuicSpdyClientStream* QuicSpdyClientBase::CreateClientStream() {
auto* stream = static_cast<QuicSpdyClientStream*>(
client_session()->CreateOutgoingBidirectionalStream());
if (stream) {
- stream->SetPriority(QuicStream::kDefaultPriority);
+ stream->SetPriority(
+ spdy::SpdyStreamPrecedence(QuicStream::kDefaultPriority));
stream->set_visitor(this);
}
return stream;
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.cc
index 319d3a2d2ec..09e7a50d571 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.cc
@@ -111,13 +111,11 @@ DEFINE_QUIC_COMMAND_LINE_FLAG(
"versions are offered in the handshake. Also supports wire versions "
"such as Q043 or T099.");
-DEFINE_QUIC_COMMAND_LINE_FLAG(
- int32_t,
- quic_ietf_draft,
- 0,
- "QUIC IETF draft number to use over the wire, e.g. 18. "
- "By default this sets quic_version to T099. "
- "This also enables required internal QUIC flags.");
+DEFINE_QUIC_COMMAND_LINE_FLAG(bool,
+ quic_ietf_draft,
+ false,
+ "Use the IETF draft version. This also enables "
+ "required internal QUIC flags.");
DEFINE_QUIC_COMMAND_LINE_FLAG(
bool,
@@ -183,14 +181,12 @@ int QuicToyClient::SendRequestsAndPrintResponses(
quic::ParsedQuicVersionVector versions = quic::CurrentSupportedVersions();
std::string quic_version_string = GetQuicFlag(FLAGS_quic_version);
- const int32_t quic_ietf_draft = GetQuicFlag(FLAGS_quic_ietf_draft);
- if (quic_ietf_draft > 0) {
- quic::QuicVersionInitializeSupportForIetfDraft(quic_ietf_draft);
- if (quic_version_string.length() == 0) {
- quic_version_string = "T099";
- }
- }
- if (quic_version_string.length() > 0) {
+ if (GetQuicFlag(FLAGS_quic_ietf_draft)) {
+ quic::QuicVersionInitializeSupportForIetfDraft();
+ versions = {{quic::PROTOCOL_TLS1_3, quic::QUIC_VERSION_99}};
+ quic::QuicEnableVersion(versions[0]);
+
+ } else if (!quic_version_string.empty()) {
if (quic_version_string[0] == 'T') {
// ParseQuicVersionString checks quic_supports_tls_handshake.
SetQuicFlag(FLAGS_quic_supports_tls_handshake, true);
@@ -201,8 +197,7 @@ int QuicToyClient::SendRequestsAndPrintResponses(
quic::QUIC_VERSION_UNSUPPORTED) {
return 1;
}
- versions.clear();
- versions.push_back(parsed_quic_version);
+ versions = {parsed_quic_version};
quic::QuicEnableVersion(parsed_quic_version);
}
@@ -216,7 +211,7 @@ int QuicToyClient::SendRequestsAndPrintResponses(
if (GetQuicFlag(FLAGS_disable_certificate_verification)) {
proof_verifier = quic::QuicMakeUnique<FakeProofVerifier>();
} else {
- proof_verifier = quic::CreateDefaultProofVerifier();
+ proof_verifier = quic::CreateDefaultProofVerifier(url.host());
}
// Build the client, and try to connect.
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_toy_server.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_toy_server.cc
index 633b465960e..9fb15eb87e5 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_toy_server.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_toy_server.cc
@@ -26,12 +26,11 @@ DEFINE_QUIC_COMMAND_LINE_FLAG(
"construction to seed the cache. Cache directory can be "
"generated using `wget -p --save-headers <url>`");
-DEFINE_QUIC_COMMAND_LINE_FLAG(
- int32_t,
- quic_ietf_draft,
- 0,
- "QUIC IETF draft number to use over the wire, e.g. 18. "
- "This also enables required internal QUIC flags.");
+DEFINE_QUIC_COMMAND_LINE_FLAG(bool,
+ quic_ietf_draft,
+ false,
+ "Use the IETF draft version. This also enables "
+ "required internal QUIC flags.");
namespace quic {
@@ -50,9 +49,8 @@ QuicToyServer::QuicToyServer(BackendFactory* backend_factory,
: backend_factory_(backend_factory), server_factory_(server_factory) {}
int QuicToyServer::Start() {
- const int32_t quic_ietf_draft = GetQuicFlag(FLAGS_quic_ietf_draft);
- if (quic_ietf_draft > 0) {
- quic::QuicVersionInitializeSupportForIetfDraft(quic_ietf_draft);
+ if (GetQuicFlag(FLAGS_quic_ietf_draft)) {
+ QuicVersionInitializeSupportForIetfDraft();
quic::QuicEnableVersion(
quic::ParsedQuicVersion(quic::PROTOCOL_TLS1_3, quic::QUIC_VERSION_99));
}
diff --git a/chromium/net/third_party/quiche/src/spdy/core/fifo_write_scheduler.h b/chromium/net/third_party/quiche/src/spdy/core/fifo_write_scheduler.h
new file mode 100644
index 00000000000..aa904f6d740
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/spdy/core/fifo_write_scheduler.h
@@ -0,0 +1,220 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_SPDY_CORE_FIFO_WRITE_SCHEDULER_H_
+#define QUICHE_SPDY_CORE_FIFO_WRITE_SCHEDULER_H_
+
+#include <map>
+#include <set>
+#include <string>
+
+#include "net/third_party/quiche/src/spdy/core/write_scheduler.h"
+#include "net/third_party/quiche/src/spdy/platform/api/spdy_string_utils.h"
+
+namespace spdy {
+
+// A write scheduler where the stream with the smallest stream ID will have the
+// highest priority.
+template <typename StreamIdType>
+class FifoWriteScheduler : public WriteScheduler<StreamIdType> {
+ public:
+ using typename WriteScheduler<StreamIdType>::StreamPrecedenceType;
+
+ FifoWriteScheduler() = default;
+
+ // WriteScheduler methods
+ void RegisterStream(StreamIdType stream_id,
+ const StreamPrecedenceType& precedence) override;
+ void UnregisterStream(StreamIdType stream_id) override;
+ bool StreamRegistered(StreamIdType stream_id) const override;
+ StreamPrecedenceType GetStreamPrecedence(
+ StreamIdType stream_id) const override;
+ void UpdateStreamPrecedence(StreamIdType stream_id,
+ const StreamPrecedenceType& precedence) override;
+ std::vector<StreamIdType> GetStreamChildren(
+ StreamIdType stream_id) const override;
+ void RecordStreamEventTime(StreamIdType stream_id,
+ int64_t now_in_usec) override;
+ int64_t GetLatestEventWithPrecedence(StreamIdType stream_id) const override;
+ bool ShouldYield(StreamIdType stream_id) const override;
+ void MarkStreamReady(StreamIdType stream_id, bool add_to_front) override;
+ void MarkStreamNotReady(StreamIdType stream_id) override;
+ bool HasReadyStreams() const override;
+ StreamIdType PopNextReadyStream() override;
+ std::tuple<StreamIdType, StreamPrecedenceType>
+ PopNextReadyStreamAndPrecedence() override;
+ size_t NumReadyStreams() const override;
+ bool IsStreamReady(StreamIdType stream_id) const override;
+ size_t NumRegisteredStreams() const override;
+ std::string DebugString() const override;
+
+ private:
+ std::set<StreamIdType> ready_streams_;
+ // This map maps stream ID to read/write event time (us since Unix epoch).
+ std::map<StreamIdType, int64_t> registered_streams_;
+};
+
+template <typename StreamIdType>
+void FifoWriteScheduler<StreamIdType>::RegisterStream(
+ StreamIdType stream_id,
+ const StreamPrecedenceType& /*precedence*/) {
+ if (StreamRegistered(stream_id)) {
+ SPDY_BUG << "Stream " << stream_id << " already registered";
+ return;
+ }
+ registered_streams_.emplace_hint(registered_streams_.end(), stream_id, 0);
+}
+
+template <typename StreamIdType>
+void FifoWriteScheduler<StreamIdType>::UnregisterStream(
+ StreamIdType stream_id) {
+ if (!StreamRegistered(stream_id)) {
+ SPDY_BUG << "Stream " << stream_id << " is not registered";
+ return;
+ }
+ registered_streams_.erase(stream_id);
+ ready_streams_.erase(stream_id);
+}
+
+template <typename StreamIdType>
+bool FifoWriteScheduler<StreamIdType>::StreamRegistered(
+ StreamIdType stream_id) const {
+ return registered_streams_.find(stream_id) != registered_streams_.end();
+}
+
+// Stream precedence is not supported by this scheduler.
+template <typename StreamIdType>
+typename FifoWriteScheduler<StreamIdType>::StreamPrecedenceType
+FifoWriteScheduler<StreamIdType>::GetStreamPrecedence(
+ StreamIdType /*stream_id*/) const {
+ return StreamPrecedenceType(kV3LowestPriority);
+}
+
+template <typename StreamIdType>
+void FifoWriteScheduler<StreamIdType>::UpdateStreamPrecedence(
+ StreamIdType /*stream_id*/,
+ const StreamPrecedenceType& /*precedence*/) {}
+
+template <typename StreamIdType>
+std::vector<StreamIdType> FifoWriteScheduler<StreamIdType>::GetStreamChildren(
+ StreamIdType /*stream_id*/) const {
+ return std::vector<StreamIdType>();
+}
+
+template <typename StreamIdType>
+void FifoWriteScheduler<StreamIdType>::RecordStreamEventTime(
+ StreamIdType stream_id,
+ int64_t now_in_usec) {
+ auto it = registered_streams_.find(stream_id);
+ if (it != registered_streams_.end()) {
+ it->second = now_in_usec;
+ } else {
+ SPDY_BUG << "Stream " << stream_id << " is not registered";
+ }
+}
+
+template <typename StreamIdType>
+int64_t FifoWriteScheduler<StreamIdType>::GetLatestEventWithPrecedence(
+ StreamIdType stream_id) const {
+ if (!StreamRegistered(stream_id)) {
+ SPDY_BUG << "Stream " << stream_id << " is not registered";
+ return 0;
+ }
+ int64_t latest_event_time_us = 0;
+ for (auto it = registered_streams_.begin(); it != registered_streams_.end();
+ ++it) {
+ if (stream_id <= it->first) {
+ break;
+ }
+ latest_event_time_us = std::max(latest_event_time_us, it->second);
+ }
+ return latest_event_time_us;
+}
+
+template <typename StreamIdType>
+bool FifoWriteScheduler<StreamIdType>::ShouldYield(
+ StreamIdType stream_id) const {
+ return !ready_streams_.empty() && stream_id > *ready_streams_.begin();
+}
+
+template <typename StreamIdType>
+void FifoWriteScheduler<StreamIdType>::MarkStreamReady(StreamIdType stream_id,
+ bool /*add_to_front*/) {
+ if (!StreamRegistered(stream_id)) {
+ SPDY_BUG << "Stream " << stream_id << " is not registered";
+ return;
+ }
+ if (ready_streams_.find(stream_id) != ready_streams_.end()) {
+ SPDY_DVLOG(1) << "Stream already exists in the list";
+ return;
+ }
+ ready_streams_.insert(stream_id);
+}
+
+template <typename StreamIdType>
+void FifoWriteScheduler<StreamIdType>::MarkStreamNotReady(
+ StreamIdType stream_id) {
+ auto it = ready_streams_.find(stream_id);
+ if (it == ready_streams_.end()) {
+ SPDY_DVLOG(1) << "Try to remove a stream that is not on list";
+ return;
+ }
+ ready_streams_.erase(it);
+}
+
+template <typename StreamIdType>
+bool FifoWriteScheduler<StreamIdType>::HasReadyStreams() const {
+ return !ready_streams_.empty();
+}
+
+template <typename StreamIdType>
+StreamIdType FifoWriteScheduler<StreamIdType>::PopNextReadyStream() {
+ if (ready_streams_.empty()) {
+ SPDY_BUG << "No ready streams available";
+ return 0;
+ }
+ auto it = ready_streams_.begin();
+ StreamIdType id = *it;
+ ready_streams_.erase(it);
+ return id;
+}
+
+template <typename StreamIdType>
+std::tuple<StreamIdType,
+ typename FifoWriteScheduler<StreamIdType>::StreamPrecedenceType>
+FifoWriteScheduler<StreamIdType>::PopNextReadyStreamAndPrecedence() {
+ return std::make_tuple(PopNextReadyStream(),
+ StreamPrecedenceType(kV3LowestPriority));
+}
+
+template <typename StreamIdType>
+size_t FifoWriteScheduler<StreamIdType>::NumReadyStreams() const {
+ return ready_streams_.size();
+}
+
+template <typename StreamIdType>
+bool FifoWriteScheduler<StreamIdType>::IsStreamReady(
+ StreamIdType stream_id) const {
+ if (!StreamRegistered(stream_id)) {
+ SPDY_BUG << "Stream " << stream_id << " is not registered";
+ return false;
+ }
+ return ready_streams_.find(stream_id) != ready_streams_.end();
+}
+
+template <typename StreamIdType>
+size_t FifoWriteScheduler<StreamIdType>::NumRegisteredStreams() const {
+ return registered_streams_.size();
+}
+
+template <typename StreamIdType>
+std::string FifoWriteScheduler<StreamIdType>::DebugString() const {
+ return SpdyStrCat(
+ "FifoWriteScheduler {num_streams=", registered_streams_.size(),
+ " num_ready_streams=", NumReadyStreams(), "}");
+}
+
+} // namespace spdy
+
+#endif // QUICHE_SPDY_CORE_FIFO_WRITE_SCHEDULER_H_
diff --git a/chromium/net/third_party/quiche/src/spdy/core/fifo_write_scheduler_test.cc b/chromium/net/third_party/quiche/src/spdy/core/fifo_write_scheduler_test.cc
new file mode 100644
index 00000000000..1ad6d62049d
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/spdy/core/fifo_write_scheduler_test.cc
@@ -0,0 +1,85 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/spdy/core/fifo_write_scheduler.h"
+
+#include "net/third_party/quiche/src/spdy/platform/api/spdy_test.h"
+#include "net/third_party/quiche/src/spdy/platform/api/spdy_test_helpers.h"
+
+namespace spdy {
+
+namespace test {
+
+TEST(FifoWriteSchedulerTest, BasicTest) {
+ FifoWriteScheduler<SpdyStreamId> fifo;
+ EXPECT_FALSE(fifo.HasReadyStreams());
+ EXPECT_SPDY_BUG(
+ EXPECT_EQ(0u, std::get<0>(fifo.PopNextReadyStreamAndPrecedence())),
+ "No ready streams available");
+ EXPECT_SPDY_BUG(fifo.MarkStreamReady(9, true), "Stream 9 is not registered");
+ EXPECT_SPDY_BUG(fifo.IsStreamReady(9), "Stream 9 is not registered");
+
+ SpdyStreamPrecedence precedence(1);
+ fifo.RegisterStream(3, precedence);
+ EXPECT_FALSE(fifo.IsStreamReady(3));
+ fifo.RegisterStream(9, precedence);
+ fifo.RegisterStream(7, precedence);
+ fifo.RegisterStream(11, precedence);
+ fifo.RegisterStream(13, precedence);
+ fifo.RegisterStream(15, precedence);
+ fifo.RegisterStream(17, precedence);
+ EXPECT_EQ(7u, fifo.NumRegisteredStreams());
+ EXPECT_FALSE(fifo.HasReadyStreams());
+
+ fifo.MarkStreamReady(9, true);
+ EXPECT_TRUE(fifo.IsStreamReady(9));
+ EXPECT_TRUE(fifo.HasReadyStreams());
+ fifo.MarkStreamReady(15, true);
+ fifo.MarkStreamReady(7, true);
+ fifo.MarkStreamReady(13, true);
+ fifo.MarkStreamReady(11, true);
+ fifo.MarkStreamReady(3, true);
+ fifo.MarkStreamReady(17, true);
+ EXPECT_EQ(7u, fifo.NumReadyStreams());
+
+ EXPECT_EQ(3u, fifo.PopNextReadyStream());
+ EXPECT_EQ(7u, std::get<0>(fifo.PopNextReadyStreamAndPrecedence()));
+ EXPECT_EQ(5u, fifo.NumReadyStreams());
+
+ EXPECT_FALSE(fifo.ShouldYield(3));
+ EXPECT_FALSE(fifo.ShouldYield(9));
+ EXPECT_TRUE(fifo.ShouldYield(13));
+ EXPECT_TRUE(fifo.ShouldYield(10));
+
+ fifo.MarkStreamNotReady(9);
+ EXPECT_EQ(4u, fifo.NumReadyStreams());
+ EXPECT_FALSE(fifo.ShouldYield(10));
+ EXPECT_TRUE(fifo.ShouldYield(12));
+}
+
+TEST(FifoWriteSchedulerTest, GetLatestEventTest) {
+ FifoWriteScheduler<SpdyStreamId> fifo;
+
+ SpdyStreamPrecedence precedence(1);
+ fifo.RegisterStream(1, precedence);
+ fifo.RegisterStream(3, precedence);
+ fifo.RegisterStream(5, precedence);
+ fifo.RegisterStream(7, precedence);
+ fifo.RegisterStream(9, precedence);
+ fifo.RecordStreamEventTime(1, 3);
+ fifo.RecordStreamEventTime(3, 2);
+ fifo.RecordStreamEventTime(5, 4);
+ fifo.RecordStreamEventTime(7, 8);
+ fifo.RecordStreamEventTime(9, 1);
+
+ EXPECT_EQ(8, fifo.GetLatestEventWithPrecedence(9));
+ EXPECT_EQ(4, fifo.GetLatestEventWithPrecedence(7));
+ EXPECT_EQ(3, fifo.GetLatestEventWithPrecedence(5));
+ EXPECT_EQ(3, fifo.GetLatestEventWithPrecedence(3));
+ EXPECT_EQ(0, fifo.GetLatestEventWithPrecedence(1));
+}
+
+} // namespace test
+
+} // namespace spdy
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 d016841f077..da3a56c6648 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
@@ -8,6 +8,7 @@
#include <stdint.h>
+#include <string>
#include <tuple>
#include <utility>
#include <vector>
@@ -22,7 +23,6 @@
#include "net/third_party/quiche/src/spdy/core/spdy_test_utils.h"
#include "net/third_party/quiche/src/spdy/platform/api/spdy_arraysize.h"
#include "net/third_party/quiche/src/spdy/platform/api/spdy_logging.h"
-#include "net/third_party/quiche/src/spdy/platform/api/spdy_string.h"
#include "net/third_party/quiche/src/spdy/platform/api/spdy_string_utils.h"
#include "net/third_party/quiche/src/spdy/platform/api/spdy_test.h"
@@ -231,8 +231,8 @@ class HpackDecoderAdapterTest
void expectEntry(size_t index,
size_t size,
- const SpdyString& name,
- const SpdyString& value) {
+ const std::string& name,
+ const std::string& value) {
const HpackStringPair* entry = decoder_peer_.GetTableEntry(index);
EXPECT_EQ(name, entry->name) << "index " << index;
EXPECT_EQ(value, entry->value);
@@ -240,7 +240,7 @@ class HpackDecoderAdapterTest
}
SpdyHeaderBlock MakeHeaderBlock(
- const std::vector<std::pair<SpdyString, SpdyString>>& headers) {
+ const std::vector<std::pair<std::string, std::string>>& headers) {
SpdyHeaderBlock result;
for (const auto& kv : headers) {
result.AppendValueOrAddHeader(kv.first, kv.second);
@@ -277,12 +277,12 @@ TEST_P(HpackDecoderAdapterTest,
// limit is rejected.
HandleControlFrameHeadersStart();
const size_t kMaxBufferSizeBytes = 50;
- const SpdyString a_value = SpdyString(49, 'x');
+ const std::string a_value = std::string(49, 'x');
decoder_.set_max_decode_buffer_size_bytes(kMaxBufferSizeBytes);
HpackBlockBuilder hbb;
hbb.AppendLiteralNameAndValue(HpackEntryType::kNeverIndexedLiteralHeader,
false, "a", false, a_value);
- const SpdyString& s = hbb.buffer();
+ const std::string& s = hbb.buffer();
EXPECT_GT(s.size(), kMaxBufferSizeBytes);
// Any one in input buffer must not exceed kMaxBufferSizeBytes.
@@ -297,8 +297,8 @@ TEST_P(HpackDecoderAdapterTest,
TEST_P(HpackDecoderAdapterTest, NameTooLong) {
// Verify that a name longer than the allowed size generates an error.
const size_t kMaxBufferSizeBytes = 50;
- const SpdyString name = SpdyString(2 * kMaxBufferSizeBytes, 'x');
- const SpdyString value = "abc";
+ const std::string name = std::string(2 * kMaxBufferSizeBytes, 'x');
+ const std::string value = "abc";
decoder_.set_max_decode_buffer_size_bytes(kMaxBufferSizeBytes);
@@ -307,7 +307,7 @@ TEST_P(HpackDecoderAdapterTest, NameTooLong) {
false, name, false, value);
const size_t fragment_size = (3 * kMaxBufferSizeBytes) / 2;
- const SpdyString fragment = hbb.buffer().substr(0, fragment_size);
+ const std::string fragment = hbb.buffer().substr(0, fragment_size);
HandleControlFrameHeadersStart();
EXPECT_FALSE(HandleControlFrameHeadersData(fragment));
@@ -316,8 +316,8 @@ TEST_P(HpackDecoderAdapterTest, NameTooLong) {
TEST_P(HpackDecoderAdapterTest, HeaderTooLongToBuffer) {
// Verify that a header longer than the allowed size generates an error if
// it isn't all in one input buffer.
- const SpdyString name = "some-key";
- const SpdyString value = "some-value";
+ const std::string name = "some-key";
+ const std::string value = "some-value";
const size_t kMaxBufferSizeBytes = name.size() + value.size() - 2;
decoder_.set_max_decode_buffer_size_bytes(kMaxBufferSizeBytes);
@@ -325,7 +325,7 @@ TEST_P(HpackDecoderAdapterTest, HeaderTooLongToBuffer) {
hbb.AppendLiteralNameAndValue(HpackEntryType::kNeverIndexedLiteralHeader,
false, name, false, value);
const size_t fragment_size = hbb.size() - 1;
- const SpdyString fragment = hbb.buffer().substr(0, fragment_size);
+ const std::string fragment = hbb.buffer().substr(0, fragment_size);
HandleControlFrameHeadersStart();
EXPECT_FALSE(HandleControlFrameHeadersData(fragment));
@@ -333,8 +333,8 @@ TEST_P(HpackDecoderAdapterTest, HeaderTooLongToBuffer) {
// Verify that a header block that exceeds the maximum length is rejected.
TEST_P(HpackDecoderAdapterTest, HeaderBlockTooLong) {
- const SpdyString name = "some-key";
- const SpdyString value = "some-value";
+ const std::string name = "some-key";
+ const std::string value = "some-value";
const size_t kMaxBufferSizeBytes = 1024;
HpackBlockBuilder hbb;
@@ -364,7 +364,7 @@ TEST_P(HpackDecoderAdapterTest, DecodeWithIncompleteData) {
// No need to wait for more data.
EXPECT_TRUE(HandleControlFrameHeadersData("\x82\x85\x82"));
- std::vector<std::pair<SpdyString, SpdyString>> expected_headers = {
+ std::vector<std::pair<std::string, std::string>> expected_headers = {
{":method", "GET"}, {":path", "/index.html"}, {":method", "GET"}};
SpdyHeaderBlock expected_block1 = MakeHeaderBlock(expected_headers);
@@ -405,7 +405,7 @@ TEST_P(HpackDecoderAdapterTest, HandleHeaderRepresentation) {
// Already-delimited headers are passed through.
decoder_peer_.HandleHeaderRepresentation("passed-through",
- SpdyString("foo\0baz", 7));
+ std::string("foo\0baz", 7));
// Other headers are joined on \0. Case matters.
decoder_peer_.HandleHeaderRepresentation("joined", "not joined");
@@ -492,7 +492,7 @@ TEST_P(HpackDecoderAdapterTest, InvalidIndexedHeader) {
TEST_P(HpackDecoderAdapterTest, ContextUpdateMaximumSize) {
EXPECT_EQ(kDefaultHeaderTableSizeSetting,
decoder_peer_.header_table_size_limit());
- SpdyString input;
+ std::string input;
{
// Maximum-size update with size 126. Succeeds.
HpackOutputStream output_stream;
@@ -529,7 +529,7 @@ TEST_P(HpackDecoderAdapterTest, ContextUpdateMaximumSize) {
// Two HeaderTableSizeUpdates may appear at the beginning of the block
TEST_P(HpackDecoderAdapterTest, TwoTableSizeUpdates) {
- SpdyString input;
+ std::string input;
{
// Should accept two table size updates, update to second one
HpackOutputStream output_stream;
@@ -546,7 +546,7 @@ TEST_P(HpackDecoderAdapterTest, TwoTableSizeUpdates) {
// Three HeaderTableSizeUpdates should result in an error
TEST_P(HpackDecoderAdapterTest, ThreeTableSizeUpdatesError) {
- SpdyString input;
+ std::string input;
{
// Should reject three table size updates, update to second one
HpackOutputStream output_stream;
@@ -567,7 +567,7 @@ TEST_P(HpackDecoderAdapterTest, ThreeTableSizeUpdatesError) {
// HeaderTableSizeUpdates may only appear at the beginning of the block
// Any other updates should result in an error
TEST_P(HpackDecoderAdapterTest, TableSizeUpdateSecondError) {
- SpdyString input;
+ std::string input;
{
// Should reject a table size update appearing after a different entry
// The table size should remain as the default
@@ -587,7 +587,7 @@ TEST_P(HpackDecoderAdapterTest, TableSizeUpdateSecondError) {
// HeaderTableSizeUpdates may only appear at the beginning of the block
// Any other updates should result in an error
TEST_P(HpackDecoderAdapterTest, TableSizeUpdateFirstThirdError) {
- SpdyString input;
+ std::string input;
{
// Should reject the second table size update
// if a different entry appears after the first update
@@ -678,7 +678,7 @@ TEST_P(HpackDecoderAdapterTest, TruncatedHuffmanLiteral) {
// | www.example.com
// | -> :authority: www.example.com
- SpdyString first = SpdyHexDecode("418cf1e3c2e5f23a6ba0ab90f4ff");
+ std::string first = SpdyHexDecode("418cf1e3c2e5f23a6ba0ab90f4ff");
EXPECT_TRUE(DecodeHeaderBlock(first));
first.pop_back();
EXPECT_FALSE(DecodeHeaderBlock(first));
@@ -698,7 +698,7 @@ TEST_P(HpackDecoderAdapterTest, HuffmanEOSError) {
// | www.example.com
// | -> :authority: www.example.com
- SpdyString first = SpdyHexDecode("418cf1e3c2e5f23a6ba0ab90f4ff");
+ std::string first = SpdyHexDecode("418cf1e3c2e5f23a6ba0ab90f4ff");
EXPECT_TRUE(DecodeHeaderBlock(first));
first = SpdyHexDecode("418df1e3c2e5f23a6ba0ab90f4ffff");
EXPECT_FALSE(DecodeHeaderBlock(first));
@@ -715,7 +715,7 @@ TEST_P(HpackDecoderAdapterTest, BasicC31) {
expected_header_set[":path"] = "/";
expected_header_set[":authority"] = "www.example.com";
- SpdyString encoded_header_set;
+ std::string encoded_header_set;
EXPECT_TRUE(
encoder.EncodeHeaderSet(expected_header_set, &encoded_header_set));
@@ -747,7 +747,7 @@ TEST_P(HpackDecoderAdapterTest, SectionC4RequestHuffmanExamples) {
// | Decoded:
// | www.example.com
// | -> :authority: www.example.com
- SpdyString first = SpdyHexDecode("828684418cf1e3c2e5f23a6ba0ab90f4ff");
+ std::string first = SpdyHexDecode("828684418cf1e3c2e5f23a6ba0ab90f4ff");
const SpdyHeaderBlock& first_header_set = DecodeBlockExpectingSuccess(first);
EXPECT_THAT(first_header_set,
@@ -784,7 +784,7 @@ TEST_P(HpackDecoderAdapterTest, SectionC4RequestHuffmanExamples) {
// | no-cache
// | -> cache-control: no-cache
- SpdyString second = SpdyHexDecode("828684be5886a8eb10649cbf");
+ std::string second = SpdyHexDecode("828684be5886a8eb10649cbf");
const SpdyHeaderBlock& second_header_set =
DecodeBlockExpectingSuccess(second);
@@ -826,7 +826,7 @@ TEST_P(HpackDecoderAdapterTest, SectionC4RequestHuffmanExamples) {
// | Decoded:
// | custom-value
// | -> custom-key: custom-value
- SpdyString third =
+ std::string third =
SpdyHexDecode("828785bf408825a849e95ba97d7f8925a849e95bb8e8b4bf");
const SpdyHeaderBlock& third_header_set = DecodeBlockExpectingSuccess(third);
@@ -896,7 +896,7 @@ TEST_P(HpackDecoderAdapterTest, SectionC6ResponseHuffmanExamples) {
// | -> location: https://www.e
// | xample.com
- SpdyString first = SpdyHexDecode(
+ std::string first = SpdyHexDecode(
"488264025885aec3771a4b6196d07abe"
"941054d444a8200595040b8166e082a6"
"2d1bff6e919d29ad171863c78f0b97c8"
@@ -939,7 +939,7 @@ TEST_P(HpackDecoderAdapterTest, SectionC6ResponseHuffmanExamples) {
// | idx = 63
// | -> location:
// | https://www.example.com
- SpdyString second = SpdyHexDecode("4883640effc1c0bf");
+ std::string second = SpdyHexDecode("4883640effc1c0bf");
const SpdyHeaderBlock& second_header_set =
DecodeBlockExpectingSuccess(second);
@@ -1011,7 +1011,7 @@ TEST_P(HpackDecoderAdapterTest, SectionC6ResponseHuffmanExamples) {
// | -> set-cookie: foo=ASDJKHQ
// | KBZXOQWEOPIUAXQWEOIU;
// | max-age=3600; version=1
- SpdyString third = SpdyHexDecode(
+ std::string third = SpdyHexDecode(
"88c16196d07abe941054d444a8200595"
"040b8166e084a62d1bffc05a839bd9ab"
"77ad94e7821dd7f2e6c7b335dfdfcd5b"
@@ -1096,7 +1096,7 @@ TEST_P(HpackDecoderAdapterTest, ReuseNameOfEvictedEntry) {
// SpdyHeaderBlock stores these 6 strings as '\0' separated values.
// Make sure that is what happened.
- SpdyString joined_values = expected_header_set[name].as_string();
+ std::string joined_values = expected_header_set[name].as_string();
EXPECT_EQ(joined_values.size(),
2 * value1.size() + 2 * value2.size() + 2 * value3.size() + 5);
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 d76ead083c1..f4f427c582c 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
@@ -86,7 +86,7 @@ HpackEncoder::HpackEncoder(const HpackHuffmanTable& table)
HpackEncoder::~HpackEncoder() = default;
bool HpackEncoder::EncodeHeaderSet(const SpdyHeaderBlock& header_set,
- SpdyString* output) {
+ std::string* output) {
// Separate header set into pseudo-headers and regular headers.
Representations pseudo_headers;
Representations regular_headers;
@@ -131,7 +131,7 @@ size_t HpackEncoder::EstimateMemoryUsage() const {
}
void HpackEncoder::EncodeRepresentations(RepresentationIterator* iter,
- SpdyString* output) {
+ std::string* output) {
MaybeEmitTableSize();
while (iter->HasNext()) {
const auto header = iter->Next();
@@ -291,7 +291,7 @@ class HpackEncoder::Encoderator : public ProgressiveEncoder {
// Encodes up to max_encoded_bytes of the current header block into the
// given output string.
- void Next(size_t max_encoded_bytes, SpdyString* output) override;
+ void Next(size_t max_encoded_bytes, std::string* output) override;
private:
HpackEncoder* encoder_;
@@ -329,7 +329,7 @@ HpackEncoder::Encoderator::Encoderator(const SpdyHeaderBlock& header_set,
}
void HpackEncoder::Encoderator::Next(size_t max_encoded_bytes,
- SpdyString* output) {
+ std::string* output) {
SPDY_BUG_IF(!has_next_)
<< "Encoderator::Next called with nothing left to encode.";
const bool use_compression = encoder_->enable_compression_;
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 c0cf968ab5d..a24d69ba18c 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
@@ -10,6 +10,7 @@
#include <functional>
#include <map>
#include <memory>
+#include <string>
#include <utility>
#include <vector>
@@ -17,7 +18,6 @@
#include "net/third_party/quiche/src/spdy/core/hpack/hpack_output_stream.h"
#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h"
#include "net/third_party/quiche/src/spdy/platform/api/spdy_export.h"
-#include "net/third_party/quiche/src/spdy/platform/api/spdy_string.h"
#include "net/third_party/quiche/src/spdy/platform/api/spdy_string_piece.h"
// An HpackEncoder encodes header sets as outlined in
@@ -53,7 +53,7 @@ class SPDY_EXPORT_PRIVATE HpackEncoder {
// Encodes the given header set into the given string. Returns
// whether or not the encoding was successful.
- bool EncodeHeaderSet(const SpdyHeaderBlock& header_set, SpdyString* output);
+ bool EncodeHeaderSet(const SpdyHeaderBlock& header_set, std::string* output);
class SPDY_EXPORT_PRIVATE ProgressiveEncoder {
public:
@@ -64,7 +64,7 @@ class SPDY_EXPORT_PRIVATE HpackEncoder {
// Encodes up to max_encoded_bytes of the current header block into the
// given output string.
- virtual void Next(size_t max_encoded_bytes, SpdyString* output) = 0;
+ virtual void Next(size_t max_encoded_bytes, std::string* output) = 0;
};
// Returns a ProgressiveEncoder which must be outlived by both the given
@@ -106,7 +106,7 @@ class SPDY_EXPORT_PRIVATE HpackEncoder {
class Encoderator;
// Encodes a sequence of header name-value pairs as a single header block.
- void EncodeRepresentations(RepresentationIterator* iter, SpdyString* output);
+ void EncodeRepresentations(RepresentationIterator* iter, std::string* output);
// Emits a static/dynamic indexed representation (Section 7.1).
void EmitIndex(const HpackEntry* entry);
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 4a70dc06a05..4683ccf8f97 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
@@ -42,7 +42,9 @@ class HpackEncoderPeer {
return encoder_->huffman_table_;
}
void EmitString(SpdyStringPiece str) { encoder_->EmitString(str); }
- void TakeString(SpdyString* out) { encoder_->output_stream_.TakeString(out); }
+ void TakeString(std::string* out) {
+ encoder_->output_stream_.TakeString(out);
+ }
static void CookieToCrumbs(SpdyStringPiece cookie,
std::vector<SpdyStringPiece>* out) {
Representations tmp;
@@ -69,7 +71,7 @@ class HpackEncoderPeer {
// non-incremental encoding path.
static bool EncodeHeaderSet(HpackEncoder* encoder,
const SpdyHeaderBlock& header_set,
- SpdyString* output,
+ std::string* output,
bool use_incremental) {
if (use_incremental) {
return EncodeIncremental(encoder, header_set, output);
@@ -80,14 +82,14 @@ class HpackEncoderPeer {
static bool EncodeIncremental(HpackEncoder* encoder,
const SpdyHeaderBlock& header_set,
- SpdyString* output) {
+ std::string* output) {
std::unique_ptr<HpackEncoder::ProgressiveEncoder> encoderator =
encoder->EncodeHeaderSet(header_set);
- SpdyString output_buffer;
+ std::string output_buffer;
http2::test::Http2Random random;
encoderator->Next(random.UniformInRange(0, 16), &output_buffer);
while (encoderator->HasNext()) {
- SpdyString second_buffer;
+ std::string second_buffer;
encoderator->Next(random.UniformInRange(0, 16), &second_buffer);
output_buffer.append(second_buffer);
}
@@ -180,7 +182,7 @@ class HpackEncoderTest : public ::testing::TestWithParam<bool> {
expected_.AppendUint32(size);
}
void CompareWithExpectedEncoding(const SpdyHeaderBlock& header_set) {
- SpdyString expected_out, actual_out;
+ std::string expected_out, actual_out;
expected_.TakeString(&expected_out);
EXPECT_TRUE(test::HpackEncoderPeer::EncodeHeaderSet(
&encoder_, header_set, &actual_out, use_incremental_));
@@ -318,7 +320,7 @@ TEST_P(HpackEncoderTest, StringsDynamicallySelectHuffmanCoding) {
expected_.AppendUint32(6);
expected_.AppendBytes("@@@@@@");
- SpdyString expected_out, actual_out;
+ std::string expected_out, actual_out;
expected_.TakeString(&expected_out);
peer_.TakeString(&actual_out);
EXPECT_EQ(expected_out, actual_out);
@@ -507,7 +509,7 @@ TEST_P(HpackEncoderTest, DecomposeRepresentation) {
TEST_P(HpackEncoderTest, CrumbleNullByteDelimitedValue) {
SpdyHeaderBlock headers;
// A header field to be crumbled: "spam: foo\0bar".
- headers["spam"] = SpdyString("foo\0bar", 7);
+ headers["spam"] = std::string("foo\0bar", 7);
ExpectIndexedLiteral("spam", "foo");
expected_.AppendPrefix(kLiteralIncrementalIndexOpcode);
diff --git a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_entry.cc b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_entry.cc
index 46e608615aa..0965739dc0e 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_entry.cc
+++ b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_entry.cc
@@ -75,7 +75,7 @@ size_t HpackEntry::Size() const {
return Size(name(), value());
}
-SpdyString HpackEntry::GetDebugString() const {
+std::string HpackEntry::GetDebugString() const {
return SpdyStrCat(
"{ name: \"", name_ref_, "\", value: \"", value_ref_,
"\", index: ", insertion_index_, " ",
diff --git a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_entry.h b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_entry.h
index 61103fddd8e..50ac3a78e5f 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_entry.h
+++ b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_entry.h
@@ -7,9 +7,9 @@
#include <cstddef>
#include <cstdint>
+#include <string>
#include "net/third_party/quiche/src/spdy/platform/api/spdy_export.h"
-#include "net/third_party/quiche/src/spdy/platform/api/spdy_string.h"
#include "net/third_party/quiche/src/spdy/platform/api/spdy_string_piece.h"
// All section references below are to
@@ -70,7 +70,7 @@ class SPDY_EXPORT_PRIVATE HpackEntry {
static size_t Size(SpdyStringPiece name, SpdyStringPiece value);
size_t Size() const;
- SpdyString GetDebugString() const;
+ std::string GetDebugString() const;
int64_t time_added() const { return time_added_; }
void set_time_added(int64_t now) { time_added_ = now; }
@@ -86,8 +86,8 @@ class SPDY_EXPORT_PRIVATE HpackEntry {
};
// These members are not used for LOOKUP entries.
- SpdyString name_;
- SpdyString value_;
+ std::string name_;
+ std::string value_;
// These members are always valid. For DYNAMIC and STATIC entries, they
// always point to |name_| and |value_|.
diff --git a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_entry_test.cc b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_entry_test.cc
index 224ac187013..316fcb92359 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_entry_test.cc
+++ b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_entry_test.cc
@@ -42,7 +42,7 @@ class HpackEntryTest : public ::testing::Test {
return name_.size() + value_.size() + HpackEntry::kSizeOverhead;
}
- SpdyString name_, value_;
+ std::string name_, value_;
private:
// Referenced by HpackEntry instances.
diff --git a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_header_table_test.cc b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_header_table_test.cc
index 4001174dd1e..a7d24821726 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_header_table_test.cc
+++ b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_header_table_test.cc
@@ -7,11 +7,11 @@
#include <algorithm>
#include <cstdint>
#include <set>
+#include <string>
#include <vector>
#include "net/third_party/quiche/src/spdy/core/hpack/hpack_constants.h"
#include "net/third_party/quiche/src/spdy/core/hpack/hpack_entry.h"
-#include "net/third_party/quiche/src/spdy/platform/api/spdy_string.h"
#include "net/third_party/quiche/src/spdy/platform/api/spdy_test.h"
namespace spdy {
@@ -75,8 +75,8 @@ class HpackHeaderTableTest : public ::testing::Test {
// Returns an entry whose Size() is equal to the given one.
static HpackEntry MakeEntryOfSize(uint32_t size) {
EXPECT_GE(size, HpackEntry::kSizeOverhead);
- SpdyString name((size - HpackEntry::kSizeOverhead) / 2, 'n');
- SpdyString value(size - HpackEntry::kSizeOverhead - name.size(), 'v');
+ std::string name((size - HpackEntry::kSizeOverhead) / 2, 'n');
+ std::string value(size - HpackEntry::kSizeOverhead - name.size(), 'v');
HpackEntry entry(name, value, false, 0);
EXPECT_EQ(size, entry.Size());
return entry;
@@ -121,7 +121,7 @@ class HpackHeaderTableTest : public ::testing::Test {
}
}
- HpackEntry DynamicEntry(const SpdyString& name, const SpdyString& value) {
+ HpackEntry DynamicEntry(const std::string& name, const std::string& value) {
peer_.AddDynamicEntry(name, value);
return peer_.dynamic_entries().back();
}
@@ -256,7 +256,7 @@ TEST_F(HpackHeaderTableTest, EntryIndexing) {
}
TEST_F(HpackHeaderTableTest, SetSizes) {
- SpdyString key = "key", value = "value";
+ std::string key = "key", value = "value";
const HpackEntry* entry1 = table_.TryAddEntry(key, value);
const HpackEntry* entry2 = table_.TryAddEntry(key, value);
const HpackEntry* entry3 = table_.TryAddEntry(key, value);
@@ -288,7 +288,7 @@ TEST_F(HpackHeaderTableTest, SetSizes) {
}
TEST_F(HpackHeaderTableTest, EvictionCountForEntry) {
- SpdyString key = "key", value = "value";
+ std::string key = "key", value = "value";
const HpackEntry* entry1 = table_.TryAddEntry(key, value);
const HpackEntry* entry2 = table_.TryAddEntry(key, value);
size_t entry3_size = HpackEntry::Size(key, value);
@@ -305,7 +305,7 @@ TEST_F(HpackHeaderTableTest, EvictionCountForEntry) {
}
TEST_F(HpackHeaderTableTest, EvictionCountToReclaim) {
- SpdyString key = "key", value = "value";
+ std::string key = "key", value = "value";
const HpackEntry* entry1 = table_.TryAddEntry(key, value);
const HpackEntry* entry2 = table_.TryAddEntry(key, value);
diff --git a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_huffman_table.h b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_huffman_table.h
index 80d9e5262b7..a01c62f822d 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_huffman_table.h
+++ b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_huffman_table.h
@@ -11,7 +11,6 @@
#include "net/third_party/quiche/src/spdy/core/hpack/hpack_constants.h"
#include "net/third_party/quiche/src/spdy/platform/api/spdy_export.h"
-#include "net/third_party/quiche/src/spdy/platform/api/spdy_string.h"
#include "net/third_party/quiche/src/spdy/platform/api/spdy_string_piece.h"
namespace spdy {
diff --git a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_huffman_table_test.cc b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_huffman_table_test.cc
index efade416d8a..de4d30c4fd1 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_huffman_table_test.cc
+++ b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_huffman_table_test.cc
@@ -4,6 +4,7 @@
#include "net/third_party/quiche/src/spdy/core/hpack/hpack_huffman_table.h"
+#include <string>
#include <utility>
#include "net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_decoder.h"
@@ -41,8 +42,8 @@ class GenericHuffmanTableTest : public ::testing::Test {
protected:
GenericHuffmanTableTest() : table_(), peer_(table_) {}
- SpdyString EncodeString(SpdyStringPiece input) {
- SpdyString result;
+ std::string EncodeString(SpdyStringPiece input) {
+ std::string result;
HpackOutputStream output_stream;
table_.EncodeString(input, &output_stream);
@@ -188,7 +189,7 @@ class HpackHuffmanTableTest : public GenericHuffmanTableTest {
}
// Use http2::HpackHuffmanDecoder for roundtrip tests.
- void DecodeString(const SpdyString& encoded, SpdyString* out) {
+ void DecodeString(const std::string& encoded, std::string* out) {
http2::HpackHuffmanDecoder decoder;
out->clear();
EXPECT_TRUE(decoder.Decode(encoded, out));
@@ -200,8 +201,8 @@ TEST_F(HpackHuffmanTableTest, InitializeHpackCode) {
}
TEST_F(HpackHuffmanTableTest, SpecRequestExamples) {
- SpdyString buffer;
- SpdyString test_table[] = {
+ std::string buffer;
+ std::string test_table[] = {
SpdyHexDecode("f1e3c2e5f23a6ba0ab90f4ff"),
"www.example.com",
SpdyHexDecode("a8eb10649cbf"),
@@ -213,8 +214,8 @@ TEST_F(HpackHuffmanTableTest, SpecRequestExamples) {
};
// Round-trip each test example.
for (size_t i = 0; i != SPDY_ARRAYSIZE(test_table); i += 2) {
- const SpdyString& encodedFixture(test_table[i]);
- const SpdyString& decodedFixture(test_table[i + 1]);
+ const std::string& encodedFixture(test_table[i]);
+ const std::string& decodedFixture(test_table[i + 1]);
DecodeString(encodedFixture, &buffer);
EXPECT_EQ(decodedFixture, buffer);
buffer = EncodeString(decodedFixture);
@@ -223,8 +224,8 @@ TEST_F(HpackHuffmanTableTest, SpecRequestExamples) {
}
TEST_F(HpackHuffmanTableTest, SpecResponseExamples) {
- SpdyString buffer;
- SpdyString test_table[] = {
+ std::string buffer;
+ std::string test_table[] = {
SpdyHexDecode("6402"),
"302",
SpdyHexDecode("aec3771a4b"),
@@ -242,8 +243,8 @@ TEST_F(HpackHuffmanTableTest, SpecResponseExamples) {
};
// Round-trip each test example.
for (size_t i = 0; i != SPDY_ARRAYSIZE(test_table); i += 2) {
- const SpdyString& encodedFixture(test_table[i]);
- const SpdyString& decodedFixture(test_table[i + 1]);
+ const std::string& encodedFixture(test_table[i]);
+ const std::string& decodedFixture(test_table[i + 1]);
DecodeString(encodedFixture, &buffer);
EXPECT_EQ(decodedFixture, buffer);
buffer = EncodeString(decodedFixture);
@@ -256,8 +257,8 @@ TEST_F(HpackHuffmanTableTest, RoundTripIndividualSymbols) {
char c = static_cast<char>(i);
char storage[3] = {c, c, c};
SpdyStringPiece input(storage, SPDY_ARRAYSIZE(storage));
- SpdyString buffer_in = EncodeString(input);
- SpdyString buffer_out;
+ std::string buffer_in = EncodeString(input);
+ std::string buffer_out;
DecodeString(buffer_in, &buffer_out);
EXPECT_EQ(input, buffer_out);
}
@@ -270,21 +271,21 @@ TEST_F(HpackHuffmanTableTest, RoundTripSymbolSequence) {
storage[511 - i] = static_cast<char>(i);
}
SpdyStringPiece input(storage, SPDY_ARRAYSIZE(storage));
- SpdyString buffer_in = EncodeString(input);
- SpdyString buffer_out;
+ std::string buffer_in = EncodeString(input);
+ std::string buffer_out;
DecodeString(buffer_in, &buffer_out);
EXPECT_EQ(input, buffer_out);
}
TEST_F(HpackHuffmanTableTest, EncodedSizeAgreesWithEncodeString) {
- SpdyString test_table[] = {
+ std::string test_table[] = {
"",
"Mon, 21 Oct 2013 20:13:21 GMT",
"https://www.example.com",
"foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1",
- SpdyString(1, '\0'),
- SpdyString("foo\0bar", 7),
- SpdyString(256, '\0'),
+ std::string(1, '\0'),
+ std::string("foo\0bar", 7),
+ std::string(256, '\0'),
};
for (size_t i = 0; i != 256; ++i) {
// Expand last |test_table| entry to cover all codes.
@@ -292,7 +293,7 @@ TEST_F(HpackHuffmanTableTest, EncodedSizeAgreesWithEncodeString) {
}
HpackOutputStream output_stream;
- SpdyString encoding;
+ std::string encoding;
for (size_t i = 0; i != SPDY_ARRAYSIZE(test_table); ++i) {
table_.EncodeString(test_table[i], &output_stream);
output_stream.TakeString(&encoding);
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 fc01c3f3bc4..4ceaece2c6e 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
@@ -63,7 +63,7 @@ void HpackOutputStream::AppendUint32(uint32_t I) {
}
}
-void HpackOutputStream::TakeString(SpdyString* output) {
+void HpackOutputStream::TakeString(std::string* output) {
// This must hold, since all public functions cause the buffer to
// end on a byte boundary.
DCHECK_EQ(bit_offset_, 0u);
@@ -72,10 +72,11 @@ void HpackOutputStream::TakeString(SpdyString* output) {
bit_offset_ = 0;
}
-void HpackOutputStream::BoundedTakeString(size_t max_size, SpdyString* output) {
+void HpackOutputStream::BoundedTakeString(size_t max_size,
+ std::string* output) {
if (buffer_.size() > max_size) {
// Save off overflow bytes to temporary string (causes a copy).
- SpdyString overflow(buffer_.data() + max_size, buffer_.size() - max_size);
+ std::string overflow(buffer_.data() + max_size, buffer_.size() - max_size);
// Resize buffer down to the given limit.
buffer_.resize(max_size);
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 01631468283..5e6513923d8 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
@@ -7,10 +7,10 @@
#include <cstdint>
#include <map>
+#include <string>
#include "net/third_party/quiche/src/spdy/core/hpack/hpack_constants.h"
#include "net/third_party/quiche/src/spdy/platform/api/spdy_export.h"
-#include "net/third_party/quiche/src/spdy/platform/api/spdy_string.h"
#include "net/third_party/quiche/src/spdy/platform/api/spdy_string_piece.h"
// All section references below are to
@@ -49,11 +49,11 @@ class SPDY_EXPORT_PRIVATE HpackOutputStream {
void AppendUint32(uint32_t I);
// Swaps the internal buffer with |output|, then resets state.
- void TakeString(SpdyString* output);
+ void TakeString(std::string* output);
// Gives up to |max_size| bytes of the internal buffer to |output|. Resets
// internal state with the overflow.
- void BoundedTakeString(size_t max_size, SpdyString* output);
+ void BoundedTakeString(size_t max_size, std::string* output);
// Size in bytes of stream's internal buffer.
size_t size() const { return buffer_.size(); }
@@ -63,7 +63,7 @@ class SPDY_EXPORT_PRIVATE HpackOutputStream {
private:
// The internal bit buffer.
- SpdyString buffer_;
+ std::string buffer_;
// If 0, the buffer ends on a byte boundary. If non-zero, the buffer
// ends on the nth most significant bit. Guaranteed to be < 8.
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 9e1988d1bbb..494241764fa 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
@@ -16,7 +16,7 @@ namespace {
// significant bit, and that it can handle crossing a byte boundary.
TEST(HpackOutputStreamTest, AppendBits) {
HpackOutputStream output_stream;
- SpdyString expected_str;
+ std::string expected_str;
output_stream.AppendBits(0x1, 1);
expected_str.append(1, 0x00);
@@ -37,20 +37,20 @@ TEST(HpackOutputStreamTest, AppendBits) {
output_stream.AppendBits(0x0, 7);
- SpdyString str;
+ std::string str;
output_stream.TakeString(&str);
EXPECT_EQ(expected_str, str);
}
// Utility function to return I as a string encoded with an N-bit
// prefix.
-SpdyString EncodeUint32(uint8_t N, uint32_t I) {
+std::string EncodeUint32(uint8_t N, uint32_t I) {
HpackOutputStream output_stream;
if (N < 8) {
output_stream.AppendBits(0x00, 8 - N);
}
output_stream.AppendUint32(I);
- SpdyString str;
+ std::string str;
output_stream.TakeString(&str);
return str;
}
@@ -61,7 +61,7 @@ SpdyString EncodeUint32(uint8_t N, uint32_t I) {
TEST(HpackOutputStreamTest, OneByteIntegersEightBitPrefix) {
// Minimum.
- EXPECT_EQ(SpdyString("\x00", 1), EncodeUint32(8, 0x00));
+ EXPECT_EQ(std::string("\x00", 1), EncodeUint32(8, 0x00));
EXPECT_EQ("\x7f", EncodeUint32(8, 0x7f));
// Maximum.
EXPECT_EQ("\xfe", EncodeUint32(8, 0xfe));
@@ -69,7 +69,7 @@ TEST(HpackOutputStreamTest, OneByteIntegersEightBitPrefix) {
TEST(HpackOutputStreamTest, TwoByteIntegersEightBitPrefix) {
// Minimum.
- EXPECT_EQ(SpdyString("\xff\x00", 2), EncodeUint32(8, 0xff));
+ EXPECT_EQ(std::string("\xff\x00", 2), EncodeUint32(8, 0xff));
EXPECT_EQ("\xff\x01", EncodeUint32(8, 0x0100));
// Maximum.
EXPECT_EQ("\xff\x7f", EncodeUint32(8, 0x017e));
@@ -112,13 +112,13 @@ TEST(HpackOutputStreamTest, SixByteIntegersEightBitPrefix) {
TEST(HpackOutputStreamTest, OneByteIntegersOneToSevenBitPrefixes) {
// Minimums.
- EXPECT_EQ(SpdyString("\x00", 1), EncodeUint32(7, 0x00));
- EXPECT_EQ(SpdyString("\x00", 1), EncodeUint32(6, 0x00));
- EXPECT_EQ(SpdyString("\x00", 1), EncodeUint32(5, 0x00));
- EXPECT_EQ(SpdyString("\x00", 1), EncodeUint32(4, 0x00));
- EXPECT_EQ(SpdyString("\x00", 1), EncodeUint32(3, 0x00));
- EXPECT_EQ(SpdyString("\x00", 1), EncodeUint32(2, 0x00));
- EXPECT_EQ(SpdyString("\x00", 1), EncodeUint32(1, 0x00));
+ EXPECT_EQ(std::string("\x00", 1), EncodeUint32(7, 0x00));
+ EXPECT_EQ(std::string("\x00", 1), EncodeUint32(6, 0x00));
+ EXPECT_EQ(std::string("\x00", 1), EncodeUint32(5, 0x00));
+ EXPECT_EQ(std::string("\x00", 1), EncodeUint32(4, 0x00));
+ EXPECT_EQ(std::string("\x00", 1), EncodeUint32(3, 0x00));
+ EXPECT_EQ(std::string("\x00", 1), EncodeUint32(2, 0x00));
+ EXPECT_EQ(std::string("\x00", 1), EncodeUint32(1, 0x00));
// Maximums.
EXPECT_EQ("\x7e", EncodeUint32(7, 0x7e));
@@ -127,18 +127,18 @@ TEST(HpackOutputStreamTest, OneByteIntegersOneToSevenBitPrefixes) {
EXPECT_EQ("\x0e", EncodeUint32(4, 0x0e));
EXPECT_EQ("\x06", EncodeUint32(3, 0x06));
EXPECT_EQ("\x02", EncodeUint32(2, 0x02));
- EXPECT_EQ(SpdyString("\x00", 1), EncodeUint32(1, 0x00));
+ EXPECT_EQ(std::string("\x00", 1), EncodeUint32(1, 0x00));
}
TEST(HpackOutputStreamTest, TwoByteIntegersOneToSevenBitPrefixes) {
// Minimums.
- EXPECT_EQ(SpdyString("\x7f\x00", 2), EncodeUint32(7, 0x7f));
- EXPECT_EQ(SpdyString("\x3f\x00", 2), EncodeUint32(6, 0x3f));
- EXPECT_EQ(SpdyString("\x1f\x00", 2), EncodeUint32(5, 0x1f));
- EXPECT_EQ(SpdyString("\x0f\x00", 2), EncodeUint32(4, 0x0f));
- EXPECT_EQ(SpdyString("\x07\x00", 2), EncodeUint32(3, 0x07));
- EXPECT_EQ(SpdyString("\x03\x00", 2), EncodeUint32(2, 0x03));
- EXPECT_EQ(SpdyString("\x01\x00", 2), EncodeUint32(1, 0x01));
+ EXPECT_EQ(std::string("\x7f\x00", 2), EncodeUint32(7, 0x7f));
+ EXPECT_EQ(std::string("\x3f\x00", 2), EncodeUint32(6, 0x3f));
+ EXPECT_EQ(std::string("\x1f\x00", 2), EncodeUint32(5, 0x1f));
+ EXPECT_EQ(std::string("\x0f\x00", 2), EncodeUint32(4, 0x0f));
+ EXPECT_EQ(std::string("\x07\x00", 2), EncodeUint32(3, 0x07));
+ EXPECT_EQ(std::string("\x03\x00", 2), EncodeUint32(2, 0x03));
+ EXPECT_EQ(std::string("\x01\x00", 2), EncodeUint32(1, 0x01));
// Maximums.
EXPECT_EQ("\x7f\x7f", EncodeUint32(7, 0xfe));
@@ -236,9 +236,9 @@ TEST(HpackOutputStreamTest, AppendUint32PreservesUpperBits) {
HpackOutputStream output_stream;
output_stream.AppendBits(0x7f, 7);
output_stream.AppendUint32(0x01);
- SpdyString str;
+ std::string str;
output_stream.TakeString(&str);
- EXPECT_EQ(SpdyString("\xff\x00", 2), str);
+ EXPECT_EQ(std::string("\xff\x00", 2), str);
}
TEST(HpackOutputStreamTest, AppendBytes) {
@@ -247,7 +247,7 @@ TEST(HpackOutputStreamTest, AppendBytes) {
output_stream.AppendBytes("buffer1");
output_stream.AppendBytes("buffer2");
- SpdyString str;
+ std::string str;
output_stream.TakeString(&str);
EXPECT_EQ("buffer1buffer2", str);
}
@@ -258,7 +258,7 @@ TEST(HpackOutputStreamTest, BoundedTakeString) {
output_stream.AppendBytes("buffer12");
output_stream.AppendBytes("buffer456");
- SpdyString str;
+ std::string str;
output_stream.BoundedTakeString(9, &str);
EXPECT_EQ("buffer12b", 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 c035812bcf5..bae0fd2e7ef 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
@@ -12,7 +12,6 @@
#include "net/third_party/quiche/src/spdy/core/hpack/hpack_decoder_adapter.h"
#include "net/third_party/quiche/src/spdy/core/hpack/hpack_encoder.h"
#include "net/third_party/quiche/src/spdy/core/spdy_test_utils.h"
-#include "net/third_party/quiche/src/spdy/platform/api/spdy_string.h"
#include "net/third_party/quiche/src/spdy/platform/api/spdy_test.h"
namespace spdy {
@@ -34,7 +33,7 @@ class HpackRoundTripTest : public ::testing::TestWithParam<InputSizeParam> {
}
bool RoundTrip(const SpdyHeaderBlock& header_set) {
- SpdyString encoded;
+ std::string encoded;
encoder_.EncodeHeaderSet(header_set, &encoded);
bool success = true;
@@ -111,7 +110,7 @@ TEST_P(HpackRoundTripTest, ResponseFixtures) {
headers["set-cookie"] =
"foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU;"
" max-age=3600; version=1";
- headers["multivalue"] = SpdyString("foo\0bar", 7);
+ headers["multivalue"] = std::string("foo\0bar", 7);
EXPECT_TRUE(RoundTrip(headers));
}
}
@@ -144,7 +143,7 @@ TEST_P(HpackRoundTripTest, RequestFixtures) {
headers[":scheme"] = "https";
headers["custom-key"] = "custom-value";
headers["cookie"] = "baz=bing; fizzle=fazzle; garbage";
- headers["multivalue"] = SpdyString("foo\0bar", 7);
+ headers["multivalue"] = std::string("foo\0bar", 7);
EXPECT_TRUE(RoundTrip(headers));
}
}
@@ -153,7 +152,7 @@ TEST_P(HpackRoundTripTest, RandomizedExamples) {
// Grow vectors of names & values, which are seeded with fixtures and then
// expanded with dynamically generated data. Samples are taken using the
// exponential distribution.
- std::vector<SpdyString> pseudo_header_names, random_header_names;
+ std::vector<std::string> pseudo_header_names, random_header_names;
pseudo_header_names.push_back(":authority");
pseudo_header_names.push_back(":path");
pseudo_header_names.push_back(":status");
@@ -161,7 +160,7 @@ TEST_P(HpackRoundTripTest, RandomizedExamples) {
// TODO(jgraettinger): Enable "cookie" as a name fixture. Crumbs may be
// reconstructed in any order, which breaks the simple validation used here.
- std::vector<SpdyString> values;
+ std::vector<std::string> values;
values.push_back("/");
values.push_back("/index.html");
values.push_back("200");
@@ -180,7 +179,7 @@ TEST_P(HpackRoundTripTest, RandomizedExamples) {
std::min(header_count, 1 + SampleExponential(7, 50));
EXPECT_LE(pseudo_header_count, header_count);
for (size_t j = 0; j != header_count; ++j) {
- SpdyString name, value;
+ std::string name, value;
// Pseudo headers must be added before regular headers.
if (j < pseudo_header_count) {
// Choose one of the defined pseudo headers at random.
@@ -204,7 +203,8 @@ TEST_P(HpackRoundTripTest, RandomizedExamples) {
// Randomly reuse an existing value, or generate a new one.
size_t value_index = SampleExponential(20, 200);
if (value_index >= values.size()) {
- SpdyString newvalue = random_.RandString(1 + SampleExponential(15, 75));
+ std::string newvalue =
+ random_.RandString(1 + SampleExponential(15, 75));
// Currently order is not preserved in the encoder. In particular,
// when a value is decomposed at \0 delimiters, its parts might get
// encoded out of order if some but not all of them already exist in
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 ac534965536..d5b20f07393 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
@@ -21,7 +21,6 @@
#include "net/third_party/quiche/src/http2/decoder/http2_frame_decoder_listener.h"
#include "net/third_party/quiche/src/http2/http2_constants.h"
#include "net/third_party/quiche/src/http2/http2_structures.h"
-#include "net/third_party/quiche/src/http2/platform/api/http2_string.h"
#include "net/third_party/quiche/src/spdy/core/hpack/hpack_decoder_adapter.h"
#include "net/third_party/quiche/src/spdy/core/hpack/hpack_header_table.h"
#include "net/third_party/quiche/src/spdy/core/spdy_alt_svc_wire_format.h"
diff --git a/chromium/net/third_party/quiche/src/spdy/core/http2_frame_decoder_adapter.h b/chromium/net/third_party/quiche/src/spdy/core/http2_frame_decoder_adapter.h
index 3c05858672f..93da6844095 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/http2_frame_decoder_adapter.h
+++ b/chromium/net/third_party/quiche/src/spdy/core/http2_frame_decoder_adapter.h
@@ -9,6 +9,7 @@
#include <cstdint>
#include <memory>
+#include <string>
#include "net/third_party/quiche/src/http2/decoder/http2_frame_decoder.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_optional.h"
@@ -251,8 +252,8 @@ class SPDY_EXPORT_PRIVATE Http2DecoderAdapter
Http2Optional<size_t> opt_pad_length_;
// Temporary buffers for the AltSvc fields.
- Http2String alt_svc_origin_;
- Http2String alt_svc_value_;
+ std::string alt_svc_origin_;
+ std::string alt_svc_value_;
// Listener used if we transition to an error state; the listener ignores all
// the callbacks.
diff --git a/chromium/net/third_party/quiche/src/spdy/core/http2_priority_write_scheduler.h b/chromium/net/third_party/quiche/src/spdy/core/http2_priority_write_scheduler.h
index d08d125f933..125583926c1 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/http2_priority_write_scheduler.h
+++ b/chromium/net/third_party/quiche/src/spdy/core/http2_priority_write_scheduler.h
@@ -11,6 +11,7 @@
#include <memory>
#include <queue>
#include <set>
+#include <string>
#include <tuple>
#include <unordered_map>
#include <utility>
@@ -24,7 +25,6 @@
#include "net/third_party/quiche/src/spdy/platform/api/spdy_logging.h"
#include "net/third_party/quiche/src/spdy/platform/api/spdy_map_util.h"
#include "net/third_party/quiche/src/spdy/platform/api/spdy_ptr_util.h"
-#include "net/third_party/quiche/src/spdy/platform/api/spdy_string.h"
#include "net/third_party/quiche/src/spdy/platform/api/spdy_string_utils.h"
namespace spdy {
@@ -77,7 +77,7 @@ class Http2PriorityWriteScheduler : public WriteScheduler<StreamIdType> {
size_t NumReadyStreams() const override;
bool IsStreamReady(StreamIdType stream_id) const override;
size_t NumRegisteredStreams() const override;
- SpdyString DebugString() const override;
+ std::string DebugString() const override;
private:
friend class test::Http2PriorityWriteSchedulerPeer<StreamIdType>;
@@ -111,6 +111,16 @@ class Http2PriorityWriteScheduler : public WriteScheduler<StreamIdType> {
// Time of latest write event for stream of this priority, in microseconds.
int64_t last_event_time_usec = 0;
+ // Returns true if this stream is ancestor of |other|.
+ bool IsAncestorOf(const StreamInfo& other) const {
+ for (const StreamInfo* p = other.parent; p != nullptr; p = p->parent) {
+ if (p == this) {
+ return true;
+ }
+ }
+ return false;
+ }
+
// Whether this stream should be scheduled ahead of another stream.
bool SchedulesBefore(const StreamInfo& other) const {
return (priority != other.priority) ? priority > other.priority
@@ -394,8 +404,10 @@ void Http2PriorityWriteScheduler<StreamIdType>::UpdateStreamParent(
return;
}
- // If the new parent is already the stream's parent, we're done.
- if (stream_info->parent == new_parent) {
+ if (stream_info->parent == new_parent &&
+ (!exclusive || new_parent->children.size() == 1u)) {
+ // If the new parent is already the stream's parent, and exclusivity (if
+ // specified) is already satisfied, we are done.
return;
}
@@ -500,13 +512,20 @@ bool Http2PriorityWriteScheduler<StreamIdType>::ShouldYield(
SPDY_BUG << "Stream " << stream_id << " not registered";
return false;
}
+ if (HasReadyAncestor(*stream_info)) {
+ return true;
+ }
for (const StreamInfo& scheduled : scheduling_queue_) {
- if (stream_info == &scheduled) {
- return false;
+ if (HasReadyAncestor(scheduled)) {
+ // Skip streams which cannot be scheduled.
+ continue;
}
- if (!HasReadyAncestor(scheduled)) {
- return true;
+ if (stream_info->IsAncestorOf(scheduled)) {
+ // Do not yield to descendants.
+ return false;
}
+ // Yield to streams with higher priorities.
+ return scheduled.SchedulesBefore(*stream_info);
}
return false;
}
@@ -694,7 +713,7 @@ size_t Http2PriorityWriteScheduler<StreamIdType>::NumRegisteredStreams() const {
}
template <typename StreamIdType>
-SpdyString Http2PriorityWriteScheduler<StreamIdType>::DebugString() const {
+std::string Http2PriorityWriteScheduler<StreamIdType>::DebugString() const {
return SpdyStrCat("Http2PriorityWriteScheduler {num_registered_streams=",
NumRegisteredStreams(),
" num_ready_streams=", NumReadyStreams(), "}");
@@ -703,8 +722,8 @@ SpdyString Http2PriorityWriteScheduler<StreamIdType>::DebugString() const {
template <typename StreamIdType>
bool Http2PriorityWriteScheduler<StreamIdType>::ValidateInvariantsForTests()
const {
- int total_streams = 0;
- int streams_visited = 0;
+ size_t total_streams = 0;
+ size_t streams_visited = 0;
// Iterate through all streams in the map.
for (const auto& kv : all_stream_infos_) {
++total_streams;
diff --git a/chromium/net/third_party/quiche/src/spdy/core/http2_priority_write_scheduler_test.cc b/chromium/net/third_party/quiche/src/spdy/core/http2_priority_write_scheduler_test.cc
index 484e59a3a74..bf9f92feb2b 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/http2_priority_write_scheduler_test.cc
+++ b/chromium/net/third_party/quiche/src/spdy/core/http2_priority_write_scheduler_test.cc
@@ -1,3 +1,7 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
#include "net/third_party/quiche/src/spdy/core/http2_priority_write_scheduler.h"
#include <initializer_list>
@@ -74,7 +78,7 @@ TEST_F(Http2PriorityWriteSchedulerTest, RegisterAndUnregisterStreams) {
EXPECT_TRUE(scheduler_.StreamRegistered(5));
ASSERT_TRUE(scheduler_.StreamRegistered(13));
EXPECT_EQ(130, scheduler_.GetStreamPrecedence(13).weight());
- EXPECT_EQ(5, scheduler_.GetStreamPrecedence(13).parent_id());
+ EXPECT_EQ(5u, scheduler_.GetStreamPrecedence(13).parent_id());
scheduler_.UnregisterStream(5);
// Cannot remove a stream that has already been removed.
@@ -88,7 +92,7 @@ TEST_F(Http2PriorityWriteSchedulerTest, RegisterAndUnregisterStreams) {
// The parent stream 19 doesn't exist, so this should use 0 as parent stream:
scheduler_.RegisterStream(7, SpdyStreamPrecedence(19, 70, false));
EXPECT_TRUE(scheduler_.StreamRegistered(7));
- EXPECT_EQ(0, scheduler_.GetStreamPrecedence(7).parent_id());
+ EXPECT_EQ(0u, scheduler_.GetStreamPrecedence(7).parent_id());
// Now stream 7 already exists, so this should fail:
EXPECT_SPDY_BUG(
scheduler_.RegisterStream(7, SpdyStreamPrecedence(1, 70, false)),
@@ -105,7 +109,7 @@ TEST_F(Http2PriorityWriteSchedulerTest, RegisterAndUnregisterStreams) {
TEST_F(Http2PriorityWriteSchedulerTest, RegisterStreamWithSpdy3Priority) {
EXPECT_FALSE(scheduler_.StreamRegistered(1));
scheduler_.RegisterStream(1, SpdyStreamPrecedence(3));
- EXPECT_EQ(0, scheduler_.NumReadyStreams());
+ EXPECT_EQ(0u, scheduler_.NumReadyStreams());
EXPECT_TRUE(scheduler_.StreamRegistered(1));
EXPECT_EQ(3, scheduler_.GetStreamPrecedence(1).spdy3_priority());
EXPECT_EQ(147, scheduler_.GetStreamPrecedence(1).weight());
@@ -113,7 +117,6 @@ TEST_F(Http2PriorityWriteSchedulerTest, RegisterStreamWithSpdy3Priority) {
EXPECT_THAT(scheduler_.GetStreamChildren(1), IsEmpty());
EXPECT_SPDY_BUG(scheduler_.RegisterStream(1, SpdyStreamPrecedence(4)),
- "Expected HTTP/2 stream dependency|"
"Stream 1 already registered");
EXPECT_EQ(3, scheduler_.GetStreamPrecedence(1).spdy3_priority());
}
@@ -147,7 +150,7 @@ TEST_F(Http2PriorityWriteSchedulerTest, GetStreamParent) {
EXPECT_EQ(kHttp2RootStreamId, scheduler_.GetStreamPrecedence(3).parent_id());
scheduler_.RegisterStream(2, SpdyStreamPrecedence(0, 20, false));
scheduler_.RegisterStream(3, SpdyStreamPrecedence(2, 30, false));
- EXPECT_EQ(2, scheduler_.GetStreamPrecedence(3).parent_id());
+ EXPECT_EQ(2u, scheduler_.GetStreamPrecedence(3).parent_id());
scheduler_.UnregisterStream(3);
EXPECT_EQ(kHttp2RootStreamId, scheduler_.GetStreamPrecedence(3).parent_id());
}
@@ -426,16 +429,139 @@ TEST_F(Http2PriorityWriteSchedulerTest,
ASSERT_TRUE(peer_.ValidateInvariants());
}
+TEST_F(Http2PriorityWriteSchedulerTest, RegisterStreamParentExclusive) {
+ /* 0
+ / \
+ 1 2
+ */
+ scheduler_.RegisterStream(1, SpdyStreamPrecedence(0, 100, false));
+ scheduler_.RegisterStream(2, SpdyStreamPrecedence(0, 100, false));
+ /* 0
+ |
+ 3
+ / \
+ 1 2
+ */
+ scheduler_.RegisterStream(3, SpdyStreamPrecedence(0, 100, true));
+ EXPECT_THAT(scheduler_.GetStreamChildren(0), ElementsAre(3));
+ EXPECT_THAT(scheduler_.GetStreamChildren(3), UnorderedElementsAre(1, 2));
+ EXPECT_THAT(scheduler_.GetStreamChildren(1), IsEmpty());
+ EXPECT_THAT(scheduler_.GetStreamChildren(2), IsEmpty());
+ ASSERT_TRUE(peer_.ValidateInvariants());
+}
+
+TEST_F(Http2PriorityWriteSchedulerTest, UpdateStreamParentExclusive) {
+ /* 0
+ /|\
+ 1 2 3
+ */
+ scheduler_.RegisterStream(1, SpdyStreamPrecedence(0, 100, false));
+ scheduler_.RegisterStream(2, SpdyStreamPrecedence(0, 100, false));
+ scheduler_.RegisterStream(3, SpdyStreamPrecedence(0, 100, false));
+ /* 0
+ |
+ 1
+ / \
+ 2 3
+ */
+ scheduler_.UpdateStreamPrecedence(1, SpdyStreamPrecedence(0, 100, true));
+ EXPECT_THAT(scheduler_.GetStreamChildren(0), ElementsAre(1));
+ EXPECT_THAT(scheduler_.GetStreamChildren(1), UnorderedElementsAre(2, 3));
+ EXPECT_THAT(scheduler_.GetStreamChildren(2), IsEmpty());
+ EXPECT_THAT(scheduler_.GetStreamChildren(3), IsEmpty());
+ ASSERT_TRUE(peer_.ValidateInvariants());
+}
+
+TEST_F(Http2PriorityWriteSchedulerTest, UpdateStreamParentExclusive2) {
+ /* 0
+ |
+ 1
+ / \
+ 2 3
+ / \
+ 4 5
+ |
+ 6
+ */
+ scheduler_.RegisterStream(1, SpdyStreamPrecedence(0, 100, false));
+ scheduler_.RegisterStream(2, SpdyStreamPrecedence(1, 100, false));
+ scheduler_.RegisterStream(3, SpdyStreamPrecedence(1, 100, false));
+ scheduler_.RegisterStream(4, SpdyStreamPrecedence(3, 100, false));
+ scheduler_.RegisterStream(5, SpdyStreamPrecedence(3, 100, false));
+ scheduler_.RegisterStream(6, SpdyStreamPrecedence(4, 100, false));
+ // Update stream 1's parent to 4 exclusive.
+ /* 0
+ |
+ 4
+ |
+ 1
+ /|\
+ 2 3 6
+ |
+ 5
+ */
+ scheduler_.UpdateStreamPrecedence(1, SpdyStreamPrecedence(4, 100, true));
+ EXPECT_THAT(scheduler_.GetStreamChildren(0), ElementsAre(4));
+ EXPECT_THAT(scheduler_.GetStreamChildren(4), ElementsAre(1));
+ EXPECT_THAT(scheduler_.GetStreamChildren(1), UnorderedElementsAre(2, 3, 6));
+ EXPECT_THAT(scheduler_.GetStreamChildren(2), IsEmpty());
+ EXPECT_THAT(scheduler_.GetStreamChildren(3), ElementsAre(5));
+ EXPECT_THAT(scheduler_.GetStreamChildren(6), IsEmpty());
+ ASSERT_TRUE(peer_.ValidateInvariants());
+}
+
+TEST_F(Http2PriorityWriteSchedulerTest, UpdateStreamParentNonExclusive) {
+ /* 0
+ |
+ 1
+ / \
+ 2 3
+ / \
+ 4 5
+ |
+ 6
+ */
+ scheduler_.RegisterStream(1, SpdyStreamPrecedence(0, 100, false));
+ scheduler_.RegisterStream(2, SpdyStreamPrecedence(1, 100, false));
+ scheduler_.RegisterStream(3, SpdyStreamPrecedence(1, 100, false));
+ scheduler_.RegisterStream(4, SpdyStreamPrecedence(3, 100, false));
+ scheduler_.RegisterStream(5, SpdyStreamPrecedence(3, 100, false));
+ scheduler_.RegisterStream(6, SpdyStreamPrecedence(4, 100, false));
+ // Update stream 1's parent to 4.
+ /* 0
+ |
+ 4
+ / \
+ 6 1
+ / \
+ 2 3
+ |
+ 5
+ */
+ scheduler_.UpdateStreamPrecedence(1, SpdyStreamPrecedence(4, 100, false));
+ EXPECT_THAT(scheduler_.GetStreamChildren(0), ElementsAre(4));
+ EXPECT_THAT(scheduler_.GetStreamChildren(4), UnorderedElementsAre(6, 1));
+ EXPECT_THAT(scheduler_.GetStreamChildren(6), IsEmpty());
+ EXPECT_THAT(scheduler_.GetStreamChildren(1), UnorderedElementsAre(2, 3));
+ EXPECT_THAT(scheduler_.GetStreamChildren(2), IsEmpty());
+ EXPECT_THAT(scheduler_.GetStreamChildren(3), ElementsAre(5));
+ EXPECT_THAT(scheduler_.GetStreamChildren(5), IsEmpty());
+ ASSERT_TRUE(peer_.ValidateInvariants());
+}
+
TEST_F(Http2PriorityWriteSchedulerTest, UpdateStreamParentToParent) {
scheduler_.RegisterStream(1, SpdyStreamPrecedence(0, 100, false));
scheduler_.RegisterStream(2, SpdyStreamPrecedence(1, 100, false));
scheduler_.RegisterStream(3, SpdyStreamPrecedence(1, 100, false));
+ EXPECT_THAT(scheduler_.GetStreamChildren(1), UnorderedElementsAre(2, 3));
+ EXPECT_THAT(scheduler_.GetStreamChildren(2), IsEmpty());
+ EXPECT_THAT(scheduler_.GetStreamChildren(3), IsEmpty());
for (bool exclusive : {true, false}) {
scheduler_.UpdateStreamPrecedence(2,
SpdyStreamPrecedence(1, 100, exclusive));
EXPECT_THAT(scheduler_.GetStreamChildren(0), ElementsAre(1));
- EXPECT_THAT(scheduler_.GetStreamChildren(1), UnorderedElementsAre(2, 3));
- EXPECT_THAT(scheduler_.GetStreamChildren(2), IsEmpty());
+ EXPECT_THAT(scheduler_.GetStreamChildren(1), UnorderedElementsAre(2));
+ EXPECT_THAT(scheduler_.GetStreamChildren(2), UnorderedElementsAre(3));
EXPECT_THAT(scheduler_.GetStreamChildren(3), IsEmpty());
}
ASSERT_TRUE(peer_.ValidateInvariants());
@@ -486,22 +612,22 @@ TEST_F(Http2PriorityWriteSchedulerTest, BlockAndUnblock) {
scheduler_.RegisterStream(13, SpdyStreamPrecedence(7, 100, true));
scheduler_.RegisterStream(14, SpdyStreamPrecedence(7, 100, false));
scheduler_.UpdateStreamPrecedence(7, SpdyStreamPrecedence(3, 100, false));
- EXPECT_EQ(0, scheduler_.GetStreamPrecedence(1).parent_id());
- EXPECT_EQ(0, scheduler_.GetStreamPrecedence(2).parent_id());
- EXPECT_EQ(0, scheduler_.GetStreamPrecedence(3).parent_id());
- EXPECT_EQ(1, scheduler_.GetStreamPrecedence(4).parent_id());
- EXPECT_EQ(1, scheduler_.GetStreamPrecedence(5).parent_id());
- EXPECT_EQ(2, scheduler_.GetStreamPrecedence(6).parent_id());
- EXPECT_EQ(3, scheduler_.GetStreamPrecedence(7).parent_id());
- EXPECT_EQ(4, scheduler_.GetStreamPrecedence(8).parent_id());
- EXPECT_EQ(4, scheduler_.GetStreamPrecedence(9).parent_id());
- EXPECT_EQ(5, scheduler_.GetStreamPrecedence(10).parent_id());
- EXPECT_EQ(5, scheduler_.GetStreamPrecedence(11).parent_id());
- EXPECT_EQ(6, scheduler_.GetStreamPrecedence(12).parent_id());
- EXPECT_EQ(7, scheduler_.GetStreamPrecedence(13).parent_id());
- EXPECT_EQ(7, scheduler_.GetStreamPrecedence(14).parent_id());
- EXPECT_EQ(8, scheduler_.GetStreamPrecedence(15).parent_id());
- EXPECT_EQ(8, scheduler_.GetStreamPrecedence(16).parent_id());
+ EXPECT_EQ(0u, scheduler_.GetStreamPrecedence(1).parent_id());
+ EXPECT_EQ(0u, scheduler_.GetStreamPrecedence(2).parent_id());
+ EXPECT_EQ(0u, scheduler_.GetStreamPrecedence(3).parent_id());
+ EXPECT_EQ(1u, scheduler_.GetStreamPrecedence(4).parent_id());
+ EXPECT_EQ(1u, scheduler_.GetStreamPrecedence(5).parent_id());
+ EXPECT_EQ(2u, scheduler_.GetStreamPrecedence(6).parent_id());
+ EXPECT_EQ(3u, scheduler_.GetStreamPrecedence(7).parent_id());
+ EXPECT_EQ(4u, scheduler_.GetStreamPrecedence(8).parent_id());
+ EXPECT_EQ(4u, scheduler_.GetStreamPrecedence(9).parent_id());
+ EXPECT_EQ(5u, scheduler_.GetStreamPrecedence(10).parent_id());
+ EXPECT_EQ(5u, scheduler_.GetStreamPrecedence(11).parent_id());
+ EXPECT_EQ(6u, scheduler_.GetStreamPrecedence(12).parent_id());
+ EXPECT_EQ(7u, scheduler_.GetStreamPrecedence(13).parent_id());
+ EXPECT_EQ(7u, scheduler_.GetStreamPrecedence(14).parent_id());
+ EXPECT_EQ(8u, scheduler_.GetStreamPrecedence(15).parent_id());
+ EXPECT_EQ(8u, scheduler_.GetStreamPrecedence(16).parent_id());
ASSERT_TRUE(peer_.ValidateInvariants());
EXPECT_EQ(peer_.TotalChildWeights(0),
@@ -604,19 +730,19 @@ TEST_F(Http2PriorityWriteSchedulerTest, MarkReadyFrontAndBack) {
for (int i = 1; i < 6; ++i) {
scheduler_.MarkStreamReady(i, false);
}
- EXPECT_EQ(5, scheduler_.PopNextReadyStream());
- EXPECT_EQ(2, scheduler_.PopNextReadyStream());
+ EXPECT_EQ(5u, scheduler_.PopNextReadyStream());
+ EXPECT_EQ(2u, scheduler_.PopNextReadyStream());
scheduler_.MarkStreamReady(2, false);
- EXPECT_EQ(3, scheduler_.PopNextReadyStream());
+ EXPECT_EQ(3u, scheduler_.PopNextReadyStream());
scheduler_.MarkStreamReady(3, false);
- EXPECT_EQ(4, scheduler_.PopNextReadyStream());
+ EXPECT_EQ(4u, scheduler_.PopNextReadyStream());
scheduler_.MarkStreamReady(4, false);
- EXPECT_EQ(2, scheduler_.PopNextReadyStream());
+ EXPECT_EQ(2u, scheduler_.PopNextReadyStream());
scheduler_.MarkStreamReady(2, true);
- EXPECT_EQ(2, scheduler_.PopNextReadyStream());
+ EXPECT_EQ(2u, scheduler_.PopNextReadyStream());
scheduler_.MarkStreamReady(5, false);
scheduler_.MarkStreamReady(2, true);
- EXPECT_EQ(5, scheduler_.PopNextReadyStream());
+ EXPECT_EQ(5u, scheduler_.PopNextReadyStream());
}
// Add ready streams at front and back and pop them with
@@ -653,6 +779,46 @@ TEST_F(Http2PriorityWriteSchedulerTest, PopNextReadyStreamAndPrecedence) {
scheduler_.PopNextReadyStreamAndPrecedence());
}
+TEST_F(Http2PriorityWriteSchedulerTest, ShouldYield) {
+ /*
+ 0
+ /|\
+ 1 2 3
+ /|\ \
+ 4 5 6 7
+ |
+ 8
+
+ */
+ scheduler_.RegisterStream(1, SpdyStreamPrecedence(0, 100, false));
+ scheduler_.RegisterStream(2, SpdyStreamPrecedence(0, 100, false));
+ scheduler_.RegisterStream(3, SpdyStreamPrecedence(0, 100, false));
+ scheduler_.RegisterStream(4, SpdyStreamPrecedence(1, 100, false));
+ scheduler_.RegisterStream(5, SpdyStreamPrecedence(1, 200, false));
+ scheduler_.RegisterStream(6, SpdyStreamPrecedence(1, 255, false));
+ scheduler_.RegisterStream(7, SpdyStreamPrecedence(2, 100, false));
+ scheduler_.RegisterStream(8, SpdyStreamPrecedence(5, 100, false));
+
+ scheduler_.MarkStreamReady(5, false);
+
+ for (int i = 1; i <= 8; ++i) {
+ // Verify only 4 and 8 should yield to 5.
+ if (i == 4 || i == 8) {
+ EXPECT_TRUE(scheduler_.ShouldYield(i)) << "stream_id: " << i;
+ } else {
+ EXPECT_FALSE(scheduler_.ShouldYield(i)) << "stream_id: " << i;
+ }
+ }
+
+ // Marks streams 1 and 2 ready.
+ scheduler_.MarkStreamReady(1, false);
+ scheduler_.MarkStreamReady(2, false);
+ // 1 should not yield.
+ EXPECT_FALSE(scheduler_.ShouldYield(1));
+ // Verify 2 should yield to 1.
+ EXPECT_TRUE(scheduler_.ShouldYield(2));
+}
+
class PopNextReadyStreamTest : public Http2PriorityWriteSchedulerTest {
protected:
void SetUp() override {
diff --git a/chromium/net/third_party/quiche/src/spdy/core/lifo_write_scheduler.h b/chromium/net/third_party/quiche/src/spdy/core/lifo_write_scheduler.h
new file mode 100644
index 00000000000..b532c860950
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/spdy/core/lifo_write_scheduler.h
@@ -0,0 +1,208 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_SPDY_CORE_LIFO_WRITE_SCHEDULER_H_
+#define QUICHE_SPDY_CORE_LIFO_WRITE_SCHEDULER_H_
+
+#include <map>
+#include <set>
+#include <string>
+
+#include "net/third_party/quiche/src/spdy/core/write_scheduler.h"
+#include "net/third_party/quiche/src/spdy/platform/api/spdy_containers.h"
+#include "net/third_party/quiche/src/spdy/platform/api/spdy_string_utils.h"
+
+namespace spdy {
+
+namespace test {
+
+template <typename StreamIdType>
+class LifoWriteSchedulerPeer;
+
+} // namespace test
+
+// Create a write scheduler where the stream added last will have the highest
+// priority.
+template <typename StreamIdType>
+class LifoWriteScheduler : public WriteScheduler<StreamIdType> {
+ public:
+ using typename WriteScheduler<StreamIdType>::StreamPrecedenceType;
+
+ LifoWriteScheduler() = default;
+
+ void RegisterStream(StreamIdType stream_id,
+ const StreamPrecedenceType& /*precedence*/) override;
+
+ void UnregisterStream(StreamIdType stream_id) override;
+
+ bool StreamRegistered(StreamIdType stream_id) const override {
+ return registered_streams_.find(stream_id) != registered_streams_.end();
+ }
+
+ // Stream precedence is not supported by this scheduler.
+ StreamPrecedenceType GetStreamPrecedence(
+ StreamIdType /*stream_id*/) const override {
+ return StreamPrecedenceType(kV3LowestPriority);
+ }
+
+ void UpdateStreamPrecedence(
+ StreamIdType /*stream_id*/,
+ const StreamPrecedenceType& /*precedence*/) override {}
+
+ std::vector<StreamIdType> GetStreamChildren(
+ StreamIdType /*stream_id*/) const override {
+ return std::vector<StreamIdType>();
+ }
+
+ void RecordStreamEventTime(StreamIdType stream_id,
+ int64_t now_in_usec) override;
+
+ int64_t GetLatestEventWithPrecedence(StreamIdType stream_id) const override;
+
+ StreamIdType PopNextReadyStream() override;
+
+ std::tuple<StreamIdType, StreamPrecedenceType>
+ PopNextReadyStreamAndPrecedence() override {
+ return std::make_tuple(PopNextReadyStream(),
+ StreamPrecedenceType(kV3LowestPriority));
+ }
+
+ bool ShouldYield(StreamIdType stream_id) const override {
+ return !ready_streams_.empty() && stream_id < *ready_streams_.rbegin();
+ }
+
+ void MarkStreamReady(StreamIdType stream_id, bool /*add_to_front*/) override;
+
+ void MarkStreamNotReady(StreamIdType stream_id) override;
+
+ bool HasReadyStreams() const override { return !ready_streams_.empty(); }
+ size_t NumReadyStreams() const override { return ready_streams_.size(); }
+ bool IsStreamReady(StreamIdType stream_id) const override;
+ size_t NumRegisteredStreams() const override;
+ std::string DebugString() const override;
+
+ private:
+ friend class test::LifoWriteSchedulerPeer<StreamIdType>;
+
+ std::set<StreamIdType> ready_streams_;
+ std::map<StreamIdType, int64_t> registered_streams_;
+};
+
+template <typename StreamIdType>
+void LifoWriteScheduler<StreamIdType>::RegisterStream(
+ StreamIdType stream_id,
+ const StreamPrecedenceType& /*precedence*/) {
+ if (StreamRegistered(stream_id)) {
+ SPDY_BUG << "Stream " << stream_id << " already registered";
+ return;
+ }
+ registered_streams_.emplace_hint(registered_streams_.end(), stream_id, 0);
+}
+
+template <typename StreamIdType>
+void LifoWriteScheduler<StreamIdType>::UnregisterStream(
+ StreamIdType stream_id) {
+ if (!StreamRegistered(stream_id)) {
+ SPDY_BUG << "Stream " << stream_id << " is not registered";
+ return;
+ }
+ registered_streams_.erase(stream_id);
+ ready_streams_.erase(stream_id);
+}
+
+template <typename StreamIdType>
+void LifoWriteScheduler<StreamIdType>::RecordStreamEventTime(
+ StreamIdType stream_id,
+ int64_t now_in_usec) {
+ auto it = registered_streams_.find(stream_id);
+ if (it != registered_streams_.end()) {
+ it->second = now_in_usec;
+ } else {
+ SPDY_BUG << "Stream " << stream_id << " is not registered";
+ }
+}
+
+template <typename StreamIdType>
+int64_t LifoWriteScheduler<StreamIdType>::GetLatestEventWithPrecedence(
+ StreamIdType stream_id) const {
+ if (!StreamRegistered(stream_id)) {
+ SPDY_BUG << "Stream " << stream_id << " is not registered";
+ return 0;
+ }
+ int64_t latest_event_time_us = 0;
+ for (auto it = registered_streams_.rbegin(); it != registered_streams_.rend();
+ ++it) {
+ if (stream_id < it->first) {
+ if (it->second > latest_event_time_us) {
+ latest_event_time_us = it->second;
+ }
+ } else {
+ break;
+ }
+ }
+ return latest_event_time_us;
+}
+
+template <typename StreamIdType>
+StreamIdType LifoWriteScheduler<StreamIdType>::PopNextReadyStream() {
+ if (ready_streams_.empty()) {
+ SPDY_BUG << "No ready streams available";
+ return 0;
+ }
+ auto it = --ready_streams_.end();
+ StreamIdType id = *it;
+ ready_streams_.erase(it);
+ return id;
+}
+
+template <typename StreamIdType>
+void LifoWriteScheduler<StreamIdType>::MarkStreamReady(StreamIdType stream_id,
+ bool /*add_to_front*/) {
+ if (!StreamRegistered(stream_id)) {
+ SPDY_BUG << "Stream " << stream_id << " is not registered";
+ return;
+ }
+ if (ready_streams_.find(stream_id) != ready_streams_.end()) {
+ SPDY_VLOG(1) << "Stream already exists in the list";
+ return;
+ }
+ ready_streams_.insert(stream_id);
+}
+
+template <typename StreamIdType>
+void LifoWriteScheduler<StreamIdType>::MarkStreamNotReady(
+ StreamIdType stream_id) {
+ auto it = ready_streams_.find(stream_id);
+ if (it == ready_streams_.end()) {
+ SPDY_VLOG(1) << "Try to remove a stream that is not on list";
+ return;
+ }
+ ready_streams_.erase(it);
+}
+
+template <typename StreamIdType>
+bool LifoWriteScheduler<StreamIdType>::IsStreamReady(
+ StreamIdType stream_id) const {
+ if (!StreamRegistered(stream_id)) {
+ SPDY_BUG << "Stream " << stream_id << " is not registered";
+ return false;
+ }
+ return ready_streams_.find(stream_id) != ready_streams_.end();
+}
+
+template <typename StreamIdType>
+size_t LifoWriteScheduler<StreamIdType>::NumRegisteredStreams() const {
+ return registered_streams_.size();
+}
+
+template <typename StreamIdType>
+std::string LifoWriteScheduler<StreamIdType>::DebugString() const {
+ return SpdyStrCat(
+ "LifoWriteScheduler {num_streams=", registered_streams_.size(),
+ " num_ready_streams=", NumReadyStreams(), "}");
+}
+
+} // namespace spdy
+
+#endif // QUICHE_SPDY_CORE_LIFO_WRITE_SCHEDULER_H_
diff --git a/chromium/net/third_party/quiche/src/spdy/core/lifo_write_scheduler_test.cc b/chromium/net/third_party/quiche/src/spdy/core/lifo_write_scheduler_test.cc
new file mode 100644
index 00000000000..c9acc11d58b
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/spdy/core/lifo_write_scheduler_test.cc
@@ -0,0 +1,156 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/spdy/core/lifo_write_scheduler.h"
+
+#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h"
+#include "net/third_party/quiche/src/spdy/core/spdy_test_utils.h"
+#include "net/third_party/quiche/src/spdy/platform/api/spdy_test.h"
+#include "net/third_party/quiche/src/spdy/platform/api/spdy_test_helpers.h"
+
+namespace spdy {
+
+namespace test {
+
+template <typename StreamIdType>
+class LifoWriteSchedulerPeer {
+ public:
+ explicit LifoWriteSchedulerPeer(LifoWriteScheduler<StreamIdType>* scheduler)
+ : scheduler_(scheduler) {}
+
+ size_t NumRegisteredListStreams() const {
+ return scheduler_->registered_streams_.size();
+ }
+
+ std::set<StreamIdType>* GetReadyList() const {
+ return &scheduler_->ready_streams_;
+ }
+
+ private:
+ LifoWriteScheduler<StreamIdType>* scheduler_;
+};
+
+// Test add and remove from ready list.
+TEST(LifoWriteSchedulerTest, ReadyListTest) {
+ LifoWriteScheduler<SpdyStreamId> lifo;
+ LifoWriteSchedulerPeer<SpdyStreamId> peer(&lifo);
+
+ EXPECT_SPDY_BUG(
+ EXPECT_EQ(0u, std::get<0>(lifo.PopNextReadyStreamAndPrecedence())),
+ "No ready streams available");
+ EXPECT_SPDY_BUG(EXPECT_EQ(0u, lifo.PopNextReadyStream()),
+ "No ready streams available");
+ EXPECT_FALSE(lifo.HasReadyStreams());
+ EXPECT_SPDY_BUG(lifo.MarkStreamReady(9, true), "Stream 9 is not registered");
+ EXPECT_SPDY_BUG(lifo.IsStreamReady(9), "Stream 9 is not registered");
+ SpdyStreamPrecedence precedence(1);
+ lifo.RegisterStream(3, precedence);
+ EXPECT_FALSE(lifo.IsStreamReady(3));
+ lifo.RegisterStream(7, precedence);
+ lifo.RegisterStream(9, precedence);
+ lifo.RegisterStream(11, precedence);
+ lifo.RegisterStream(13, precedence);
+ lifo.RegisterStream(15, precedence);
+ lifo.RegisterStream(17, precedence);
+ lifo.MarkStreamReady(9, true);
+ lifo.MarkStreamReady(15, true);
+ lifo.MarkStreamReady(7, true);
+ lifo.MarkStreamReady(13, true);
+ lifo.MarkStreamReady(11, true);
+ lifo.MarkStreamReady(3, true);
+ EXPECT_TRUE(lifo.IsStreamReady(3));
+ lifo.MarkStreamReady(17, true);
+ EXPECT_TRUE(lifo.HasReadyStreams());
+ EXPECT_EQ(7u, lifo.NumReadyStreams());
+
+ // Verify MarkStream(Not)Ready() can be called multiple times for the same
+ // stream.
+ lifo.MarkStreamReady(11, true);
+ lifo.MarkStreamNotReady(5);
+ lifo.MarkStreamNotReady(21);
+
+ EXPECT_EQ(17u, lifo.PopNextReadyStream());
+ EXPECT_EQ(15u, std::get<0>(lifo.PopNextReadyStreamAndPrecedence()));
+ EXPECT_TRUE(lifo.ShouldYield(9));
+ EXPECT_FALSE(lifo.ShouldYield(13));
+ EXPECT_FALSE(lifo.ShouldYield(15));
+
+ lifo.MarkStreamNotReady(3);
+ EXPECT_TRUE(peer.GetReadyList()->find(3) == peer.GetReadyList()->end());
+ lifo.MarkStreamNotReady(13);
+ EXPECT_TRUE(peer.GetReadyList()->find(13) == peer.GetReadyList()->end());
+ lifo.MarkStreamNotReady(7);
+ EXPECT_TRUE(peer.GetReadyList()->find(7) == peer.GetReadyList()->end());
+ EXPECT_EQ(2u, lifo.NumReadyStreams());
+
+ lifo.MarkStreamNotReady(9);
+ lifo.MarkStreamNotReady(11);
+ EXPECT_FALSE(lifo.ShouldYield(1));
+}
+
+// Test add and remove from registered list.
+TEST(LifoWriteSchedulerTest, RegisterListTest) {
+ LifoWriteScheduler<SpdyStreamId> lifo;
+ LifoWriteSchedulerPeer<SpdyStreamId> peer(&lifo);
+ SpdyStreamPrecedence precedence(1);
+ EXPECT_EQ(0u, lifo.NumRegisteredStreams());
+ lifo.RegisterStream(3, precedence);
+ lifo.RegisterStream(5, precedence);
+ lifo.RegisterStream(7, precedence);
+ lifo.RegisterStream(9, precedence);
+ lifo.RegisterStream(11, precedence);
+ EXPECT_EQ(5u, lifo.NumRegisteredStreams());
+
+ EXPECT_TRUE(lifo.StreamRegistered(3));
+ EXPECT_TRUE(lifo.StreamRegistered(5));
+ EXPECT_TRUE(lifo.StreamRegistered(7));
+ EXPECT_TRUE(lifo.StreamRegistered(9));
+ EXPECT_TRUE(lifo.StreamRegistered(11));
+ EXPECT_SPDY_BUG(lifo.RegisterStream(11, precedence),
+ "Stream 11 already registered");
+ EXPECT_EQ(5u, peer.NumRegisteredListStreams());
+
+ lifo.UnregisterStream(3);
+ EXPECT_EQ(4u, lifo.NumRegisteredStreams());
+ EXPECT_FALSE(lifo.StreamRegistered(3));
+ EXPECT_SPDY_BUG(lifo.UnregisterStream(3), "Stream 3 is not registered");
+ EXPECT_SPDY_BUG(lifo.UnregisterStream(13), "Stream 13 is not registered");
+ lifo.UnregisterStream(11);
+ EXPECT_FALSE(lifo.StreamRegistered(11));
+ lifo.UnregisterStream(7);
+ EXPECT_EQ(2u, lifo.NumRegisteredStreams());
+ EXPECT_FALSE(lifo.StreamRegistered(7));
+ EXPECT_TRUE(lifo.StreamRegistered(5));
+ EXPECT_TRUE(lifo.StreamRegistered(9));
+}
+
+// Test mark latest event time.
+TEST(LifoWriteSchedulerTest, GetLatestEventTest) {
+ LifoWriteScheduler<SpdyStreamId> lifo;
+ LifoWriteSchedulerPeer<SpdyStreamId> peer(&lifo);
+ SpdyStreamPrecedence precedence(1);
+ lifo.RegisterStream(1, precedence);
+ lifo.RegisterStream(3, precedence);
+ lifo.RegisterStream(5, precedence);
+ lifo.RegisterStream(7, precedence);
+ lifo.RegisterStream(9, precedence);
+ lifo.RecordStreamEventTime(1, 1);
+ lifo.RecordStreamEventTime(3, 8);
+ lifo.RecordStreamEventTime(5, 4);
+ lifo.RecordStreamEventTime(7, 2);
+ lifo.RecordStreamEventTime(9, 3);
+ EXPECT_SPDY_BUG(lifo.RecordStreamEventTime(11, 1),
+ "Stream 11 is not registered");
+ EXPECT_EQ(0, lifo.GetLatestEventWithPrecedence(9));
+ EXPECT_EQ(3, lifo.GetLatestEventWithPrecedence(7));
+ EXPECT_EQ(3, lifo.GetLatestEventWithPrecedence(5));
+ EXPECT_EQ(4, lifo.GetLatestEventWithPrecedence(3));
+ EXPECT_EQ(8, lifo.GetLatestEventWithPrecedence(1));
+ EXPECT_SPDY_BUG(lifo.GetLatestEventWithPrecedence(11),
+ "Stream 11 is not registered");
+}
+
+} // namespace test
+
+} // namespace spdy
diff --git a/chromium/net/third_party/quiche/src/spdy/core/priority_write_scheduler.h b/chromium/net/third_party/quiche/src/spdy/core/priority_write_scheduler.h
index e4385835315..15939e09102 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/priority_write_scheduler.h
+++ b/chromium/net/third_party/quiche/src/spdy/core/priority_write_scheduler.h
@@ -8,6 +8,7 @@
#include <algorithm>
#include <cstddef>
#include <cstdint>
+#include <string>
#include <tuple>
#include <unordered_map>
#include <utility>
@@ -19,7 +20,6 @@
#include "net/third_party/quiche/src/spdy/platform/api/spdy_bug_tracker.h"
#include "net/third_party/quiche/src/spdy/platform/api/spdy_logging.h"
#include "net/third_party/quiche/src/spdy/platform/api/spdy_macros.h"
-#include "net/third_party/quiche/src/spdy/platform/api/spdy_string.h"
#include "net/third_party/quiche/src/spdy/platform/api/spdy_string_utils.h"
namespace spdy {
@@ -260,7 +260,7 @@ class PriorityWriteScheduler : public WriteScheduler<StreamIdType> {
size_t NumRegisteredStreams() const override { return stream_infos_.size(); }
- SpdyString DebugString() const override {
+ std::string DebugString() const override {
return SpdyStrCat(
"PriorityWriteScheduler {num_streams=", stream_infos_.size(),
" num_ready_streams=", NumReadyStreams(), "}");
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 d230ae09fdd..fcbfd16eb5d 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
@@ -38,8 +38,8 @@ bool ParsePositiveIntegerImpl(SpdyStringPiece::const_iterator c,
SpdyAltSvcWireFormat::AlternativeService::AlternativeService() = default;
SpdyAltSvcWireFormat::AlternativeService::AlternativeService(
- const SpdyString& protocol_id,
- const SpdyString& host,
+ const std::string& protocol_id,
+ const std::string& host,
uint16_t port,
uint32_t max_age,
VersionVector version)
@@ -71,7 +71,7 @@ bool SpdyAltSvcWireFormat::ParseHeaderFieldValue(
// Parse protocol-id.
SpdyStringPiece::const_iterator percent_encoded_protocol_id_end =
std::find(c, value.end(), '=');
- SpdyString protocol_id;
+ std::string protocol_id;
if (percent_encoded_protocol_id_end == c ||
!PercentDecode(c, percent_encoded_protocol_id_end, &protocol_id)) {
return false;
@@ -105,7 +105,7 @@ bool SpdyAltSvcWireFormat::ParseHeaderFieldValue(
return false;
}
DCHECK_EQ('"', *c);
- SpdyString host;
+ std::string host;
uint16_t port;
if (!ParseAltAuthority(alt_authority_begin, c, &host, &port)) {
return false;
@@ -129,7 +129,7 @@ bool SpdyAltSvcWireFormat::ParseHeaderFieldValue(
if (c == parameters_end) {
break;
}
- SpdyString parameter_name;
+ std::string parameter_name;
for (; c != parameters_end && *c != '=' && *c != ' ' && *c != '\t'; ++c) {
parameter_name.push_back(tolower(*c));
}
@@ -211,13 +211,13 @@ bool SpdyAltSvcWireFormat::ParseHeaderFieldValue(
}
// static
-SpdyString SpdyAltSvcWireFormat::SerializeHeaderFieldValue(
+std::string SpdyAltSvcWireFormat::SerializeHeaderFieldValue(
const AlternativeServiceVector& altsvc_vector) {
if (altsvc_vector.empty()) {
- return SpdyString("clear");
+ return std::string("clear");
}
const char kNibbleToHex[] = "0123456789ABCDEF";
- SpdyString value;
+ std::string value;
for (const AlternativeService& altsvc : altsvc_vector) {
if (!value.empty()) {
value.push_back(',');
@@ -300,7 +300,7 @@ void SpdyAltSvcWireFormat::SkipWhiteSpace(SpdyStringPiece::const_iterator* c,
// static
bool SpdyAltSvcWireFormat::PercentDecode(SpdyStringPiece::const_iterator c,
SpdyStringPiece::const_iterator end,
- SpdyString* output) {
+ std::string* output) {
output->clear();
for (; c != end; ++c) {
if (*c != '%') {
@@ -328,7 +328,7 @@ bool SpdyAltSvcWireFormat::PercentDecode(SpdyStringPiece::const_iterator c,
bool SpdyAltSvcWireFormat::ParseAltAuthority(
SpdyStringPiece::const_iterator c,
SpdyStringPiece::const_iterator end,
- SpdyString* host,
+ std::string* host,
uint16_t* port) {
host->clear();
if (c == end) {
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 ac834bc851a..13142efe950 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
@@ -11,11 +11,11 @@
#define QUICHE_SPDY_CORE_SPDY_ALT_SVC_WIRE_FORMAT_H_
#include <cstdint>
+#include <string>
#include <vector>
#include "net/third_party/quiche/src/spdy/platform/api/spdy_containers.h"
#include "net/third_party/quiche/src/spdy/platform/api/spdy_export.h"
-#include "net/third_party/quiche/src/spdy/platform/api/spdy_string.h"
#include "net/third_party/quiche/src/spdy/platform/api/spdy_string_piece.h"
namespace spdy {
@@ -29,8 +29,8 @@ class SPDY_EXPORT_PRIVATE SpdyAltSvcWireFormat {
using VersionVector = SpdyInlinedVector<uint32_t, 8>;
struct SPDY_EXPORT_PRIVATE AlternativeService {
- SpdyString protocol_id;
- SpdyString host;
+ std::string protocol_id;
+ std::string host;
// Default is 0: invalid port.
uint16_t port = 0;
@@ -40,8 +40,8 @@ class SPDY_EXPORT_PRIVATE SpdyAltSvcWireFormat {
VersionVector version;
AlternativeService();
- AlternativeService(const SpdyString& protocol_id,
- const SpdyString& host,
+ AlternativeService(const std::string& protocol_id,
+ const std::string& host,
uint16_t port,
uint32_t max_age,
VersionVector version);
@@ -62,7 +62,7 @@ class SPDY_EXPORT_PRIVATE SpdyAltSvcWireFormat {
friend class test::SpdyAltSvcWireFormatPeer;
static bool ParseHeaderFieldValue(SpdyStringPiece value,
AlternativeServiceVector* altsvc_vector);
- static SpdyString SerializeHeaderFieldValue(
+ static std::string SerializeHeaderFieldValue(
const AlternativeServiceVector& altsvc_vector);
private:
@@ -70,10 +70,10 @@ class SPDY_EXPORT_PRIVATE SpdyAltSvcWireFormat {
SpdyStringPiece::const_iterator end);
static bool PercentDecode(SpdyStringPiece::const_iterator c,
SpdyStringPiece::const_iterator end,
- SpdyString* output);
+ std::string* output);
static bool ParseAltAuthority(SpdyStringPiece::const_iterator c,
SpdyStringPiece::const_iterator end,
- SpdyString* host,
+ std::string* host,
uint16_t* port);
static bool ParsePositiveInteger16(SpdyStringPiece::const_iterator c,
SpdyStringPiece::const_iterator end,
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 bda5bc519d4..7b5e0bb6eb4 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
@@ -20,12 +20,12 @@ class SpdyAltSvcWireFormatPeer {
}
static bool PercentDecode(SpdyStringPiece::const_iterator c,
SpdyStringPiece::const_iterator end,
- SpdyString* output) {
+ std::string* output) {
return SpdyAltSvcWireFormat::PercentDecode(c, end, output);
}
static bool ParseAltAuthority(SpdyStringPiece::const_iterator c,
SpdyStringPiece::const_iterator end,
- SpdyString* host,
+ std::string* host,
uint16_t* port) {
return SpdyAltSvcWireFormat::ParseAltAuthority(c, end, host, port);
}
@@ -49,7 +49,7 @@ namespace {
// random case, and corresponding AlternativeService entries.
void FuzzHeaderFieldValue(
int i,
- SpdyString* header_field_value,
+ std::string* header_field_value,
SpdyAltSvcWireFormat::AlternativeService* expected_altsvc) {
if (!header_field_value->empty()) {
header_field_value->push_back(',');
@@ -132,7 +132,7 @@ void FuzzHeaderFieldValue(
// canonical form, that is, what SerializeHeaderFieldValue() should output.
void FuzzAlternativeService(int i,
SpdyAltSvcWireFormat::AlternativeService* altsvc,
- SpdyString* expected_header_field_value) {
+ std::string* expected_header_field_value) {
if (!expected_header_field_value->empty()) {
expected_header_field_value->push_back(',');
}
@@ -183,7 +183,7 @@ TEST(SpdyAltSvcWireFormatTest, ParseHeaderFieldValueClear) {
// separator, etc. Single alternative service at a time.
TEST(SpdyAltSvcWireFormatTest, ParseHeaderFieldValue) {
for (int i = 0; i < 1 << 13; ++i) {
- SpdyString header_field_value;
+ std::string header_field_value;
SpdyAltSvcWireFormat::AlternativeService expected_altsvc;
FuzzHeaderFieldValue(i, &header_field_value, &expected_altsvc);
SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector;
@@ -197,7 +197,7 @@ TEST(SpdyAltSvcWireFormatTest, ParseHeaderFieldValue) {
EXPECT_EQ(expected_altsvc.version, altsvc_vector[0].version);
// Roundtrip test starting with |altsvc_vector|.
- SpdyString reserialized_header_field_value =
+ std::string reserialized_header_field_value =
SpdyAltSvcWireFormat::SerializeHeaderFieldValue(altsvc_vector);
SpdyAltSvcWireFormat::AlternativeServiceVector roundtrip_altsvc_vector;
ASSERT_TRUE(SpdyAltSvcWireFormat::ParseHeaderFieldValue(
@@ -217,7 +217,7 @@ TEST(SpdyAltSvcWireFormatTest, ParseHeaderFieldValue) {
// separator, etc. Possibly multiple alternative service at a time.
TEST(SpdyAltSvcWireFormatTest, ParseHeaderFieldValueMultiple) {
for (int i = 0; i < 1 << 13;) {
- SpdyString header_field_value;
+ std::string header_field_value;
SpdyAltSvcWireFormat::AlternativeServiceVector expected_altsvc_vector;
// This will generate almost two hundred header field values with two,
// three, four, five, six, and seven alternative services each, and
@@ -242,7 +242,7 @@ TEST(SpdyAltSvcWireFormatTest, ParseHeaderFieldValueMultiple) {
}
// Roundtrip test starting with |altsvc_vector|.
- SpdyString reserialized_header_field_value =
+ std::string reserialized_header_field_value =
SpdyAltSvcWireFormat::SerializeHeaderFieldValue(altsvc_vector);
SpdyAltSvcWireFormat::AlternativeServiceVector roundtrip_altsvc_vector;
ASSERT_TRUE(SpdyAltSvcWireFormat::ParseHeaderFieldValue(
@@ -276,7 +276,7 @@ TEST(SpdyAltSvcWireFormatTest, SerializeEmptyHeaderFieldValue) {
TEST(SpdyAltSvcWireFormatTest, RoundTrip) {
for (int i = 0; i < 1 << 3; ++i) {
SpdyAltSvcWireFormat::AlternativeService altsvc;
- SpdyString expected_header_field_value;
+ std::string expected_header_field_value;
FuzzAlternativeService(i, &altsvc, &expected_header_field_value);
// Test ParseHeaderFieldValue().
@@ -304,7 +304,7 @@ TEST(SpdyAltSvcWireFormatTest, RoundTrip) {
// parameter. Multiple alternative services at a time.
TEST(SpdyAltSvcWireFormatTest, RoundTripMultiple) {
SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector;
- SpdyString expected_header_field_value;
+ std::string expected_header_field_value;
for (int i = 0; i < 1 << 3; ++i) {
SpdyAltSvcWireFormat::AlternativeService altsvc;
FuzzAlternativeService(i, &altsvc, &expected_header_field_value);
@@ -374,7 +374,7 @@ TEST(SpdyAltSvcWireFormatTest, ParseTruncatedHeaderFieldValue) {
SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector;
const char* field_value_array[] = {"a=\":137\"", "a=\"foo:137\"",
"a%25=\"foo\\\"bar\\\\baz:137\""};
- for (const SpdyString& field_value : field_value_array) {
+ for (const std::string& field_value : field_value_array) {
for (size_t len = 1; len < field_value.size(); ++len) {
EXPECT_FALSE(SpdyAltSvcWireFormat::ParseHeaderFieldValue(
field_value.substr(0, len), &altsvc_vector))
@@ -402,7 +402,7 @@ TEST(SpdyAltSvcWireFormatTest, SkipWhiteSpace) {
// Test PercentDecode() on valid input.
TEST(SpdyAltSvcWireFormatTest, PercentDecodeValid) {
SpdyStringPiece input("");
- SpdyString output;
+ std::string output;
ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::PercentDecode(
input.begin(), input.end(), &output));
EXPECT_EQ("", output);
@@ -425,7 +425,7 @@ TEST(SpdyAltSvcWireFormatTest, PercentDecodeInvalid) {
const char* invalid_input_array[] = {"a%", "a%x", "a%b", "%J22", "%9z"};
for (const char* invalid_input : invalid_input_array) {
SpdyStringPiece input(invalid_input);
- SpdyString output;
+ std::string output;
EXPECT_FALSE(test::SpdyAltSvcWireFormatPeer::PercentDecode(
input.begin(), input.end(), &output))
<< input;
@@ -435,7 +435,7 @@ TEST(SpdyAltSvcWireFormatTest, PercentDecodeInvalid) {
// Test ParseAltAuthority() on valid input.
TEST(SpdyAltSvcWireFormatTest, ParseAltAuthorityValid) {
SpdyStringPiece input(":42");
- SpdyString host;
+ std::string host;
uint16_t port;
ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::ParseAltAuthority(
input.begin(), input.end(), &host, &port));
@@ -476,7 +476,7 @@ TEST(SpdyAltSvcWireFormatTest, ParseAltAuthorityInvalid) {
"2003:8:0:16::509d:9615]:443"};
for (const char* invalid_input : invalid_input_array) {
SpdyStringPiece input(invalid_input);
- SpdyString host;
+ std::string host;
uint16_t port;
EXPECT_FALSE(test::SpdyAltSvcWireFormatPeer::ParseAltAuthority(
input.begin(), input.end(), &host, &port))
diff --git a/chromium/net/third_party/quiche/src/spdy/core/spdy_deframer_visitor.cc b/chromium/net/third_party/quiche/src/spdy/core/spdy_deframer_visitor.cc
index 39a2e51b3ef..0ea2020abdf 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/spdy_deframer_visitor.cc
+++ b/chromium/net/third_party/quiche/src/spdy/core/spdy_deframer_visitor.cc
@@ -214,7 +214,7 @@ class SpdyTestDeframerImpl : public SpdyTestDeframer,
bool fin_ = false;
bool got_hpack_end_ = false;
- std::unique_ptr<SpdyString> data_;
+ std::unique_ptr<std::string> data_;
// Total length of the data frame.
size_t data_len_ = 0;
@@ -223,7 +223,7 @@ class SpdyTestDeframerImpl : public SpdyTestDeframer,
// Length field).
size_t padding_len_ = 0;
- std::unique_ptr<SpdyString> goaway_description_;
+ std::unique_ptr<std::string> goaway_description_;
std::unique_ptr<StringPairVector> headers_;
std::unique_ptr<SettingVector> settings_;
std::unique_ptr<TestHeadersHandler> headers_handler_;
@@ -417,7 +417,7 @@ void SpdyTestDeframerImpl::OnAltSvc(
<< " frame_type_=" << Http2FrameTypeToString(frame_type_);
CHECK_GT(stream_id, 0u);
auto ptr = SpdyMakeUnique<SpdyAltSvcIR>(stream_id);
- ptr->set_origin(SpdyString(origin));
+ ptr->set_origin(std::string(origin));
for (auto& altsvc : altsvc_vector) {
ptr->add_altsvc(altsvc);
}
@@ -456,7 +456,7 @@ void SpdyTestDeframerImpl::OnDataFrameHeader(SpdyStreamId stream_id,
stream_id_ = stream_id;
fin_ = fin;
data_len_ = length;
- data_ = SpdyMakeUnique<SpdyString>();
+ data_ = SpdyMakeUnique<std::string>();
}
// The SpdyFramer will not process any more data at this point.
@@ -482,7 +482,7 @@ void SpdyTestDeframerImpl::OnGoAway(SpdyStreamId last_good_stream_id,
frame_type_ = GOAWAY;
goaway_ir_ =
SpdyMakeUnique<SpdyGoAwayIR>(last_good_stream_id, error_code, "");
- goaway_description_ = SpdyMakeUnique<SpdyString>();
+ goaway_description_ = SpdyMakeUnique<std::string>();
}
// If len==0 then we've reached the end of the GOAWAY frame.
@@ -761,7 +761,8 @@ void SpdyTestDeframerImpl::OnHeader(SpdyStringPiece key,
frame_type_ == PUSH_PROMISE)
<< " frame_type_=" << Http2FrameTypeToString(frame_type_);
CHECK(!got_hpack_end_);
- HTTP2_DIE_IF_NULL(headers_)->emplace_back(SpdyString(key), SpdyString(value));
+ HTTP2_DIE_IF_NULL(headers_)->emplace_back(std::string(key),
+ std::string(value));
HTTP2_DIE_IF_NULL(headers_handler_)->OnHeader(key, value);
}
diff --git a/chromium/net/third_party/quiche/src/spdy/core/spdy_deframer_visitor.h b/chromium/net/third_party/quiche/src/spdy/core/spdy_deframer_visitor.h
index 272a4f6200a..f95d513f8c7 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/spdy_deframer_visitor.h
+++ b/chromium/net/third_party/quiche/src/spdy/core/spdy_deframer_visitor.h
@@ -68,8 +68,8 @@
// are met.
#include <cstdint>
-
#include <memory>
+#include <string>
#include <type_traits>
#include <utility>
#include <vector>
@@ -79,7 +79,6 @@
#include "net/third_party/quiche/src/spdy/core/spdy_protocol_test_utils.h"
#include "net/third_party/quiche/src/spdy/core/spdy_test_utils.h"
#include "net/third_party/quiche/src/spdy/platform/api/spdy_logging.h"
-#include "net/third_party/quiche/src/spdy/platform/api/spdy_string.h"
namespace spdy {
namespace test {
@@ -91,7 +90,7 @@ typedef std::vector<std::pair<SpdyKnownSettingsId, uint32_t>> SettingVector;
// particular the order of each header entry, though it doesn't expose the
// inner details of the HPACK block, such as the type of encoding selected
// for each header entry, nor dynamic table size changes.
-typedef std::pair<SpdyString, SpdyString> StringPair;
+typedef std::pair<std::string, std::string> StringPair;
typedef std::vector<StringPair> StringPairVector;
// Forward decl.
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 7891d72e1f6..59f7c3ba91b 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
@@ -96,7 +96,7 @@ uint8_t SerializePushPromiseFrameFlags(const SpdyPushPromiseIR& push_promise_ir,
// block. Does not need or use the SpdyHeaderBlock inside SpdyHeadersIR.
// Return false if the serialization fails. |encoding| should not be empty.
bool SerializeHeadersGivenEncoding(const SpdyHeadersIR& headers,
- const SpdyString& encoding,
+ const std::string& encoding,
const bool end_headers,
ZeroCopyOutputBuffer* output) {
const size_t frame_size =
@@ -124,7 +124,7 @@ bool SerializeHeadersGivenEncoding(const SpdyHeadersIR& headers,
}
if (ret && headers.padding_payload_len() > 0) {
- SpdyString padding(headers.padding_payload_len(), 0);
+ std::string padding(headers.padding_payload_len(), 0);
ret &= builder.WriteBytes(padding.data(), padding.length());
}
@@ -138,7 +138,7 @@ bool SerializeHeadersGivenEncoding(const SpdyHeadersIR& headers,
// encoded header block. Does not need or use the SpdyHeaderBlock inside
// SpdyPushPromiseIR.
bool SerializePushPromiseGivenEncoding(const SpdyPushPromiseIR& push_promise,
- const SpdyString& encoding,
+ const std::string& encoding,
const bool end_headers,
ZeroCopyOutputBuffer* output) {
const size_t frame_size =
@@ -155,7 +155,7 @@ bool SerializePushPromiseGivenEncoding(const SpdyPushPromiseIR& push_promise,
ok = ok && builder.WriteUInt32(push_promise.promised_stream_id()) &&
builder.WriteBytes(encoding.data(), encoding.size());
if (ok && push_promise.padding_payload_len() > 0) {
- SpdyString padding(push_promise.padding_payload_len(), 0);
+ std::string padding(push_promise.padding_payload_len(), 0);
ok = builder.WriteBytes(padding.data(), padding.length());
}
@@ -166,7 +166,7 @@ bool SerializePushPromiseGivenEncoding(const SpdyPushPromiseIR& push_promise,
}
bool WritePayloadWithContinuation(SpdyFrameBuilder* builder,
- const SpdyString& hpack_encoding,
+ const std::string& hpack_encoding,
SpdyStreamId stream_id,
SpdyFrameType type,
int padding_payload_len) {
@@ -191,7 +191,7 @@ bool WritePayloadWithContinuation(SpdyFrameBuilder* builder,
bool ret = builder->WriteBytes(&hpack_encoding[0],
hpack_encoding.size() - bytes_remaining);
if (padding_payload_len > 0) {
- SpdyString padding = SpdyString(padding_payload_len, 0);
+ std::string padding = std::string(padding_payload_len, 0);
ret &= builder->WriteBytes(padding.data(), padding.length());
}
@@ -262,7 +262,7 @@ void SerializeSettingsBuilderHelper(const SpdySettingsIR& settings,
}
void SerializeAltSvcBuilderHelper(const SpdyAltSvcIR& altsvc_ir,
- SpdyString* value,
+ std::string* value,
size_t* size) {
*size = kGetAltSvcFrameMinimumSize;
*size = *size + altsvc_ir.origin().length();
@@ -301,7 +301,7 @@ size_t SpdyFramer::SpdyFrameIterator::NextFrame(ZeroCopyOutputBuffer* output) {
const size_t size_without_block =
is_first_frame_ ? GetFrameSizeSansBlock() : kContinuationFrameMinimumSize;
- auto encoding = SpdyMakeUnique<SpdyString>();
+ auto encoding = SpdyMakeUnique<std::string>();
encoder_->Next(kHttp2MaxControlFrameSendSize - size_without_block,
encoding.get());
has_next_frame_ = encoder_->HasNext();
@@ -353,7 +353,7 @@ size_t SpdyFramer::SpdyHeaderFrameIterator::GetFrameSizeSansBlock() const {
}
bool SpdyFramer::SpdyHeaderFrameIterator::SerializeGivenEncoding(
- const SpdyString& encoding,
+ const std::string& encoding,
ZeroCopyOutputBuffer* output) const {
return SerializeHeadersGivenEncoding(*headers_ir_, encoding,
!has_next_frame(), output);
@@ -378,7 +378,7 @@ size_t SpdyFramer::SpdyPushPromiseFrameIterator::GetFrameSizeSansBlock() const {
}
bool SpdyFramer::SpdyPushPromiseFrameIterator::SerializeGivenEncoding(
- const SpdyString& encoding,
+ const std::string& encoding,
ZeroCopyOutputBuffer* output) const {
return SerializePushPromiseGivenEncoding(*push_promise_ir_, encoding,
!has_next_frame(), output);
@@ -446,7 +446,7 @@ SpdySerializedFrame SpdyFramer::SerializeData(const SpdyDataIR& data_ir) {
}
builder.WriteBytes(data_ir.data(), data_ir.data_len());
if (data_ir.padding_payload_len() > 0) {
- SpdyString padding(data_ir.padding_payload_len(), 0);
+ std::string padding(data_ir.padding_payload_len(), 0);
builder.WriteBytes(padding.data(), padding.length());
}
DCHECK_EQ(size_with_padding, builder.length());
@@ -552,7 +552,7 @@ SpdySerializedFrame SpdyFramer::SerializeGoAway(
void SpdyFramer::SerializeHeadersBuilderHelper(const SpdyHeadersIR& headers,
uint8_t* flags,
size_t* size,
- SpdyString* hpack_encoding,
+ std::string* hpack_encoding,
int* weight,
size_t* length_field) {
if (headers.fin()) {
@@ -608,7 +608,7 @@ SpdySerializedFrame SpdyFramer::SerializeHeaders(const SpdyHeadersIR& headers) {
// The size of this frame, including padding (if there is any) and
// variable-length header block.
size_t size = 0;
- SpdyString hpack_encoding;
+ std::string hpack_encoding;
int weight = 0;
size_t length_field = 0;
SerializeHeadersBuilderHelper(headers, &flags, &size, &hpack_encoding,
@@ -658,7 +658,7 @@ SpdySerializedFrame SpdyFramer::SerializeWindowUpdate(
void SpdyFramer::SerializePushPromiseBuilderHelper(
const SpdyPushPromiseIR& push_promise,
uint8_t* flags,
- SpdyString* hpack_encoding,
+ std::string* hpack_encoding,
size_t* size) {
*flags = 0;
// This will get overwritten if we overflow into a CONTINUATION frame.
@@ -686,7 +686,7 @@ SpdySerializedFrame SpdyFramer::SerializePushPromise(
const SpdyPushPromiseIR& push_promise) {
uint8_t flags = 0;
size_t size = 0;
- SpdyString hpack_encoding;
+ std::string hpack_encoding;
SerializePushPromiseBuilderHelper(push_promise, &flags, &hpack_encoding,
&size);
@@ -725,7 +725,7 @@ SpdySerializedFrame SpdyFramer::SerializePushPromise(
SpdySerializedFrame SpdyFramer::SerializeContinuation(
const SpdyContinuationIR& continuation) const {
- const SpdyString& encoding = continuation.encoding();
+ const std::string& encoding = continuation.encoding();
size_t frame_size = kContinuationFrameMinimumSize + encoding.size();
SpdyFrameBuilder builder(frame_size);
uint8_t flags = continuation.end_headers() ? HEADERS_FLAG_END_HEADERS : 0;
@@ -738,7 +738,7 @@ SpdySerializedFrame SpdyFramer::SerializeContinuation(
}
SpdySerializedFrame SpdyFramer::SerializeAltSvc(const SpdyAltSvcIR& altsvc_ir) {
- SpdyString value;
+ std::string value;
size_t size = 0;
SerializeAltSvcBuilderHelper(altsvc_ir, &value, &size);
SpdyFrameBuilder builder(size);
@@ -942,8 +942,8 @@ bool SpdyFramer::SerializeData(const SpdyDataIR& data_ir,
ok = ok && builder.WriteBytes(data_ir.data(), data_ir.data_len());
if (data_ir.padding_payload_len() > 0) {
- SpdyString padding;
- padding = SpdyString(data_ir.padding_payload_len(), 0);
+ std::string padding;
+ padding = std::string(data_ir.padding_payload_len(), 0);
ok = ok && builder.WriteBytes(padding.data(), padding.length());
}
DCHECK_EQ(size_with_padding, builder.length());
@@ -1054,7 +1054,7 @@ bool SpdyFramer::SerializeHeaders(const SpdyHeadersIR& headers,
// The size of this frame, including padding (if there is any) and
// variable-length header block.
size_t size = 0;
- SpdyString hpack_encoding;
+ std::string hpack_encoding;
int weight = 0;
size_t length_field = 0;
SerializeHeadersBuilderHelper(headers, &flags, &size, &hpack_encoding,
@@ -1107,7 +1107,7 @@ bool SpdyFramer::SerializePushPromise(const SpdyPushPromiseIR& push_promise,
ZeroCopyOutputBuffer* output) {
uint8_t flags = 0;
size_t size = 0;
- SpdyString hpack_encoding;
+ std::string hpack_encoding;
SerializePushPromiseBuilderHelper(push_promise, &flags, &hpack_encoding,
&size);
@@ -1148,7 +1148,7 @@ bool SpdyFramer::SerializePushPromise(const SpdyPushPromiseIR& push_promise,
bool SpdyFramer::SerializeContinuation(const SpdyContinuationIR& continuation,
ZeroCopyOutputBuffer* output) const {
- const SpdyString& encoding = continuation.encoding();
+ const std::string& encoding = continuation.encoding();
size_t frame_size = kContinuationFrameMinimumSize + encoding.size();
SpdyFrameBuilder builder(frame_size, output);
uint8_t flags = continuation.end_headers() ? HEADERS_FLAG_END_HEADERS : 0;
@@ -1163,7 +1163,7 @@ bool SpdyFramer::SerializeContinuation(const SpdyContinuationIR& continuation,
bool SpdyFramer::SerializeAltSvc(const SpdyAltSvcIR& altsvc_ir,
ZeroCopyOutputBuffer* output) {
- SpdyString value;
+ std::string value;
size_t size = 0;
SerializeAltSvcBuilderHelper(altsvc_ir, &value, &size);
SpdyFrameBuilder builder(size, output);
diff --git a/chromium/net/third_party/quiche/src/spdy/core/spdy_framer.h b/chromium/net/third_party/quiche/src/spdy/core/spdy_framer.h
index e268994e89b..45d1f86f33c 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/spdy_framer.h
+++ b/chromium/net/third_party/quiche/src/spdy/core/spdy_framer.h
@@ -10,6 +10,7 @@
#include <cstdint>
#include <map>
#include <memory>
+#include <string>
#include <utility>
#include "net/third_party/quiche/src/spdy/core/hpack/hpack_encoder.h"
@@ -19,7 +20,6 @@
#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h"
#include "net/third_party/quiche/src/spdy/core/zero_copy_output_buffer.h"
#include "net/third_party/quiche/src/spdy/platform/api/spdy_export.h"
-#include "net/third_party/quiche/src/spdy/platform/api/spdy_string.h"
#include "net/third_party/quiche/src/spdy/platform/api/spdy_string_piece.h"
namespace spdy {
@@ -258,7 +258,7 @@ class SPDY_EXPORT_PRIVATE SpdyFramer {
protected:
virtual size_t GetFrameSizeSansBlock() const = 0;
- virtual bool SerializeGivenEncoding(const SpdyString& encoding,
+ virtual bool SerializeGivenEncoding(const std::string& encoding,
ZeroCopyOutputBuffer* output) const = 0;
SpdyFramer* GetFramer() const { return framer_; }
@@ -291,7 +291,7 @@ class SPDY_EXPORT_PRIVATE SpdyFramer {
private:
const SpdyFrameIR& GetIR() const override;
size_t GetFrameSizeSansBlock() const override;
- bool SerializeGivenEncoding(const SpdyString& encoding,
+ bool SerializeGivenEncoding(const std::string& encoding,
ZeroCopyOutputBuffer* output) const override;
const std::unique_ptr<const SpdyHeadersIR> headers_ir_;
@@ -313,7 +313,7 @@ class SPDY_EXPORT_PRIVATE SpdyFramer {
private:
const SpdyFrameIR& GetIR() const override;
size_t GetFrameSizeSansBlock() const override;
- bool SerializeGivenEncoding(const SpdyString& encoding,
+ bool SerializeGivenEncoding(const std::string& encoding,
ZeroCopyOutputBuffer* output) const override;
const std::unique_ptr<const SpdyPushPromiseIR> push_promise_ir_;
@@ -344,12 +344,12 @@ class SPDY_EXPORT_PRIVATE SpdyFramer {
void SerializeHeadersBuilderHelper(const SpdyHeadersIR& headers,
uint8_t* flags,
size_t* size,
- SpdyString* hpack_encoding,
+ std::string* hpack_encoding,
int* weight,
size_t* length_field);
void SerializePushPromiseBuilderHelper(const SpdyPushPromiseIR& push_promise,
uint8_t* flags,
- SpdyString* hpack_encoding,
+ std::string* hpack_encoding,
size_t* size);
std::unique_ptr<HpackEncoder> hpack_encoder_;
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 abca5a790d3..a424adb565a 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
@@ -24,7 +24,6 @@
#include "net/third_party/quiche/src/spdy/platform/api/spdy_flags.h"
#include "net/third_party/quiche/src/spdy/platform/api/spdy_logging.h"
#include "net/third_party/quiche/src/spdy/platform/api/spdy_ptr_util.h"
-#include "net/third_party/quiche/src/spdy/platform/api/spdy_string.h"
#include "net/third_party/quiche/src/spdy/platform/api/spdy_string_utils.h"
#include "net/third_party/quiche/src/spdy/platform/api/spdy_test.h"
@@ -411,7 +410,7 @@ class TestSpdyVisitor : public SpdyFramerVisitorInterface,
<< "\", altsvc_vector)";
test_altsvc_ir_ = SpdyMakeUnique<SpdyAltSvcIR>(stream_id);
if (origin.length() > 0) {
- test_altsvc_ir_->set_origin(SpdyString(origin));
+ test_altsvc_ir_->set_origin(std::string(origin));
}
for (const auto& altsvc : altsvc_vector) {
test_altsvc_ir_->add_altsvc(altsvc);
@@ -568,7 +567,7 @@ class TestExtension : public ExtensionVisitorInterface {
size_t length_ = 0;
uint8_t type_ = 0;
uint8_t flags_ = 0;
- SpdyString payload_;
+ std::string payload_;
};
// Exposes SpdyUnknownIR::set_length() for testing purposes.
@@ -600,7 +599,7 @@ class SpdyFramerTest : public ::testing::TestWithParam<Output> {
}
}
- void CompareFrame(const SpdyString& description,
+ void CompareFrame(const std::string& description,
const SpdySerializedFrame& actual_frame,
const unsigned char* expected,
const int expected_len) {
@@ -1034,7 +1033,7 @@ TEST_P(SpdyFramerTest, ContinuationWithStreamIdZero) {
SpdyContinuationIR continuation(/* stream_id = */ 0);
auto some_nonsense_encoding =
- SpdyMakeUnique<SpdyString>("some nonsense encoding");
+ SpdyMakeUnique<std::string>("some nonsense encoding");
continuation.take_encoding(std::move(some_nonsense_encoding));
continuation.set_end_headers(true);
SpdySerializedFrame frame(framer_.SerializeContinuation(continuation));
@@ -1101,11 +1100,11 @@ TEST_P(SpdyFramerTest, PushPromiseWithPromisedStreamIdZero) {
TEST_P(SpdyFramerTest, MultiValueHeader) {
SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION);
- SpdyString value("value1\0value2", 13);
+ std::string value("value1\0value2", 13);
// TODO(jgraettinger): If this pattern appears again, move to test class.
SpdyHeaderBlock header_set;
header_set["name"] = value;
- SpdyString buffer;
+ std::string buffer;
HpackEncoder encoder(ObtainHpackHuffmanTable());
encoder.DisableCompression();
encoder.EncodeHeaderSet(header_set, &buffer);
@@ -2308,7 +2307,7 @@ TEST_P(SpdyFramerTest, CreateContinuationUncompressed) {
SpdyHeaderBlock header_block;
header_block["bar"] = "foo";
header_block["foo"] = "bar";
- auto buffer = SpdyMakeUnique<SpdyString>();
+ auto buffer = SpdyMakeUnique<std::string>();
HpackEncoder encoder(ObtainHpackHuffmanTable());
encoder.DisableCompression();
encoder.EncodeHeaderSet(header_block, buffer.get());
@@ -2426,7 +2425,7 @@ TEST_P(SpdyFramerTest, CreatePushPromiseThenContinuationUncompressed) {
SpdyPushPromiseIR push_promise(/* stream_id = */ 42,
/* promised_stream_id = */ 57);
push_promise.set_padding_len(1);
- SpdyString big_value(kHttp2MaxControlFrameSendSize, 'x');
+ std::string big_value(kHttp2MaxControlFrameSendSize, 'x');
push_promise.SetHeader("xxx", big_value);
SpdySerializedFrame frame(SpdyFramerPeer::SerializePushPromise(
&framer, push_promise, use_output_ ? &output_ : nullptr));
@@ -2617,7 +2616,7 @@ TEST_P(SpdyFramerTest, TooLargeHeadersFrameUsesContinuation) {
// Exact payload length will change with HPACK, but this should be long
// enough to cause an overflow.
const size_t kBigValueSize = kHttp2MaxControlFrameSendSize;
- SpdyString big_value(kBigValueSize, 'x');
+ std::string big_value(kBigValueSize, 'x');
headers.SetHeader("aa", big_value);
SpdySerializedFrame control_frame(SpdyFramerPeer::SerializeHeaders(
&framer, headers, use_output_ ? &output_ : nullptr));
@@ -2642,9 +2641,9 @@ TEST_P(SpdyFramerTest, MultipleContinuationFramesWithIterator) {
// Exact payload length will change with HPACK, but this should be long
// enough to cause an overflow.
const size_t kBigValueSize = kHttp2MaxControlFrameSendSize;
- SpdyString big_valuex(kBigValueSize, 'x');
+ std::string big_valuex(kBigValueSize, 'x');
headers->SetHeader("aa", big_valuex);
- SpdyString big_valuez(kBigValueSize, 'z');
+ std::string big_valuez(kBigValueSize, 'z');
headers->SetHeader("bb", big_valuez);
SpdyFramer::SpdyHeaderFrameIterator frame_it(&framer, std::move(headers));
@@ -2707,9 +2706,9 @@ TEST_P(SpdyFramerTest, PushPromiseFramesWithIterator) {
// Exact payload length will change with HPACK, but this should be long
// enough to cause an overflow.
const size_t kBigValueSize = kHttp2MaxControlFrameSendSize;
- SpdyString big_valuex(kBigValueSize, 'x');
+ std::string big_valuex(kBigValueSize, 'x');
push_promise->SetHeader("aa", big_valuex);
- SpdyString big_valuez(kBigValueSize, 'z');
+ std::string big_valuez(kBigValueSize, 'z');
push_promise->SetHeader("bb", big_valuez);
SpdyFramer::SpdyPushPromiseFrameIterator frame_it(&framer,
@@ -2836,7 +2835,7 @@ TEST_P(SpdyFramerTest, TooLargePushPromiseFrameUsesContinuation) {
// Exact payload length will change with HPACK, but this should be long
// enough to cause an overflow.
const size_t kBigValueSize = kHttp2MaxControlFrameSendSize;
- SpdyString big_value(kBigValueSize, 'x');
+ std::string big_value(kBigValueSize, 'x');
push_promise.SetHeader("aa", big_value);
SpdySerializedFrame control_frame(SpdyFramerPeer::SerializePushPromise(
&framer, push_promise, use_output_ ? &output_ : nullptr));
@@ -2861,7 +2860,7 @@ TEST_P(SpdyFramerTest, ControlFrameMuchTooLarge) {
const size_t kHeaderBufferSize =
kHttp2DefaultFramePayloadLimit / kHeaderBufferChunks;
const size_t kBigValueSize = kHeaderBufferSize * 2;
- SpdyString big_value(kBigValueSize, 'x');
+ std::string big_value(kBigValueSize, 'x');
SpdyHeadersIR headers(/* stream_id = */ 1);
headers.set_fin(true);
headers.SetHeader("aa", big_value);
@@ -2898,7 +2897,7 @@ TEST_P(SpdyFramerTest, ControlFrameSizesAreValidated) {
0x00, 0x00, 0x00, // Truncated Status Field
};
const size_t pad_length = length + kFrameHeaderSize - sizeof(kH2FrameData);
- SpdyString pad(pad_length, 'A');
+ std::string pad(pad_length, 'A');
TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION);
visitor.SimulateInFramer(kH2FrameData, sizeof(kH2FrameData));
@@ -3649,7 +3648,7 @@ TEST_P(SpdyFramerTest, ReadUnknownExtensionFrameWithExtension) {
EXPECT_EQ(20u, extension.length_);
EXPECT_EQ(255, extension.type_);
EXPECT_EQ(0xff, extension.flags_);
- EXPECT_EQ(SpdyString(20, '\xff'), extension.payload_);
+ EXPECT_EQ(std::string(20, '\xff'), extension.payload_);
// Follow it up with a valid control frame to make sure we handle
// subsequent frames correctly.
@@ -4646,7 +4645,7 @@ TEST_P(SpdyFramerTest, ProcessAllInput) {
SPDY_VLOG(1) << "frame1_size = " << frame1_size;
SPDY_VLOG(1) << "frame2_size = " << frame2_size;
- SpdyString input_buffer;
+ std::string input_buffer;
input_buffer.append(frame1.data(), frame1_size);
input_buffer.append(frame2.data(), frame2_size);
@@ -4693,7 +4692,7 @@ TEST_P(SpdyFramerTest, ProcessAtMostOneFrame) {
SPDY_VLOG(1) << "frame1_size = " << frame1_size;
SPDY_VLOG(1) << "frame2_size = " << frame2_size;
- SpdyString input_buffer;
+ std::string input_buffer;
input_buffer.append(frame1.data(), frame1_size);
input_buffer.append(frame2.data(), frame2_size);
@@ -4792,8 +4791,8 @@ TEST_P(SpdyFramerTest, SpdyFrameIRSize) {
CheckFrameAndIRSize(&headers_ir, &framer, &output_);
SpdyHeadersIR headers_ir_with_continuation(1);
- headers_ir_with_continuation.SetHeader("alpha", SpdyString(100000, 'x'));
- headers_ir_with_continuation.SetHeader("beta", SpdyString(100000, 'x'));
+ headers_ir_with_continuation.SetHeader("alpha", std::string(100000, 'x'));
+ headers_ir_with_continuation.SetHeader("beta", std::string(100000, 'x'));
headers_ir_with_continuation.SetHeader("cookie", "key1=value1; key2=value2");
CheckFrameAndIRSize(&headers_ir_with_continuation, &framer, &output_);
@@ -4801,8 +4800,8 @@ TEST_P(SpdyFramerTest, SpdyFrameIRSize) {
CheckFrameAndIRSize(&window_update_ir, &framer, &output_);
SpdyPushPromiseIR push_promise_ir(3, 8);
- push_promise_ir.SetHeader("alpha", SpdyString(100000, 'x'));
- push_promise_ir.SetHeader("beta", SpdyString(100000, 'x'));
+ push_promise_ir.SetHeader("alpha", std::string(100000, 'x'));
+ push_promise_ir.SetHeader("beta", std::string(100000, 'x'));
push_promise_ir.SetHeader("cookie", "key1=value1; key2=value2");
CheckFrameAndIRSize(&push_promise_ir, &framer, &output_);
diff --git a/chromium/net/third_party/quiche/src/spdy/core/spdy_header_block.cc b/chromium/net/third_party/quiche/src/spdy/core/spdy_header_block.cc
index c99bbf32e3c..705038a573a 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/spdy_header_block.cc
+++ b/chromium/net/third_party/quiche/src/spdy/core/spdy_header_block.cc
@@ -218,11 +218,11 @@ SpdyHeaderBlock::ValueProxy& SpdyHeaderBlock::ValueProxy::operator=(
return *this;
}
-SpdyString SpdyHeaderBlock::ValueProxy::as_string() const {
+std::string SpdyHeaderBlock::ValueProxy::as_string() const {
if (lookup_result_ == block_->end()) {
return "";
} else {
- return SpdyString(lookup_result_->second.value());
+ return std::string(lookup_result_->second.value());
}
}
@@ -262,12 +262,12 @@ bool SpdyHeaderBlock::operator!=(const SpdyHeaderBlock& other) const {
return !(operator==(other));
}
-SpdyString SpdyHeaderBlock::DebugString() const {
+std::string SpdyHeaderBlock::DebugString() const {
if (empty()) {
return "{}";
}
- SpdyString output = "\n{\n";
+ std::string output = "\n{\n";
for (auto it = begin(); it != end(); ++it) {
SpdyStrAppend(&output, " ", it->first, " ", it->second, "\n");
}
diff --git a/chromium/net/third_party/quiche/src/spdy/core/spdy_header_block.h b/chromium/net/third_party/quiche/src/spdy/core/spdy_header_block.h
index f5795790e5e..71e1537831b 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/spdy_header_block.h
+++ b/chromium/net/third_party/quiche/src/spdy/core/spdy_header_block.h
@@ -9,13 +9,13 @@
#include <list>
#include <memory>
+#include <string>
#include <utility>
#include <vector>
#include "net/third_party/quiche/src/spdy/platform/api/spdy_containers.h"
#include "net/third_party/quiche/src/spdy/platform/api/spdy_export.h"
#include "net/third_party/quiche/src/spdy/platform/api/spdy_macros.h"
-#include "net/third_party/quiche/src/spdy/platform/api/spdy_string.h"
#include "net/third_party/quiche/src/spdy/platform/api/spdy_string_piece.h"
namespace spdy {
@@ -149,7 +149,7 @@ class SPDY_EXPORT_PRIVATE SpdyHeaderBlock {
// Provides a human readable multi-line representation of the stored header
// keys and values.
- SpdyString DebugString() const;
+ std::string DebugString() const;
iterator begin() { return iterator(block_.begin()); }
iterator end() { return iterator(block_.end()); }
@@ -183,7 +183,8 @@ class SPDY_EXPORT_PRIVATE SpdyHeaderBlock {
SPDY_MUST_USE_RESULT ValueProxy operator[](const SpdyStringPiece key);
// This object provides automatic conversions that allow SpdyHeaderBlock to be
- // nearly a drop-in replacement for SpdyLinkedHashMap<SpdyString, SpdyString>.
+ // nearly a drop-in replacement for
+ // SpdyLinkedHashMap<std::string, std::string>.
// It reads data from or writes data to a SpdyHeaderBlock::Storage.
class SPDY_EXPORT_PRIVATE ValueProxy {
public:
@@ -200,7 +201,7 @@ class SPDY_EXPORT_PRIVATE SpdyHeaderBlock {
// Assignment modifies the underlying SpdyHeaderBlock.
ValueProxy& operator=(const SpdyStringPiece other);
- SpdyString as_string() const;
+ std::string as_string() const;
private:
friend class SpdyHeaderBlock;
diff --git a/chromium/net/third_party/quiche/src/spdy/core/spdy_header_block_test.cc b/chromium/net/third_party/quiche/src/spdy/core/spdy_header_block_test.cc
index f8694319d7c..c34b718a1a4 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/spdy_header_block_test.cc
+++ b/chromium/net/third_party/quiche/src/spdy/core/spdy_header_block_test.cc
@@ -69,15 +69,15 @@ TEST(SpdyHeaderBlockTest, KeyMemoryReclaimedOnLookup) {
// This test verifies that headers can be set in a variety of ways.
TEST(SpdyHeaderBlockTest, AddHeaders) {
SpdyHeaderBlock block;
- block["foo"] = SpdyString(300, 'x');
+ block["foo"] = std::string(300, 'x');
block["bar"] = "baz";
block["qux"] = "qux1";
block["qux"] = "qux2";
block.insert(std::make_pair("key", "value"));
- EXPECT_EQ(Pair("foo", SpdyString(300, 'x')), *block.find("foo"));
+ EXPECT_EQ(Pair("foo", std::string(300, 'x')), *block.find("foo"));
EXPECT_EQ("baz", block["bar"]);
- SpdyString qux("qux");
+ std::string qux("qux");
EXPECT_EQ("qux2", block[qux]);
ASSERT_NE(block.end(), block.find("key"));
EXPECT_EQ(Pair("key", "value"), *block.find("key"));
@@ -89,7 +89,7 @@ TEST(SpdyHeaderBlockTest, AddHeaders) {
// This test verifies that SpdyHeaderBlock can be copied using Clone().
TEST(SpdyHeaderBlockTest, CopyBlocks) {
SpdyHeaderBlock block1;
- block1["foo"] = SpdyString(300, 'x');
+ block1["foo"] = std::string(300, 'x');
block1["bar"] = "baz";
block1.insert(std::make_pair("qux", "qux1"));
@@ -147,7 +147,7 @@ TEST(SpdyHeaderBlockTest, AppendHeaders) {
SpdyHeaderBlock block;
block["foo"] = "foo";
block.AppendValueOrAddHeader("foo", "bar");
- EXPECT_EQ(Pair("foo", SpdyString("foo\0bar", 7)), *block.find("foo"));
+ EXPECT_EQ(Pair("foo", std::string("foo\0bar", 7)), *block.find("foo"));
block.insert(std::make_pair("foo", "baz"));
EXPECT_EQ("baz", block["foo"]);
@@ -171,9 +171,9 @@ TEST(SpdyHeaderBlockTest, AppendHeaders) {
EXPECT_EQ("key1=value1; key2=value2; key3=value3", block["cookie"]);
EXPECT_EQ("baz", block["foo"]);
- EXPECT_EQ(SpdyString("h1v1\0h1v2\0h1v3", 14), block["h1"]);
- EXPECT_EQ(SpdyString("h2v1\0h2v2\0h2v3", 14), block["h2"]);
- EXPECT_EQ(SpdyString("h3v2\0h3v3", 9), block["h3"]);
+ EXPECT_EQ(std::string("h1v1\0h1v2\0h1v3", 14), block["h1"]);
+ EXPECT_EQ(std::string("h2v1\0h2v2\0h2v3", 14), block["h2"]);
+ EXPECT_EQ(std::string("h3v2\0h3v3", 9), block["h3"]);
EXPECT_EQ("singleton", block["h4"]);
}
@@ -217,20 +217,20 @@ size_t SpdyHeaderBlockSize(const SpdyHeaderBlock& block) {
TEST(SpdyHeaderBlockTest, TotalBytesUsed) {
SpdyHeaderBlock block;
const size_t value_size = 300;
- block["foo"] = SpdyString(value_size, 'x');
+ block["foo"] = std::string(value_size, 'x');
EXPECT_EQ(block.TotalBytesUsed(), SpdyHeaderBlockSize(block));
- block.insert(std::make_pair("key", SpdyString(value_size, 'x')));
+ block.insert(std::make_pair("key", std::string(value_size, 'x')));
EXPECT_EQ(block.TotalBytesUsed(), SpdyHeaderBlockSize(block));
- block.AppendValueOrAddHeader("abc", SpdyString(value_size, 'x'));
+ block.AppendValueOrAddHeader("abc", std::string(value_size, 'x'));
EXPECT_EQ(block.TotalBytesUsed(), SpdyHeaderBlockSize(block));
// Replace value for existing key.
- block["foo"] = SpdyString(value_size, 'x');
+ block["foo"] = std::string(value_size, 'x');
EXPECT_EQ(block.TotalBytesUsed(), SpdyHeaderBlockSize(block));
- block.insert(std::make_pair("key", SpdyString(value_size, 'x')));
+ block.insert(std::make_pair("key", std::string(value_size, 'x')));
EXPECT_EQ(block.TotalBytesUsed(), SpdyHeaderBlockSize(block));
// Add value for existing key.
- block.AppendValueOrAddHeader("abc", SpdyString(value_size, 'x'));
+ block.AppendValueOrAddHeader("abc", std::string(value_size, 'x'));
EXPECT_EQ(block.TotalBytesUsed(), SpdyHeaderBlockSize(block));
// Copies/clones SpdyHeaderBlock.
diff --git a/chromium/net/third_party/quiche/src/spdy/core/spdy_intrusive_list_test.cc b/chromium/net/third_party/quiche/src/spdy/core/spdy_intrusive_list_test.cc
index eee65e34c29..7fecec4a166 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/spdy_intrusive_list_test.cc
+++ b/chromium/net/third_party/quiche/src/spdy/core/spdy_intrusive_list_test.cc
@@ -7,9 +7,9 @@
#include <algorithm>
#include <cstddef>
#include <list>
+#include <string>
#include <utility>
-#include "net/third_party/quiche/src/spdy/platform/api/spdy_string.h"
#include "net/third_party/quiche/src/spdy/platform/api/spdy_test.h"
namespace spdy {
@@ -72,18 +72,18 @@ class IntrusiveListTest : public ::testing::Test {
TEST(NewIntrusiveListTest, Basic) {
TestList list1;
- CHECK_EQ(sizeof(SpdyIntrusiveLink<TestItem>), sizeof(void *) * 2);
+ EXPECT_EQ(sizeof(SpdyIntrusiveLink<TestItem>), sizeof(void*) * 2);
for (int i = 0; i < 10; ++i) {
TestItem *e = new TestItem;
e->n = i;
list1.push_front(e);
}
- CHECK_EQ(list1.size(), 10);
+ EXPECT_EQ(list1.size(), 10u);
// Verify we can reverse a list because we defined swap for TestItem.
std::reverse(list1.begin(), list1.end());
- CHECK_EQ(list1.size(), 10);
+ EXPECT_EQ(list1.size(), 10u);
// Check both const and non-const forward iteration.
const TestList& clist1 = list1;
@@ -92,28 +92,28 @@ TEST(NewIntrusiveListTest, Basic) {
for (;
iter != list1.end();
++iter, ++i) {
- CHECK_EQ(iter->n, i);
+ EXPECT_EQ(iter->n, i);
}
- CHECK(iter == clist1.end());
- CHECK(iter != clist1.begin());
+ EXPECT_EQ(iter, clist1.end());
+ EXPECT_NE(iter, clist1.begin());
i = 0;
iter = list1.begin();
for (;
iter != list1.end();
++iter, ++i) {
- CHECK_EQ(iter->n, i);
+ EXPECT_EQ(iter->n, i);
}
- CHECK(iter == clist1.end());
- CHECK(iter != clist1.begin());
+ EXPECT_EQ(iter, clist1.end());
+ EXPECT_NE(iter, clist1.begin());
- CHECK_EQ(list1.front().n, 0);
- CHECK_EQ(list1.back().n, 9);
+ EXPECT_EQ(list1.front().n, 0);
+ EXPECT_EQ(list1.back().n, 9);
// Verify we can swap 2 lists.
TestList list2;
list2.swap(list1);
- CHECK_EQ(list1.size(), 0);
- CHECK_EQ(list2.size(), 10);
+ EXPECT_EQ(list1.size(), 0u);
+ EXPECT_EQ(list2.size(), 10u);
// Check both const and non-const reverse iteration.
const TestList& clist2 = list2;
@@ -122,20 +122,20 @@ TEST(NewIntrusiveListTest, Basic) {
for (;
riter != list2.rend();
++riter, --i) {
- CHECK_EQ(riter->n, i);
+ EXPECT_EQ(riter->n, i);
}
- CHECK(riter == clist2.rend());
- CHECK(riter != clist2.rbegin());
+ EXPECT_EQ(riter, clist2.rend());
+ EXPECT_NE(riter, clist2.rbegin());
riter = list2.rbegin();
i = 9;
for (;
riter != list2.rend();
++riter, --i) {
- CHECK_EQ(riter->n, i);
+ EXPECT_EQ(riter->n, i);
}
- CHECK(riter == clist2.rend());
- CHECK(riter != clist2.rbegin());
+ EXPECT_EQ(riter, clist2.rend());
+ EXPECT_NE(riter, clist2.rbegin());
while (!list2.empty()) {
TestItem *e = &list2.front();
@@ -156,12 +156,12 @@ TEST(NewIntrusiveListTest, Erase) {
// Test that erase works.
for (int i = 0; i < 10; ++i) {
- CHECK_EQ(l.size(), (10 - i));
+ EXPECT_EQ(l.size(), (10u - i));
TestList::iterator iter = l.erase(e[i]);
- CHECK(iter != TestList::iterator(e[i]));
+ EXPECT_NE(iter, TestList::iterator(e[i]));
- CHECK_EQ(l.size(), (10 - i - 1));
+ EXPECT_EQ(l.size(), (10u - i - 1));
delete e[i];
}
}
@@ -175,15 +175,15 @@ TEST(NewIntrusiveListTest, Insert) {
for (int i = 9; i >= 0; --i) {
e[i] = new TestItem;
iter = l.insert(iter, e[i]);
- CHECK_EQ(&(*iter), e[i]);
+ EXPECT_EQ(&(*iter), e[i]);
}
- CHECK_EQ(l.size(), 10);
+ EXPECT_EQ(l.size(), 10u);
// Verify insertion order.
iter = l.begin();
for (TestItem *item : e) {
- CHECK_EQ(&(*iter), item);
+ EXPECT_EQ(&(*iter), item);
iter = l.erase(item);
delete item;
}
@@ -264,7 +264,7 @@ TEST_F(IntrusiveListTest, Splice) {
CheckLists();
- ASSERT_EQ(3, secondary_list.size());
+ ASSERT_EQ(3u, secondary_list.size());
for (int i = 0; i < 3; ++i) {
EXPECT_EQ(&e[i], &*std::next(secondary_list.begin(), i));
}
@@ -282,24 +282,24 @@ struct DerivedLinkId {};
struct AbstractBase : public SpdyIntrusiveLink<AbstractBase, BaseLinkId> {
virtual ~AbstractBase() = 0;
- virtual SpdyString name() { return "AbstractBase"; }
+ virtual std::string name() { return "AbstractBase"; }
};
AbstractBase::~AbstractBase() {}
struct DerivedClass : public SpdyIntrusiveLink<DerivedClass, DerivedLinkId>,
public AbstractBase {
virtual ~DerivedClass() {}
- virtual SpdyString name() { return "DerivedClass"; }
+ virtual std::string name() { return "DerivedClass"; }
};
struct VirtuallyDerivedBaseClass : public virtual AbstractBase {
virtual ~VirtuallyDerivedBaseClass() = 0;
- virtual SpdyString name() { return "VirtuallyDerivedBaseClass"; }
+ virtual std::string name() { return "VirtuallyDerivedBaseClass"; }
};
VirtuallyDerivedBaseClass::~VirtuallyDerivedBaseClass() {}
struct VirtuallyDerivedClassA
: public SpdyIntrusiveLink<VirtuallyDerivedClassA, DerivedLinkId>,
public virtual VirtuallyDerivedBaseClass {
virtual ~VirtuallyDerivedClassA() {}
- virtual SpdyString name() { return "VirtuallyDerivedClassA"; }
+ virtual std::string name() { return "VirtuallyDerivedClassA"; }
};
struct NonceClass {
virtual ~NonceClass() {}
@@ -310,7 +310,7 @@ struct VirtuallyDerivedClassB
public virtual NonceClass,
public virtual VirtuallyDerivedBaseClass {
virtual ~VirtuallyDerivedClassB() {}
- virtual SpdyString name() { return "VirtuallyDerivedClassB"; }
+ virtual std::string name() { return "VirtuallyDerivedClassB"; }
};
struct VirtuallyDerivedClassC
: public SpdyIntrusiveLink<VirtuallyDerivedClassC, DerivedLinkId>,
@@ -318,7 +318,7 @@ struct VirtuallyDerivedClassC
public virtual NonceClass,
public virtual VirtuallyDerivedBaseClass {
virtual ~VirtuallyDerivedClassC() {}
- virtual SpdyString name() { return "VirtuallyDerivedClassC"; }
+ virtual std::string name() { return "VirtuallyDerivedClassC"; }
};
// Test for multiple layers between the element type and the link.
@@ -338,11 +338,11 @@ TEST(NewIntrusiveListTest, HandleInheritanceHierarchies) {
DerivedClass elements[2];
EXPECT_TRUE(list.empty());
list.push_back(&elements[0]);
- EXPECT_EQ(1, list.size());
+ EXPECT_EQ(1u, list.size());
list.push_back(&elements[1]);
- EXPECT_EQ(2, list.size());
+ EXPECT_EQ(2u, list.size());
list.pop_back();
- EXPECT_EQ(1, list.size());
+ EXPECT_EQ(1u, list.size());
list.pop_back();
EXPECT_TRUE(list.empty());
}
@@ -351,11 +351,11 @@ TEST(NewIntrusiveListTest, HandleInheritanceHierarchies) {
VirtuallyDerivedClassA elements[2];
EXPECT_TRUE(list.empty());
list.push_back(&elements[0]);
- EXPECT_EQ(1, list.size());
+ EXPECT_EQ(1u, list.size());
list.push_back(&elements[1]);
- EXPECT_EQ(2, list.size());
+ EXPECT_EQ(2u, list.size());
list.pop_back();
- EXPECT_EQ(1, list.size());
+ EXPECT_EQ(1u, list.size());
list.pop_back();
EXPECT_TRUE(list.empty());
}
@@ -364,11 +364,11 @@ TEST(NewIntrusiveListTest, HandleInheritanceHierarchies) {
VirtuallyDerivedClassC elements[2];
EXPECT_TRUE(list.empty());
list.push_back(&elements[0]);
- EXPECT_EQ(1, list.size());
+ EXPECT_EQ(1u, list.size());
list.push_back(&elements[1]);
- EXPECT_EQ(2, list.size());
+ EXPECT_EQ(2u, list.size());
list.pop_back();
- EXPECT_EQ(1, list.size());
+ EXPECT_EQ(1u, list.size());
list.pop_back();
EXPECT_TRUE(list.empty());
}
@@ -380,13 +380,13 @@ TEST(NewIntrusiveListTest, HandleInheritanceHierarchies) {
VirtuallyDerivedClassC d4;
EXPECT_TRUE(list.empty());
list.push_back(&d1);
- EXPECT_EQ(1, list.size());
+ EXPECT_EQ(1u, list.size());
list.push_back(&d2);
- EXPECT_EQ(2, list.size());
+ EXPECT_EQ(2u, list.size());
list.push_back(&d3);
- EXPECT_EQ(3, list.size());
+ EXPECT_EQ(3u, list.size());
list.push_back(&d4);
- EXPECT_EQ(4, list.size());
+ EXPECT_EQ(4u, list.size());
SpdyIntrusiveList<AbstractBase, BaseLinkId>::iterator it = list.begin();
EXPECT_EQ("DerivedClass", (it++)->name());
EXPECT_EQ("VirtuallyDerivedClassA", (it++)->name());
@@ -398,11 +398,11 @@ TEST(NewIntrusiveListTest, HandleInheritanceHierarchies) {
templated_base_link::DerivedClass elements[2];
EXPECT_TRUE(list.empty());
list.push_back(&elements[0]);
- EXPECT_EQ(1, list.size());
+ EXPECT_EQ(1u, list.size());
list.push_back(&elements[1]);
- EXPECT_EQ(2, list.size());
+ EXPECT_EQ(2u, list.size());
list.pop_back();
- EXPECT_EQ(1, list.size());
+ EXPECT_EQ(1u, list.size());
list.pop_back();
EXPECT_TRUE(list.empty());
}
diff --git a/chromium/net/third_party/quiche/src/spdy/core/spdy_pinnable_buffer_piece_test.cc b/chromium/net/third_party/quiche/src/spdy/core/spdy_pinnable_buffer_piece_test.cc
index d62af5bf37a..9c7f1384fc7 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/spdy_pinnable_buffer_piece_test.cc
+++ b/chromium/net/third_party/quiche/src/spdy/core/spdy_pinnable_buffer_piece_test.cc
@@ -4,8 +4,9 @@
#include "net/third_party/quiche/src/spdy/core/spdy_pinnable_buffer_piece.h"
+#include <string>
+
#include "net/third_party/quiche/src/spdy/core/spdy_prefixed_buffer_reader.h"
-#include "net/third_party/quiche/src/spdy/platform/api/spdy_string.h"
#include "net/third_party/quiche/src/spdy/platform/api/spdy_test.h"
namespace spdy {
@@ -14,14 +15,14 @@ namespace test {
class SpdyPinnableBufferPieceTest : public ::testing::Test {
protected:
- SpdyPrefixedBufferReader Build(const SpdyString& prefix,
- const SpdyString& suffix) {
+ SpdyPrefixedBufferReader Build(const std::string& prefix,
+ const std::string& suffix) {
prefix_ = prefix;
suffix_ = suffix;
return SpdyPrefixedBufferReader(prefix_.data(), prefix_.length(),
suffix_.data(), suffix_.length());
}
- SpdyString prefix_, suffix_;
+ std::string prefix_, suffix_;
};
TEST_F(SpdyPinnableBufferPieceTest, Pin) {
diff --git a/chromium/net/third_party/quiche/src/spdy/core/spdy_prefixed_buffer_reader_test.cc b/chromium/net/third_party/quiche/src/spdy/core/spdy_prefixed_buffer_reader_test.cc
index f570dfc411d..a0f9257f28a 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/spdy_prefixed_buffer_reader_test.cc
+++ b/chromium/net/third_party/quiche/src/spdy/core/spdy_prefixed_buffer_reader_test.cc
@@ -4,7 +4,8 @@
#include "net/third_party/quiche/src/spdy/core/spdy_prefixed_buffer_reader.h"
-#include "net/third_party/quiche/src/spdy/platform/api/spdy_string.h"
+#include <string>
+
#include "net/third_party/quiche/src/spdy/platform/api/spdy_string_piece.h"
#include "net/third_party/quiche/src/spdy/platform/api/spdy_test.h"
@@ -16,14 +17,14 @@ using testing::ElementsAreArray;
class SpdyPrefixedBufferReaderTest : public ::testing::Test {
protected:
- SpdyPrefixedBufferReader Build(const SpdyString& prefix,
- const SpdyString& suffix) {
+ SpdyPrefixedBufferReader Build(const std::string& prefix,
+ const std::string& suffix) {
prefix_ = prefix;
suffix_ = suffix;
return SpdyPrefixedBufferReader(prefix_.data(), prefix_.length(),
suffix_.data(), suffix_.length());
}
- SpdyString prefix_, suffix_;
+ std::string prefix_, suffix_;
};
TEST_F(SpdyPrefixedBufferReaderTest, ReadRawFromPrefix) {
diff --git a/chromium/net/third_party/quiche/src/spdy/core/spdy_protocol.cc b/chromium/net/third_party/quiche/src/spdy/core/spdy_protocol.cc
index d9b642f4649..dae7006ff37 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/spdy_protocol.cc
+++ b/chromium/net/third_party/quiche/src/spdy/core/spdy_protocol.cc
@@ -157,7 +157,7 @@ bool ParseSettingsId(SpdySettingsId wire_setting_id,
return false;
}
-SpdyString SettingsIdToString(SpdySettingsId id) {
+std::string SettingsIdToString(SpdySettingsId id) {
SpdyKnownSettingsId known_id;
if (!ParseSettingsId(id, &known_id)) {
return SpdyStrCat("SETTINGS_UNKNOWN_",
@@ -229,6 +229,20 @@ const char* ErrorCodeToString(SpdyErrorCode error_code) {
return "UNKNOWN_ERROR_CODE";
}
+const char* WriteSchedulerTypeToString(WriteSchedulerType type) {
+ switch (type) {
+ case WriteSchedulerType::LIFO:
+ return "LIFO";
+ case WriteSchedulerType::SPDY:
+ return "SPDY";
+ case WriteSchedulerType::HTTP2:
+ return "HTTP2";
+ case WriteSchedulerType::FIFO:
+ return "FIFO";
+ }
+ return "UNKNOWN";
+}
+
size_t GetNumberRequiredContinuationFrames(size_t size) {
DCHECK_GT(size, kHttp2MaxControlFrameSendSize);
size_t overflow = size - kHttp2MaxControlFrameSendSize;
@@ -279,9 +293,9 @@ SpdyDataIR::SpdyDataIR(SpdyStreamId stream_id, SpdyStringPiece data)
SpdyDataIR::SpdyDataIR(SpdyStreamId stream_id, const char* data)
: SpdyDataIR(stream_id, SpdyStringPiece(data)) {}
-SpdyDataIR::SpdyDataIR(SpdyStreamId stream_id, SpdyString data)
+SpdyDataIR::SpdyDataIR(SpdyStreamId stream_id, std::string data)
: SpdyFrameWithFinIR(stream_id),
- data_store_(SpdyMakeUnique<SpdyString>(std::move(data))),
+ data_store_(SpdyMakeUnique<std::string>(std::move(data))),
data_(data_store_->data()),
data_len_(data_store_->size()),
padded_(false),
@@ -378,7 +392,7 @@ SpdyGoAwayIR::SpdyGoAwayIR(SpdyStreamId last_good_stream_id,
SpdyGoAwayIR::SpdyGoAwayIR(SpdyStreamId last_good_stream_id,
SpdyErrorCode error_code,
- SpdyString description)
+ std::string description)
: description_store_(std::move(description)),
description_(description_store_) {
set_last_good_stream_id(last_good_stream_id);
@@ -401,7 +415,7 @@ size_t SpdyGoAwayIR::size() const {
SpdyContinuationIR::SpdyContinuationIR(SpdyStreamId stream_id)
: SpdyFrameIR(stream_id), end_headers_(false) {
- encoding_ = SpdyMakeUnique<SpdyString>();
+ encoding_ = SpdyMakeUnique<std::string>();
}
SpdyContinuationIR::~SpdyContinuationIR() = default;
@@ -505,7 +519,7 @@ size_t SpdyAltSvcIR::size() const {
size_t size = kGetAltSvcFrameMinimumSize;
size += origin_.length();
// TODO(yasong): estimates the size without serializing the vector.
- SpdyString str =
+ std::string str =
SpdyAltSvcWireFormat::SerializeHeaderFieldValue(altsvc_vector_);
size += str.size();
return size;
diff --git a/chromium/net/third_party/quiche/src/spdy/core/spdy_protocol.h b/chromium/net/third_party/quiche/src/spdy/core/spdy_protocol.h
index 2d2ce967e6c..b014107a3ee 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/spdy_protocol.h
+++ b/chromium/net/third_party/quiche/src/spdy/core/spdy_protocol.h
@@ -16,6 +16,7 @@
#include <map>
#include <memory>
#include <new>
+#include <string>
#include <utility>
#include "net/third_party/quiche/src/spdy/core/spdy_alt_svc_wire_format.h"
@@ -25,7 +26,6 @@
#include "net/third_party/quiche/src/spdy/platform/api/spdy_export.h"
#include "net/third_party/quiche/src/spdy/platform/api/spdy_logging.h"
#include "net/third_party/quiche/src/spdy/platform/api/spdy_ptr_util.h"
-#include "net/third_party/quiche/src/spdy/platform/api/spdy_string.h"
#include "net/third_party/quiche/src/spdy/platform/api/spdy_string_piece.h"
namespace spdy {
@@ -203,6 +203,7 @@ enum class WriteSchedulerType {
// https://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3-1#TOC-2.3.3-Stream-priority.
HTTP2, // Uses HTTP2 (tree-style) priority described in
// https://tools.ietf.org/html/rfc7540#section-5.3.
+ FIFO, // Stream with the smallest stream ID has the highest priority.
};
// A SPDY priority is a number between 0 and 7 (inclusive).
@@ -273,7 +274,7 @@ SPDY_EXPORT_PRIVATE bool ParseSettingsId(SpdySettingsId wire_setting_id,
// Returns a string representation of the |id| for logging/debugging. Returns
// the |id| prefixed with "SETTINGS_UNKNOWN_" for unknown SETTINGS IDs. To parse
// the |id| into a SpdyKnownSettingsId (if applicable), use ParseSettingsId().
-SPDY_EXPORT_PRIVATE SpdyString SettingsIdToString(SpdySettingsId id);
+SPDY_EXPORT_PRIVATE std::string SettingsIdToString(SpdySettingsId id);
// Parse |wire_error_code| to a SpdyErrorCode.
// Treat unrecognized error codes as INTERNAL_ERROR
@@ -284,6 +285,10 @@ SPDY_EXPORT_PRIVATE SpdyErrorCode ParseErrorCode(uint32_t wire_error_code);
// for logging/debugging.
const char* ErrorCodeToString(SpdyErrorCode error_code);
+// Serialize |type| to string for logging/debugging.
+SPDY_EXPORT_PRIVATE const char* WriteSchedulerTypeToString(
+ WriteSchedulerType type);
+
// Minimum size of a frame, in octets.
const size_t kFrameMinimumSize = kFrameHeaderSize;
@@ -519,7 +524,7 @@ class SPDY_EXPORT_PRIVATE SpdyDataIR : public SpdyFrameWithFinIR {
SpdyDataIR(SpdyStreamId stream_id, const char* data);
// Moves data into data_store_. Makes a copy if passed a non-movable string.
- SpdyDataIR(SpdyStreamId stream_id, SpdyString data);
+ SpdyDataIR(SpdyStreamId stream_id, std::string data);
// Use in conjunction with SetDataShallow() for shallow-copy on data.
explicit SpdyDataIR(SpdyStreamId stream_id);
@@ -545,7 +550,7 @@ class SPDY_EXPORT_PRIVATE SpdyDataIR : public SpdyFrameWithFinIR {
// Deep-copy of data (keep private copy).
void SetDataDeep(SpdyStringPiece data) {
- data_store_ = SpdyMakeUnique<SpdyString>(data.data(), data.size());
+ data_store_ = SpdyMakeUnique<std::string>(data.data(), data.size());
data_ = data_store_->data();
data_len_ = data.size();
}
@@ -575,7 +580,7 @@ class SPDY_EXPORT_PRIVATE SpdyDataIR : public SpdyFrameWithFinIR {
private:
// Used to store data that this SpdyDataIR should own.
- std::unique_ptr<SpdyString> data_store_;
+ std::unique_ptr<std::string> data_store_;
const char* data_;
size_t data_len_;
@@ -669,7 +674,7 @@ class SPDY_EXPORT_PRIVATE SpdyGoAwayIR : public SpdyFrameIR {
// keep description live after constructing this SpdyGoAwayIR.
SpdyGoAwayIR(SpdyStreamId last_good_stream_id,
SpdyErrorCode error_code,
- SpdyString description);
+ std::string description);
SpdyGoAwayIR(const SpdyGoAwayIR&) = delete;
SpdyGoAwayIR& operator=(const SpdyGoAwayIR&) = delete;
@@ -697,7 +702,7 @@ class SPDY_EXPORT_PRIVATE SpdyGoAwayIR : public SpdyFrameIR {
private:
SpdyStreamId last_good_stream_id_;
SpdyErrorCode error_code_;
- const SpdyString description_store_;
+ const std::string description_store_;
const SpdyStringPiece description_;
};
@@ -821,14 +826,14 @@ class SPDY_EXPORT_PRIVATE SpdyContinuationIR : public SpdyFrameIR {
bool end_headers() const { return end_headers_; }
void set_end_headers(bool end_headers) { end_headers_ = end_headers; }
- const SpdyString& encoding() const { return *encoding_; }
- void take_encoding(std::unique_ptr<SpdyString> encoding) {
+ const std::string& encoding() const { return *encoding_; }
+ void take_encoding(std::unique_ptr<std::string> encoding) {
encoding_ = std::move(encoding);
}
size_t size() const override;
private:
- std::unique_ptr<SpdyString> encoding_;
+ std::unique_ptr<std::string> encoding_;
bool end_headers_;
};
@@ -839,12 +844,12 @@ class SPDY_EXPORT_PRIVATE SpdyAltSvcIR : public SpdyFrameIR {
SpdyAltSvcIR& operator=(const SpdyAltSvcIR&) = delete;
~SpdyAltSvcIR() override;
- SpdyString origin() const { return origin_; }
+ std::string origin() const { return origin_; }
const SpdyAltSvcWireFormat::AlternativeServiceVector& altsvc_vector() const {
return altsvc_vector_;
}
- void set_origin(SpdyString origin) { origin_ = std::move(origin); }
+ void set_origin(std::string origin) { origin_ = std::move(origin); }
void add_altsvc(const SpdyAltSvcWireFormat::AlternativeService& altsvc) {
altsvc_vector_.push_back(altsvc);
}
@@ -856,7 +861,7 @@ class SPDY_EXPORT_PRIVATE SpdyAltSvcIR : public SpdyFrameIR {
size_t size() const override;
private:
- SpdyString origin_;
+ std::string origin_;
SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector_;
};
@@ -894,7 +899,7 @@ class SPDY_EXPORT_PRIVATE SpdyUnknownIR : public SpdyFrameIR {
SpdyUnknownIR(SpdyStreamId stream_id,
uint8_t type,
uint8_t flags,
- SpdyString payload)
+ std::string payload)
: SpdyFrameIR(stream_id),
type_(type),
flags_(flags),
@@ -905,7 +910,7 @@ class SPDY_EXPORT_PRIVATE SpdyUnknownIR : public SpdyFrameIR {
uint8_t type() const { return type_; }
uint8_t flags() const { return flags_; }
size_t length() const { return length_; }
- const SpdyString& payload() const { return payload_; }
+ const std::string& payload() const { return payload_; }
void Visit(SpdyFrameVisitor* visitor) const override;
@@ -923,7 +928,7 @@ class SPDY_EXPORT_PRIVATE SpdyUnknownIR : public SpdyFrameIR {
uint8_t type_;
uint8_t flags_;
size_t length_;
- const SpdyString payload_;
+ const std::string payload_;
};
class SPDY_EXPORT_PRIVATE SpdySerializedFrame {
diff --git a/chromium/net/third_party/quiche/src/spdy/core/spdy_protocol_test.cc b/chromium/net/third_party/quiche/src/spdy/core/spdy_protocol_test.cc
index e10d2d6c202..542d23d1283 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/spdy_protocol_test.cc
+++ b/chromium/net/third_party/quiche/src/spdy/core/spdy_protocol_test.cc
@@ -131,7 +131,7 @@ TEST(SpdyProtocolTest, ParseSettingsId) {
TEST(SpdyProtocolTest, SettingsIdToString) {
struct {
SpdySettingsId setting_id;
- const SpdyString expected_string;
+ const std::string expected_string;
} test_cases[] = {
{0, "SETTINGS_UNKNOWN_0"},
{SETTINGS_HEADER_TABLE_SIZE, "SETTINGS_HEADER_TABLE_SIZE"},
@@ -240,20 +240,20 @@ TEST(SpdyDataIRTest, Construct) {
EXPECT_EQ((int)d1.data_len(), d1.flow_control_window_consumed());
// Confirm copies a const string.
- const SpdyString foo = "foo";
+ const std::string foo = "foo";
SpdyDataIR d3(/* stream_id = */ 3, foo);
EXPECT_EQ(foo, d3.data());
EXPECT_EQ((int)d3.data_len(), d3.flow_control_window_consumed());
// Confirm copies a non-const string.
- SpdyString bar = "bar";
+ std::string bar = "bar";
SpdyDataIR d4(/* stream_id = */ 4, bar);
EXPECT_EQ("bar", bar);
EXPECT_EQ("bar", SpdyStringPiece(d4.data(), d4.data_len()));
// Confirm moves an rvalue reference. Note that the test string "baz" is too
// short to trigger the move optimization, and instead a copy occurs.
- SpdyString baz = "the quick brown fox";
+ std::string baz = "the quick brown fox";
SpdyDataIR d5(/* stream_id = */ 5, std::move(baz));
EXPECT_EQ("", baz);
EXPECT_EQ(SpdyStringPiece(d5.data(), d5.data_len()), "the quick brown fox");
diff --git a/chromium/net/third_party/quiche/src/spdy/core/spdy_simple_arena_test.cc b/chromium/net/third_party/quiche/src/spdy/core/spdy_simple_arena_test.cc
index 217e2d798e2..60bbe24e725 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/spdy_simple_arena_test.cc
+++ b/chromium/net/third_party/quiche/src/spdy/core/spdy_simple_arena_test.cc
@@ -4,9 +4,9 @@
#include "net/third_party/quiche/src/spdy/core/spdy_simple_arena.h"
+#include <string>
#include <vector>
-#include "net/third_party/quiche/src/spdy/platform/api/spdy_string.h"
#include "net/third_party/quiche/src/spdy/platform/api/spdy_string_piece.h"
#include "net/third_party/quiche/src/spdy/platform/api/spdy_test.h"
@@ -36,11 +36,11 @@ TEST(SpdySimpleArenaTest, MemdupLargeString) {
TEST(SpdySimpleArenaTest, MultipleBlocks) {
SpdySimpleArena arena(40 /* block size */);
- std::vector<SpdyString> strings = {
+ std::vector<std::string> strings = {
"One decently long string.", "Another string.",
"A third string that will surely go in a different block."};
std::vector<SpdyStringPiece> copies;
- for (const SpdyString& s : strings) {
+ for (const std::string& s : strings) {
SpdyStringPiece sp(arena.Memdup(s.data(), s.size()), s.size());
copies.push_back(sp);
}
diff --git a/chromium/net/third_party/quiche/src/spdy/core/spdy_test_utils.cc b/chromium/net/third_party/quiche/src/spdy/core/spdy_test_utils.cc
index bf54a1a8361..f248c86ae5d 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/spdy_test_utils.cc
+++ b/chromium/net/third_party/quiche/src/spdy/core/spdy_test_utils.cc
@@ -18,10 +18,10 @@
namespace spdy {
namespace test {
-SpdyString HexDumpWithMarks(const unsigned char* data,
- int length,
- const bool* marks,
- int mark_length) {
+std::string HexDumpWithMarks(const unsigned char* data,
+ int length,
+ const bool* marks,
+ int mark_length) {
static const char kHexChars[] = "0123456789abcdef";
static const int kColumns = 4;
@@ -32,7 +32,7 @@ SpdyString HexDumpWithMarks(const unsigned char* data,
mark_length = std::min(mark_length, kSizeLimit);
}
- SpdyString hex;
+ std::string hex;
for (const unsigned char* row = data; length > 0;
row += kColumns, length -= kColumns) {
for (const unsigned char* p = row; p < row + 4; ++p) {
@@ -58,7 +58,7 @@ SpdyString HexDumpWithMarks(const unsigned char* data,
return hex;
}
-void CompareCharArraysWithHexError(const SpdyString& description,
+void CompareCharArraysWithHexError(const std::string& description,
const unsigned char* actual,
const int actual_len,
const unsigned char* expected,
diff --git a/chromium/net/third_party/quiche/src/spdy/core/spdy_test_utils.h b/chromium/net/third_party/quiche/src/spdy/core/spdy_test_utils.h
index 03a6caf896d..e2c3b477017 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/spdy_test_utils.h
+++ b/chromium/net/third_party/quiche/src/spdy/core/spdy_test_utils.h
@@ -7,12 +7,12 @@
#include <cstddef>
#include <cstdint>
+#include <string>
#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h"
#include "net/third_party/quiche/src/spdy/core/spdy_headers_handler_interface.h"
#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h"
#include "net/third_party/quiche/src/spdy/platform/api/spdy_bug_tracker.h"
-#include "net/third_party/quiche/src/spdy/platform/api/spdy_string.h"
#include "net/third_party/quiche/src/spdy/platform/api/spdy_string_piece.h"
namespace spdy {
@@ -24,12 +24,12 @@ inline bool operator==(SpdyStringPiece x,
namespace test {
-SpdyString HexDumpWithMarks(const unsigned char* data,
- int length,
- const bool* marks,
- int mark_length);
+std::string HexDumpWithMarks(const unsigned char* data,
+ int length,
+ const bool* marks,
+ int mark_length);
-void CompareCharArraysWithHexError(const SpdyString& description,
+void CompareCharArraysWithHexError(const std::string& description,
const unsigned char* actual,
const int actual_len,
const unsigned char* expected,
diff --git a/chromium/net/third_party/quiche/src/spdy/core/write_scheduler.h b/chromium/net/third_party/quiche/src/spdy/core/write_scheduler.h
index 98db442437e..c2c048f543b 100644
--- a/chromium/net/third_party/quiche/src/spdy/core/write_scheduler.h
+++ b/chromium/net/third_party/quiche/src/spdy/core/write_scheduler.h
@@ -6,12 +6,12 @@
#define QUICHE_SPDY_CORE_WRITE_SCHEDULER_H_
#include <cstdint>
+#include <string>
#include <tuple>
#include <vector>
#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h"
#include "net/third_party/quiche/src/spdy/platform/api/spdy_export.h"
-#include "net/third_party/quiche/src/spdy/platform/api/spdy_string.h"
namespace spdy {
@@ -154,7 +154,7 @@ class SPDY_EXPORT_PRIVATE WriteScheduler {
virtual size_t NumRegisteredStreams() const = 0;
// Returns summary of internal state, for logging/debugging.
- virtual SpdyString DebugString() const = 0;
+ virtual std::string DebugString() const = 0;
};
} // namespace spdy
diff --git a/chromium/net/third_party/quiche/src/spdy/platform/api/spdy_string.h b/chromium/net/third_party/quiche/src/spdy/platform/api/spdy_string.h
deleted file mode 100644
index 16eb9e5569d..00000000000
--- a/chromium/net/third_party/quiche/src/spdy/platform/api/spdy_string.h
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright (c) 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef QUICHE_SPDY_PLATFORM_API_SPDY_STRING_H_
-#define QUICHE_SPDY_PLATFORM_API_SPDY_STRING_H_
-
-#include "net/spdy/platform/impl/spdy_string_impl.h"
-
-namespace spdy {
-
-using SpdyString = SpdyStringImpl;
-
-} // namespace spdy
-
-#endif // QUICHE_SPDY_PLATFORM_API_SPDY_STRING_H_
diff --git a/chromium/net/third_party/quiche/src/spdy/platform/api/spdy_string_utils.h b/chromium/net/third_party/quiche/src/spdy/platform/api/spdy_string_utils.h
index 7554f796a97..e2f709df48a 100644
--- a/chromium/net/third_party/quiche/src/spdy/platform/api/spdy_string_utils.h
+++ b/chromium/net/third_party/quiche/src/spdy/platform/api/spdy_string_utils.h
@@ -5,6 +5,7 @@
#ifndef QUICHE_SPDY_PLATFORM_API_SPDY_STRING_UTILS_H_
#define QUICHE_SPDY_PLATFORM_API_SPDY_STRING_UTILS_H_
+#include <string>
#include <utility>
// The following header file has to be included from at least
@@ -13,19 +14,18 @@
// non-test code.
#include "net/third_party/quiche/src/spdy/platform/api/spdy_mem_slice.h"
-#include "net/third_party/quiche/src/spdy/platform/api/spdy_string.h"
#include "net/third_party/quiche/src/spdy/platform/api/spdy_string_piece.h"
#include "net/spdy/platform/impl/spdy_string_utils_impl.h"
namespace spdy {
template <typename... Args>
-inline SpdyString SpdyStrCat(const Args&... args) {
+inline std::string SpdyStrCat(const Args&... args) {
return SpdyStrCatImpl(std::forward<const Args&>(args)...);
}
template <typename... Args>
-inline void SpdyStrAppend(SpdyString* output, const Args&... args) {
+inline void SpdyStrAppend(std::string* output, const Args&... args) {
SpdyStrAppendImpl(output, std::forward<const Args&>(args)...);
}
@@ -33,7 +33,7 @@ inline char SpdyHexDigitToInt(char c) {
return SpdyHexDigitToIntImpl(c);
}
-inline SpdyString SpdyHexDecode(SpdyStringPiece data) {
+inline std::string SpdyHexDecode(SpdyStringPiece data) {
return SpdyHexDecodeImpl(data);
}
@@ -41,15 +41,15 @@ inline bool SpdyHexDecodeToUInt32(SpdyStringPiece data, uint32_t* out) {
return SpdyHexDecodeToUInt32Impl(data, out);
}
-inline SpdyString SpdyHexEncode(const char* bytes, size_t size) {
+inline std::string SpdyHexEncode(const char* bytes, size_t size) {
return SpdyHexEncodeImpl(bytes, size);
}
-inline SpdyString SpdyHexEncodeUInt32AndTrim(uint32_t data) {
+inline std::string SpdyHexEncodeUInt32AndTrim(uint32_t data) {
return SpdyHexEncodeUInt32AndTrimImpl(data);
}
-inline SpdyString SpdyHexDump(SpdyStringPiece data) {
+inline std::string SpdyHexDump(SpdyStringPiece data) {
return SpdyHexDumpImpl(data);
}
diff --git a/chromium/net/third_party/quiche/src/spdy/platform/api/spdy_string_utils_test.cc b/chromium/net/third_party/quiche/src/spdy/platform/api/spdy_string_utils_test.cc
index 91656ae165c..f6f094f999f 100644
--- a/chromium/net/third_party/quiche/src/spdy/platform/api/spdy_string_utils_test.cc
+++ b/chromium/net/third_party/quiche/src/spdy/platform/api/spdy_string_utils_test.cc
@@ -19,7 +19,7 @@ TEST(SpdyStringUtilsTest, SpdyStrCat) {
// Single string-like argument.
const char kFoo[] = "foo";
- const SpdyString string_foo(kFoo);
+ const std::string string_foo(kFoo);
const SpdyStringPiece stringpiece_foo(string_foo);
EXPECT_EQ("foo", SpdyStrCat(kFoo));
EXPECT_EQ("foo", SpdyStrCat(string_foo));
@@ -28,7 +28,7 @@ TEST(SpdyStringUtilsTest, SpdyStrCat) {
// Two string-like arguments.
const char kBar[] = "bar";
const SpdyStringPiece stringpiece_bar(kBar);
- const SpdyString string_bar(kBar);
+ const std::string string_bar(kBar);
EXPECT_EQ("foobar", SpdyStrCat(kFoo, kBar));
EXPECT_EQ("foobar", SpdyStrCat(kFoo, string_bar));
EXPECT_EQ("foobar", SpdyStrCat(kFoo, stringpiece_bar));
@@ -72,13 +72,13 @@ TEST(SpdyStringUtilsTest, SpdyStrCat) {
TEST(SpdyStringUtilsTest, SpdyStrAppend) {
// No arguments on empty string.
- SpdyString output;
+ std::string output;
SpdyStrAppend(&output);
EXPECT_TRUE(output.empty());
// Single string-like argument.
const char kFoo[] = "foo";
- const SpdyString string_foo(kFoo);
+ const std::string string_foo(kFoo);
const SpdyStringPiece stringpiece_foo(string_foo);
SpdyStrAppend(&output, kFoo);
EXPECT_EQ("foo", output);
@@ -96,7 +96,7 @@ TEST(SpdyStringUtilsTest, SpdyStrAppend) {
// Two string-like arguments.
const char kBar[] = "bar";
const SpdyStringPiece stringpiece_bar(kBar);
- const SpdyString string_bar(kBar);
+ const std::string string_bar(kBar);
SpdyStrAppend(&output, kFoo, kBar);
EXPECT_EQ("foobar", output);
SpdyStrAppend(&output, kFoo, string_bar);
diff --git a/chromium/net/third_party/uri_template/uri_template_fuzzer.cc b/chromium/net/third_party/uri_template/uri_template_fuzzer.cc
index 148dbbad8d3..08731dd1001 100644
--- a/chromium/net/third_party/uri_template/uri_template_fuzzer.cc
+++ b/chromium/net/third_party/uri_template/uri_template_fuzzer.cc
@@ -4,7 +4,7 @@
#include "net/third_party/uri_template/uri_template.h"
-#include "third_party/libFuzzer/src/utils/FuzzedDataProvider.h"
+#include <fuzzer/FuzzedDataProvider.h>
// Entry point for LibFuzzer.
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {