diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2021-09-03 13:32:17 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2021-10-01 14:31:55 +0200 |
commit | 21ba0c5d4bf8fba15dddd97cd693bad2358b77fd (patch) | |
tree | 91be119f694044dfc1ff9fdc054459e925de9df0 /chromium/net/third_party | |
parent | 03c549e0392f92c02536d3f86d5e1d8dfa3435ac (diff) | |
download | qtwebengine-chromium-21ba0c5d4bf8fba15dddd97cd693bad2358b77fd.tar.gz |
BASELINE: Update Chromium to 92.0.4515.166
Change-Id: I42a050486714e9e54fc271f2a8939223a02ae364
Diffstat (limited to 'chromium/net/third_party')
336 files changed, 11287 insertions, 5466 deletions
diff --git a/chromium/net/third_party/nss/DIR_METADATA b/chromium/net/third_party/nss/DIR_METADATA index 250c6d5b294..54e5bb81d80 100644 --- a/chromium/net/third_party/nss/DIR_METADATA +++ b/chromium/net/third_party/nss/DIR_METADATA @@ -1,10 +1,10 @@ # Metadata information for this directory. # # For more information on DIR_METADATA files, see: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md # # For the schema of this file, see Metadata message: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto monorail { component: "Internals>Network>SSL" diff --git a/chromium/net/third_party/quiche/BUILD.gn b/chromium/net/third_party/quiche/BUILD.gn index 7b567969912..41d2dfff1d9 100644 --- a/chromium/net/third_party/quiche/BUILD.gn +++ b/chromium/net/third_party/quiche/BUILD.gn @@ -29,619 +29,614 @@ source_set("quiche_public_deps") { source_set("quiche") { sources = [ + "overrides/quiche_platform_impl/quic_mutex_impl.cc", + "overrides/quiche_platform_impl/quic_mutex_impl.h", "overrides/quiche_platform_impl/quiche_export_impl.h", + "overrides/quiche_platform_impl/quiche_logging_impl.h", + "overrides/quiche_platform_impl/quiche_time_utils_impl.cc", + "overrides/quiche_platform_impl/quiche_time_utils_impl.h", + "src/common/platform/api/quiche_export.h", + "src/common/platform/api/quiche_flag_utils.h", + "src/common/platform/api/quiche_flags.h", + "src/common/platform/api/quiche_logging.h", + "src/common/platform/api/quiche_prefetch.h", + "src/common/platform/api/quiche_time_utils.h", + "src/common/platform/default/quiche_platform_impl/quiche_prefetch_impl.h", + "src/common/quiche_circular_deque.h", + "src/common/quiche_data_reader.cc", + "src/common/quiche_data_reader.h", + "src/common/quiche_data_writer.cc", + "src/common/quiche_data_writer.h", + "src/common/quiche_endian.h", + "src/common/quiche_linked_hash_map.h", + "src/common/quiche_text_utils.cc", + "src/common/quiche_text_utils.h", + "src/http2/core/http2_priority_write_scheduler.h", + "src/http2/core/priority_write_scheduler.h", + "src/http2/core/write_scheduler.h", + "src/http2/decoder/decode_buffer.cc", + "src/http2/decoder/decode_buffer.h", + "src/http2/decoder/decode_http2_structures.cc", + "src/http2/decoder/decode_http2_structures.h", + "src/http2/decoder/decode_status.cc", + "src/http2/decoder/decode_status.h", + "src/http2/decoder/frame_decoder_state.cc", + "src/http2/decoder/frame_decoder_state.h", + "src/http2/decoder/http2_frame_decoder.cc", + "src/http2/decoder/http2_frame_decoder.h", + "src/http2/decoder/http2_frame_decoder_listener.cc", + "src/http2/decoder/http2_frame_decoder_listener.h", + "src/http2/decoder/http2_structure_decoder.cc", + "src/http2/decoder/http2_structure_decoder.h", + "src/http2/decoder/payload_decoders/altsvc_payload_decoder.cc", + "src/http2/decoder/payload_decoders/altsvc_payload_decoder.h", + "src/http2/decoder/payload_decoders/continuation_payload_decoder.cc", + "src/http2/decoder/payload_decoders/continuation_payload_decoder.h", + "src/http2/decoder/payload_decoders/data_payload_decoder.cc", + "src/http2/decoder/payload_decoders/data_payload_decoder.h", + "src/http2/decoder/payload_decoders/goaway_payload_decoder.cc", + "src/http2/decoder/payload_decoders/goaway_payload_decoder.h", + "src/http2/decoder/payload_decoders/headers_payload_decoder.cc", + "src/http2/decoder/payload_decoders/headers_payload_decoder.h", + "src/http2/decoder/payload_decoders/ping_payload_decoder.cc", + "src/http2/decoder/payload_decoders/ping_payload_decoder.h", + "src/http2/decoder/payload_decoders/priority_payload_decoder.cc", + "src/http2/decoder/payload_decoders/priority_payload_decoder.h", + "src/http2/decoder/payload_decoders/priority_update_payload_decoder.cc", + "src/http2/decoder/payload_decoders/priority_update_payload_decoder.h", + "src/http2/decoder/payload_decoders/push_promise_payload_decoder.cc", + "src/http2/decoder/payload_decoders/push_promise_payload_decoder.h", + "src/http2/decoder/payload_decoders/rst_stream_payload_decoder.cc", + "src/http2/decoder/payload_decoders/rst_stream_payload_decoder.h", + "src/http2/decoder/payload_decoders/settings_payload_decoder.cc", + "src/http2/decoder/payload_decoders/settings_payload_decoder.h", + "src/http2/decoder/payload_decoders/unknown_payload_decoder.cc", + "src/http2/decoder/payload_decoders/unknown_payload_decoder.h", + "src/http2/decoder/payload_decoders/window_update_payload_decoder.cc", + "src/http2/decoder/payload_decoders/window_update_payload_decoder.h", + "src/http2/hpack/decoder/hpack_block_decoder.cc", + "src/http2/hpack/decoder/hpack_block_decoder.h", + "src/http2/hpack/decoder/hpack_decoder.cc", + "src/http2/hpack/decoder/hpack_decoder.h", + "src/http2/hpack/decoder/hpack_decoder_listener.cc", + "src/http2/hpack/decoder/hpack_decoder_listener.h", + "src/http2/hpack/decoder/hpack_decoder_state.cc", + "src/http2/hpack/decoder/hpack_decoder_state.h", + "src/http2/hpack/decoder/hpack_decoder_string_buffer.cc", + "src/http2/hpack/decoder/hpack_decoder_string_buffer.h", + "src/http2/hpack/decoder/hpack_decoder_tables.cc", + "src/http2/hpack/decoder/hpack_decoder_tables.h", + "src/http2/hpack/decoder/hpack_decoding_error.cc", + "src/http2/hpack/decoder/hpack_decoding_error.h", + "src/http2/hpack/decoder/hpack_entry_decoder.cc", + "src/http2/hpack/decoder/hpack_entry_decoder.h", + "src/http2/hpack/decoder/hpack_entry_decoder_listener.cc", + "src/http2/hpack/decoder/hpack_entry_decoder_listener.h", + "src/http2/hpack/decoder/hpack_entry_type_decoder.cc", + "src/http2/hpack/decoder/hpack_entry_type_decoder.h", + "src/http2/hpack/decoder/hpack_string_decoder.cc", + "src/http2/hpack/decoder/hpack_string_decoder.h", + "src/http2/hpack/decoder/hpack_string_decoder_listener.cc", + "src/http2/hpack/decoder/hpack_string_decoder_listener.h", + "src/http2/hpack/decoder/hpack_whole_entry_buffer.cc", + "src/http2/hpack/decoder/hpack_whole_entry_buffer.h", + "src/http2/hpack/decoder/hpack_whole_entry_listener.cc", + "src/http2/hpack/decoder/hpack_whole_entry_listener.h", + "src/http2/hpack/hpack_static_table_entries.inc", + "src/http2/hpack/http2_hpack_constants.cc", + "src/http2/hpack/http2_hpack_constants.h", + "src/http2/hpack/huffman/hpack_huffman_decoder.cc", + "src/http2/hpack/huffman/hpack_huffman_decoder.h", + "src/http2/hpack/huffman/hpack_huffman_encoder.cc", + "src/http2/hpack/huffman/hpack_huffman_encoder.h", + "src/http2/hpack/huffman/huffman_spec_tables.cc", + "src/http2/hpack/huffman/huffman_spec_tables.h", + "src/http2/hpack/varint/hpack_varint_decoder.cc", + "src/http2/hpack/varint/hpack_varint_decoder.h", + "src/http2/hpack/varint/hpack_varint_encoder.cc", + "src/http2/hpack/varint/hpack_varint_encoder.h", + "src/http2/http2_constants.cc", + "src/http2/http2_constants.h", + "src/http2/http2_structures.cc", + "src/http2/http2_structures.h", + "src/http2/platform/api/http2_bug_tracker.h", + "src/http2/platform/api/http2_containers.h", + "src/http2/platform/api/http2_estimate_memory_usage.h", + "src/http2/platform/api/http2_flag_utils.h", + "src/http2/platform/api/http2_flags.h", + "src/http2/platform/api/http2_logging.h", + "src/http2/platform/api/http2_macros.h", + "src/http2/platform/api/http2_string_utils.h", + "src/quic/core/congestion_control/bandwidth_sampler.cc", + "src/quic/core/congestion_control/bandwidth_sampler.h", + "src/quic/core/congestion_control/bbr2_drain.cc", + "src/quic/core/congestion_control/bbr2_drain.h", + "src/quic/core/congestion_control/bbr2_misc.cc", + "src/quic/core/congestion_control/bbr2_misc.h", + "src/quic/core/congestion_control/bbr2_probe_bw.cc", + "src/quic/core/congestion_control/bbr2_probe_bw.h", + "src/quic/core/congestion_control/bbr2_probe_rtt.cc", + "src/quic/core/congestion_control/bbr2_probe_rtt.h", + "src/quic/core/congestion_control/bbr2_sender.cc", + "src/quic/core/congestion_control/bbr2_sender.h", + "src/quic/core/congestion_control/bbr2_startup.cc", + "src/quic/core/congestion_control/bbr2_startup.h", + "src/quic/core/congestion_control/bbr_sender.cc", + "src/quic/core/congestion_control/bbr_sender.h", + "src/quic/core/congestion_control/cubic_bytes.cc", + "src/quic/core/congestion_control/cubic_bytes.h", + "src/quic/core/congestion_control/general_loss_algorithm.cc", + "src/quic/core/congestion_control/general_loss_algorithm.h", + "src/quic/core/congestion_control/hybrid_slow_start.cc", + "src/quic/core/congestion_control/hybrid_slow_start.h", + "src/quic/core/congestion_control/loss_detection_interface.h", + "src/quic/core/congestion_control/pacing_sender.cc", + "src/quic/core/congestion_control/pacing_sender.h", + "src/quic/core/congestion_control/prr_sender.cc", + "src/quic/core/congestion_control/prr_sender.h", + "src/quic/core/congestion_control/rtt_stats.cc", + "src/quic/core/congestion_control/rtt_stats.h", + "src/quic/core/congestion_control/send_algorithm_interface.cc", + "src/quic/core/congestion_control/send_algorithm_interface.h", + "src/quic/core/congestion_control/tcp_cubic_sender_bytes.cc", + "src/quic/core/congestion_control/tcp_cubic_sender_bytes.h", + "src/quic/core/congestion_control/uber_loss_algorithm.cc", + "src/quic/core/congestion_control/uber_loss_algorithm.h", + "src/quic/core/congestion_control/windowed_filter.h", + "src/quic/core/crypto/aead_base_decrypter.cc", + "src/quic/core/crypto/aead_base_decrypter.h", + "src/quic/core/crypto/aead_base_encrypter.cc", + "src/quic/core/crypto/aead_base_encrypter.h", + "src/quic/core/crypto/aes_128_gcm_12_decrypter.cc", + "src/quic/core/crypto/aes_128_gcm_12_decrypter.h", + "src/quic/core/crypto/aes_128_gcm_12_encrypter.cc", + "src/quic/core/crypto/aes_128_gcm_12_encrypter.h", + "src/quic/core/crypto/aes_128_gcm_decrypter.cc", + "src/quic/core/crypto/aes_128_gcm_decrypter.h", + "src/quic/core/crypto/aes_128_gcm_encrypter.cc", + "src/quic/core/crypto/aes_128_gcm_encrypter.h", + "src/quic/core/crypto/aes_256_gcm_decrypter.cc", + "src/quic/core/crypto/aes_256_gcm_decrypter.h", + "src/quic/core/crypto/aes_256_gcm_encrypter.cc", + "src/quic/core/crypto/aes_256_gcm_encrypter.h", + "src/quic/core/crypto/aes_base_decrypter.cc", + "src/quic/core/crypto/aes_base_decrypter.h", + "src/quic/core/crypto/aes_base_encrypter.cc", + "src/quic/core/crypto/aes_base_encrypter.h", + "src/quic/core/crypto/boring_utils.h", + "src/quic/core/crypto/cert_compressor.cc", + "src/quic/core/crypto/cert_compressor.h", + "src/quic/core/crypto/certificate_view.cc", + "src/quic/core/crypto/certificate_view.h", + "src/quic/core/crypto/chacha20_poly1305_decrypter.cc", + "src/quic/core/crypto/chacha20_poly1305_decrypter.h", + "src/quic/core/crypto/chacha20_poly1305_encrypter.cc", + "src/quic/core/crypto/chacha20_poly1305_encrypter.h", + "src/quic/core/crypto/chacha20_poly1305_tls_decrypter.cc", + "src/quic/core/crypto/chacha20_poly1305_tls_decrypter.h", + "src/quic/core/crypto/chacha20_poly1305_tls_encrypter.cc", + "src/quic/core/crypto/chacha20_poly1305_tls_encrypter.h", + "src/quic/core/crypto/chacha_base_decrypter.cc", + "src/quic/core/crypto/chacha_base_decrypter.h", + "src/quic/core/crypto/chacha_base_encrypter.cc", + "src/quic/core/crypto/chacha_base_encrypter.h", + "src/quic/core/crypto/channel_id.cc", + "src/quic/core/crypto/channel_id.h", + "src/quic/core/crypto/common_cert_set.cc", + "src/quic/core/crypto/common_cert_set.h", + "src/quic/core/crypto/crypto_framer.cc", + "src/quic/core/crypto/crypto_framer.h", + "src/quic/core/crypto/crypto_handshake.cc", + "src/quic/core/crypto/crypto_handshake.h", + "src/quic/core/crypto/crypto_handshake_message.cc", + "src/quic/core/crypto/crypto_handshake_message.h", + "src/quic/core/crypto/crypto_message_parser.h", + "src/quic/core/crypto/crypto_protocol.h", + "src/quic/core/crypto/crypto_secret_boxer.cc", + "src/quic/core/crypto/crypto_secret_boxer.h", + "src/quic/core/crypto/crypto_utils.cc", + "src/quic/core/crypto/crypto_utils.h", + "src/quic/core/crypto/curve25519_key_exchange.cc", + "src/quic/core/crypto/curve25519_key_exchange.h", + "src/quic/core/crypto/key_exchange.cc", + "src/quic/core/crypto/key_exchange.h", + "src/quic/core/crypto/null_decrypter.cc", + "src/quic/core/crypto/null_decrypter.h", + "src/quic/core/crypto/null_encrypter.cc", + "src/quic/core/crypto/null_encrypter.h", + "src/quic/core/crypto/p256_key_exchange.cc", + "src/quic/core/crypto/p256_key_exchange.h", + "src/quic/core/crypto/proof_source.cc", + "src/quic/core/crypto/proof_source.h", + "src/quic/core/crypto/proof_verifier.h", + "src/quic/core/crypto/quic_compressed_certs_cache.cc", + "src/quic/core/crypto/quic_compressed_certs_cache.h", + "src/quic/core/crypto/quic_crypter.cc", + "src/quic/core/crypto/quic_crypter.h", + "src/quic/core/crypto/quic_crypto_client_config.cc", + "src/quic/core/crypto/quic_crypto_client_config.h", + "src/quic/core/crypto/quic_crypto_proof.cc", + "src/quic/core/crypto/quic_crypto_proof.h", + "src/quic/core/crypto/quic_crypto_server_config.cc", + "src/quic/core/crypto/quic_crypto_server_config.h", + "src/quic/core/crypto/quic_decrypter.cc", + "src/quic/core/crypto/quic_decrypter.h", + "src/quic/core/crypto/quic_encrypter.cc", + "src/quic/core/crypto/quic_encrypter.h", + "src/quic/core/crypto/quic_hkdf.cc", + "src/quic/core/crypto/quic_hkdf.h", + "src/quic/core/crypto/quic_random.cc", + "src/quic/core/crypto/quic_random.h", + "src/quic/core/crypto/server_proof_verifier.h", + "src/quic/core/crypto/tls_client_connection.cc", + "src/quic/core/crypto/tls_client_connection.h", + "src/quic/core/crypto/tls_connection.cc", + "src/quic/core/crypto/tls_connection.h", + "src/quic/core/crypto/tls_server_connection.cc", + "src/quic/core/crypto/tls_server_connection.h", + "src/quic/core/crypto/transport_parameters.cc", + "src/quic/core/crypto/transport_parameters.h", + "src/quic/core/frames/quic_ack_frame.cc", + "src/quic/core/frames/quic_ack_frame.h", + "src/quic/core/frames/quic_ack_frequency_frame.cc", + "src/quic/core/frames/quic_ack_frequency_frame.h", + "src/quic/core/frames/quic_blocked_frame.cc", + "src/quic/core/frames/quic_blocked_frame.h", + "src/quic/core/frames/quic_connection_close_frame.cc", + "src/quic/core/frames/quic_connection_close_frame.h", + "src/quic/core/frames/quic_crypto_frame.cc", + "src/quic/core/frames/quic_crypto_frame.h", + "src/quic/core/frames/quic_frame.cc", + "src/quic/core/frames/quic_frame.h", + "src/quic/core/frames/quic_goaway_frame.cc", + "src/quic/core/frames/quic_goaway_frame.h", + "src/quic/core/frames/quic_handshake_done_frame.cc", + "src/quic/core/frames/quic_handshake_done_frame.h", + "src/quic/core/frames/quic_inlined_frame.h", + "src/quic/core/frames/quic_max_streams_frame.cc", + "src/quic/core/frames/quic_max_streams_frame.h", + "src/quic/core/frames/quic_message_frame.cc", + "src/quic/core/frames/quic_message_frame.h", + "src/quic/core/frames/quic_mtu_discovery_frame.h", + "src/quic/core/frames/quic_new_connection_id_frame.cc", + "src/quic/core/frames/quic_new_connection_id_frame.h", + "src/quic/core/frames/quic_new_token_frame.cc", + "src/quic/core/frames/quic_new_token_frame.h", + "src/quic/core/frames/quic_padding_frame.cc", + "src/quic/core/frames/quic_padding_frame.h", + "src/quic/core/frames/quic_path_challenge_frame.cc", + "src/quic/core/frames/quic_path_challenge_frame.h", + "src/quic/core/frames/quic_path_response_frame.cc", + "src/quic/core/frames/quic_path_response_frame.h", + "src/quic/core/frames/quic_ping_frame.cc", + "src/quic/core/frames/quic_ping_frame.h", + "src/quic/core/frames/quic_retire_connection_id_frame.cc", + "src/quic/core/frames/quic_retire_connection_id_frame.h", + "src/quic/core/frames/quic_rst_stream_frame.cc", + "src/quic/core/frames/quic_rst_stream_frame.h", + "src/quic/core/frames/quic_stop_sending_frame.cc", + "src/quic/core/frames/quic_stop_sending_frame.h", + "src/quic/core/frames/quic_stop_waiting_frame.cc", + "src/quic/core/frames/quic_stop_waiting_frame.h", + "src/quic/core/frames/quic_stream_frame.cc", + "src/quic/core/frames/quic_stream_frame.h", + "src/quic/core/frames/quic_streams_blocked_frame.cc", + "src/quic/core/frames/quic_streams_blocked_frame.h", + "src/quic/core/frames/quic_window_update_frame.cc", + "src/quic/core/frames/quic_window_update_frame.h", + "src/quic/core/handshaker_delegate_interface.h", + "src/quic/core/http/http_constants.cc", + "src/quic/core/http/http_constants.h", + "src/quic/core/http/http_decoder.cc", + "src/quic/core/http/http_decoder.h", + "src/quic/core/http/http_encoder.cc", + "src/quic/core/http/http_encoder.h", + "src/quic/core/http/http_frames.h", + "src/quic/core/http/quic_client_promised_info.cc", + "src/quic/core/http/quic_client_promised_info.h", + "src/quic/core/http/quic_client_push_promise_index.cc", + "src/quic/core/http/quic_client_push_promise_index.h", + "src/quic/core/http/quic_header_list.cc", + "src/quic/core/http/quic_header_list.h", + "src/quic/core/http/quic_headers_stream.cc", + "src/quic/core/http/quic_headers_stream.h", + "src/quic/core/http/quic_receive_control_stream.cc", + "src/quic/core/http/quic_receive_control_stream.h", + "src/quic/core/http/quic_send_control_stream.cc", + "src/quic/core/http/quic_send_control_stream.h", + "src/quic/core/http/quic_server_initiated_spdy_stream.cc", + "src/quic/core/http/quic_server_initiated_spdy_stream.h", + "src/quic/core/http/quic_server_session_base.cc", + "src/quic/core/http/quic_server_session_base.h", + "src/quic/core/http/quic_spdy_client_session.cc", + "src/quic/core/http/quic_spdy_client_session.h", + "src/quic/core/http/quic_spdy_client_session_base.cc", + "src/quic/core/http/quic_spdy_client_session_base.h", + "src/quic/core/http/quic_spdy_client_stream.cc", + "src/quic/core/http/quic_spdy_client_stream.h", + "src/quic/core/http/quic_spdy_session.cc", + "src/quic/core/http/quic_spdy_session.h", + "src/quic/core/http/quic_spdy_stream.cc", + "src/quic/core/http/quic_spdy_stream.h", + "src/quic/core/http/quic_spdy_stream_body_manager.cc", + "src/quic/core/http/quic_spdy_stream_body_manager.h", + "src/quic/core/http/spdy_server_push_utils.cc", + "src/quic/core/http/spdy_server_push_utils.h", + "src/quic/core/http/spdy_utils.cc", + "src/quic/core/http/spdy_utils.h", + "src/quic/core/http/web_transport_http3.cc", + "src/quic/core/http/web_transport_http3.h", + "src/quic/core/legacy_quic_stream_id_manager.cc", + "src/quic/core/legacy_quic_stream_id_manager.h", + "src/quic/core/packet_number_indexed_queue.h", + "src/quic/core/proto/cached_network_parameters_proto.h", + "src/quic/core/proto/crypto_server_config_proto.h", + "src/quic/core/proto/source_address_token_proto.h", + "src/quic/core/qpack/qpack_blocking_manager.cc", + "src/quic/core/qpack/qpack_blocking_manager.h", + "src/quic/core/qpack/qpack_decoded_headers_accumulator.cc", + "src/quic/core/qpack/qpack_decoded_headers_accumulator.h", + "src/quic/core/qpack/qpack_decoder.cc", + "src/quic/core/qpack/qpack_decoder.h", + "src/quic/core/qpack/qpack_decoder_stream_receiver.cc", + "src/quic/core/qpack/qpack_decoder_stream_receiver.h", + "src/quic/core/qpack/qpack_decoder_stream_sender.cc", + "src/quic/core/qpack/qpack_decoder_stream_sender.h", + "src/quic/core/qpack/qpack_encoder.cc", + "src/quic/core/qpack/qpack_encoder.h", + "src/quic/core/qpack/qpack_encoder_stream_receiver.cc", + "src/quic/core/qpack/qpack_encoder_stream_receiver.h", + "src/quic/core/qpack/qpack_encoder_stream_sender.cc", + "src/quic/core/qpack/qpack_encoder_stream_sender.h", + "src/quic/core/qpack/qpack_header_table.cc", + "src/quic/core/qpack/qpack_header_table.h", + "src/quic/core/qpack/qpack_index_conversions.cc", + "src/quic/core/qpack/qpack_index_conversions.h", + "src/quic/core/qpack/qpack_instruction_decoder.cc", + "src/quic/core/qpack/qpack_instruction_decoder.h", + "src/quic/core/qpack/qpack_instruction_encoder.cc", + "src/quic/core/qpack/qpack_instruction_encoder.h", + "src/quic/core/qpack/qpack_instructions.cc", + "src/quic/core/qpack/qpack_instructions.h", + "src/quic/core/qpack/qpack_progressive_decoder.cc", + "src/quic/core/qpack/qpack_progressive_decoder.h", + "src/quic/core/qpack/qpack_receive_stream.cc", + "src/quic/core/qpack/qpack_receive_stream.h", + "src/quic/core/qpack/qpack_required_insert_count.cc", + "src/quic/core/qpack/qpack_required_insert_count.h", + "src/quic/core/qpack/qpack_send_stream.cc", + "src/quic/core/qpack/qpack_send_stream.h", + "src/quic/core/qpack/qpack_static_table.cc", + "src/quic/core/qpack/qpack_static_table.h", + "src/quic/core/qpack/qpack_stream_receiver.h", + "src/quic/core/qpack/qpack_stream_sender_delegate.h", + "src/quic/core/qpack/value_splitting_header_list.cc", + "src/quic/core/qpack/value_splitting_header_list.h", + "src/quic/core/quic_ack_listener_interface.cc", + "src/quic/core/quic_ack_listener_interface.h", + "src/quic/core/quic_alarm.cc", + "src/quic/core/quic_alarm.h", + "src/quic/core/quic_alarm_factory.h", + "src/quic/core/quic_arena_scoped_ptr.h", + "src/quic/core/quic_bandwidth.cc", + "src/quic/core/quic_bandwidth.h", + "src/quic/core/quic_blocked_writer_interface.h", + "src/quic/core/quic_buffer_allocator.cc", + "src/quic/core/quic_buffer_allocator.h", + "src/quic/core/quic_chaos_protector.cc", + "src/quic/core/quic_chaos_protector.h", + "src/quic/core/quic_clock.cc", + "src/quic/core/quic_clock.h", + "src/quic/core/quic_coalesced_packet.cc", + "src/quic/core/quic_coalesced_packet.h", + "src/quic/core/quic_config.cc", + "src/quic/core/quic_config.h", + "src/quic/core/quic_connection.cc", + "src/quic/core/quic_connection.h", + "src/quic/core/quic_connection_id.cc", + "src/quic/core/quic_connection_id.h", + "src/quic/core/quic_connection_id_manager.cc", + "src/quic/core/quic_connection_id_manager.h", + "src/quic/core/quic_connection_stats.cc", + "src/quic/core/quic_connection_stats.h", + "src/quic/core/quic_constants.cc", + "src/quic/core/quic_constants.h", + "src/quic/core/quic_control_frame_manager.cc", + "src/quic/core/quic_control_frame_manager.h", + "src/quic/core/quic_crypto_client_handshaker.cc", + "src/quic/core/quic_crypto_client_handshaker.h", + "src/quic/core/quic_crypto_client_stream.cc", + "src/quic/core/quic_crypto_client_stream.h", + "src/quic/core/quic_crypto_handshaker.cc", + "src/quic/core/quic_crypto_handshaker.h", + "src/quic/core/quic_crypto_server_stream.cc", + "src/quic/core/quic_crypto_server_stream.h", + "src/quic/core/quic_crypto_server_stream_base.cc", + "src/quic/core/quic_crypto_server_stream_base.h", + "src/quic/core/quic_crypto_stream.cc", + "src/quic/core/quic_crypto_stream.h", + "src/quic/core/quic_data_reader.cc", + "src/quic/core/quic_data_reader.h", + "src/quic/core/quic_data_writer.cc", + "src/quic/core/quic_data_writer.h", + "src/quic/core/quic_datagram_queue.cc", + "src/quic/core/quic_datagram_queue.h", "src/quic/core/quic_error_codes.cc", "src/quic/core/quic_error_codes.h", + "src/quic/core/quic_flow_controller.cc", + "src/quic/core/quic_flow_controller.h", + "src/quic/core/quic_framer.cc", + "src/quic/core/quic_framer.h", + "src/quic/core/quic_idle_network_detector.cc", + "src/quic/core/quic_idle_network_detector.h", + "src/quic/core/quic_interval.h", + "src/quic/core/quic_interval_deque.h", + "src/quic/core/quic_interval_set.h", + "src/quic/core/quic_legacy_version_encapsulator.cc", + "src/quic/core/quic_legacy_version_encapsulator.h", + "src/quic/core/quic_lru_cache.h", + "src/quic/core/quic_mtu_discovery.cc", + "src/quic/core/quic_mtu_discovery.h", + "src/quic/core/quic_network_blackhole_detector.cc", + "src/quic/core/quic_network_blackhole_detector.h", + "src/quic/core/quic_one_block_arena.h", + "src/quic/core/quic_packet_creator.cc", + "src/quic/core/quic_packet_creator.h", + "src/quic/core/quic_packet_number.cc", + "src/quic/core/quic_packet_number.h", + "src/quic/core/quic_packet_writer.h", + "src/quic/core/quic_packets.cc", + "src/quic/core/quic_packets.h", + "src/quic/core/quic_path_validator.cc", + "src/quic/core/quic_path_validator.h", + "src/quic/core/quic_protocol_flags_list.h", + "src/quic/core/quic_received_packet_manager.cc", + "src/quic/core/quic_received_packet_manager.h", + "src/quic/core/quic_sent_packet_manager.cc", + "src/quic/core/quic_sent_packet_manager.h", + "src/quic/core/quic_server_id.cc", + "src/quic/core/quic_server_id.h", + "src/quic/core/quic_session.cc", + "src/quic/core/quic_session.h", + "src/quic/core/quic_simple_buffer_allocator.cc", + "src/quic/core/quic_simple_buffer_allocator.h", + "src/quic/core/quic_socket_address_coder.cc", + "src/quic/core/quic_socket_address_coder.h", + "src/quic/core/quic_stream.cc", + "src/quic/core/quic_stream.h", + "src/quic/core/quic_stream_frame_data_producer.h", + "src/quic/core/quic_stream_id_manager.cc", + "src/quic/core/quic_stream_id_manager.h", + "src/quic/core/quic_stream_send_buffer.cc", + "src/quic/core/quic_stream_send_buffer.h", + "src/quic/core/quic_stream_sequencer.cc", + "src/quic/core/quic_stream_sequencer.h", + "src/quic/core/quic_stream_sequencer_buffer.cc", + "src/quic/core/quic_stream_sequencer_buffer.h", + "src/quic/core/quic_sustained_bandwidth_recorder.cc", + "src/quic/core/quic_sustained_bandwidth_recorder.h", + "src/quic/core/quic_tag.cc", + "src/quic/core/quic_tag.h", + "src/quic/core/quic_time.cc", + "src/quic/core/quic_time.h", + "src/quic/core/quic_time_accumulator.h", + "src/quic/core/quic_transmission_info.cc", + "src/quic/core/quic_transmission_info.h", + "src/quic/core/quic_types.cc", + "src/quic/core/quic_types.h", + "src/quic/core/quic_unacked_packet_map.cc", + "src/quic/core/quic_unacked_packet_map.h", + "src/quic/core/quic_utils.cc", + "src/quic/core/quic_utils.h", + "src/quic/core/quic_version_manager.cc", + "src/quic/core/quic_version_manager.h", + "src/quic/core/quic_versions.cc", + "src/quic/core/quic_versions.h", + "src/quic/core/quic_write_blocked_list.cc", + "src/quic/core/quic_write_blocked_list.h", + "src/quic/core/session_notifier_interface.h", + "src/quic/core/stream_delegate_interface.h", + "src/quic/core/tls_client_handshaker.cc", + "src/quic/core/tls_client_handshaker.h", + "src/quic/core/tls_handshaker.cc", + "src/quic/core/tls_handshaker.h", + "src/quic/core/tls_server_handshaker.cc", + "src/quic/core/tls_server_handshaker.h", + "src/quic/core/uber_quic_stream_id_manager.cc", + "src/quic/core/uber_quic_stream_id_manager.h", + "src/quic/core/uber_received_packet_manager.cc", + "src/quic/core/uber_received_packet_manager.h", + "src/quic/core/web_transport_stream_adapter.cc", + "src/quic/core/web_transport_stream_adapter.h", + "src/quic/platform/api/quic_bug_tracker.h", + "src/quic/platform/api/quic_client_stats.h", + "src/quic/platform/api/quic_containers.h", + "src/quic/platform/api/quic_error_code_wrappers.h", + "src/quic/platform/api/quic_estimate_memory_usage.h", + "src/quic/platform/api/quic_export.h", + "src/quic/platform/api/quic_exported_stats.h", + "src/quic/platform/api/quic_file_utils.cc", + "src/quic/platform/api/quic_file_utils.h", + "src/quic/platform/api/quic_flag_utils.h", + "src/quic/platform/api/quic_flags.h", + "src/quic/platform/api/quic_hostname_utils.cc", + "src/quic/platform/api/quic_hostname_utils.h", + "src/quic/platform/api/quic_iovec.h", + "src/quic/platform/api/quic_ip_address.cc", + "src/quic/platform/api/quic_ip_address.h", + "src/quic/platform/api/quic_ip_address_family.h", + "src/quic/platform/api/quic_logging.h", + "src/quic/platform/api/quic_map_util.h", + "src/quic/platform/api/quic_mem_slice.h", + "src/quic/platform/api/quic_mem_slice_span.h", + "src/quic/platform/api/quic_mem_slice_storage.h", + "src/quic/platform/api/quic_mutex.cc", + "src/quic/platform/api/quic_mutex.h", + "src/quic/platform/api/quic_reference_counted.h", + "src/quic/platform/api/quic_server_stats.h", + "src/quic/platform/api/quic_sleep.h", + "src/quic/platform/api/quic_socket_address.cc", + "src/quic/platform/api/quic_socket_address.h", + "src/quic/platform/api/quic_stack_trace.h", + "src/quic/platform/api/quic_thread.h", + "src/quic/quic_transport/quic_transport_client_session.cc", + "src/quic/quic_transport/quic_transport_client_session.h", + "src/quic/quic_transport/quic_transport_protocol.h", + "src/quic/quic_transport/quic_transport_server_session.cc", + "src/quic/quic_transport/quic_transport_server_session.h", + "src/quic/quic_transport/quic_transport_session_interface.h", + "src/quic/quic_transport/quic_transport_stream.cc", + "src/quic/quic_transport/quic_transport_stream.h", + "src/quic/quic_transport/web_transport_fingerprint_proof_verifier.cc", + "src/quic/quic_transport/web_transport_fingerprint_proof_verifier.h", + "src/spdy/core/hpack/hpack_constants.cc", + "src/spdy/core/hpack/hpack_constants.h", + "src/spdy/core/hpack/hpack_decoder_adapter.cc", + "src/spdy/core/hpack/hpack_decoder_adapter.h", + "src/spdy/core/hpack/hpack_encoder.cc", + "src/spdy/core/hpack/hpack_encoder.h", + "src/spdy/core/hpack/hpack_entry.cc", + "src/spdy/core/hpack/hpack_entry.h", + "src/spdy/core/hpack/hpack_header_table.cc", + "src/spdy/core/hpack/hpack_header_table.h", + "src/spdy/core/hpack/hpack_output_stream.cc", + "src/spdy/core/hpack/hpack_output_stream.h", + "src/spdy/core/hpack/hpack_static_table.cc", + "src/spdy/core/hpack/hpack_static_table.h", + "src/spdy/core/http2_frame_decoder_adapter.cc", + "src/spdy/core/http2_frame_decoder_adapter.h", + "src/spdy/core/recording_headers_handler.cc", + "src/spdy/core/recording_headers_handler.h", + "src/spdy/core/spdy_alt_svc_wire_format.cc", + "src/spdy/core/spdy_alt_svc_wire_format.h", + "src/spdy/core/spdy_bitmasks.h", + "src/spdy/core/spdy_frame_builder.cc", + "src/spdy/core/spdy_frame_builder.h", + "src/spdy/core/spdy_frame_reader.cc", + "src/spdy/core/spdy_frame_reader.h", + "src/spdy/core/spdy_framer.cc", + "src/spdy/core/spdy_framer.h", + "src/spdy/core/spdy_header_block.cc", + "src/spdy/core/spdy_header_block.h", + "src/spdy/core/spdy_header_storage.cc", + "src/spdy/core/spdy_header_storage.h", + "src/spdy/core/spdy_headers_handler_interface.h", + "src/spdy/core/spdy_intrusive_list.h", + "src/spdy/core/spdy_no_op_visitor.cc", + "src/spdy/core/spdy_no_op_visitor.h", + "src/spdy/core/spdy_pinnable_buffer_piece.cc", + "src/spdy/core/spdy_pinnable_buffer_piece.h", + "src/spdy/core/spdy_prefixed_buffer_reader.cc", + "src/spdy/core/spdy_prefixed_buffer_reader.h", + "src/spdy/core/spdy_protocol.cc", + "src/spdy/core/spdy_protocol.h", + "src/spdy/core/spdy_simple_arena.cc", + "src/spdy/core/spdy_simple_arena.h", + "src/spdy/core/zero_copy_output_buffer.h", + "src/spdy/platform/api/spdy_containers.h", + "src/spdy/platform/api/spdy_estimate_memory_usage.h", ] - if (!is_nacl) { - sources += [ - "overrides/quiche_platform_impl/quic_mutex_impl.cc", - "overrides/quiche_platform_impl/quic_mutex_impl.h", - "overrides/quiche_platform_impl/quiche_logging_impl.h", - "overrides/quiche_platform_impl/quiche_time_utils_impl.cc", - "overrides/quiche_platform_impl/quiche_time_utils_impl.h", - "src/common/platform/api/quiche_export.h", - "src/common/platform/api/quiche_flag_utils.h", - "src/common/platform/api/quiche_flags.h", - "src/common/platform/api/quiche_logging.h", - "src/common/platform/api/quiche_text_utils.h", - "src/common/platform/api/quiche_time_utils.h", - "src/common/quiche_data_reader.cc", - "src/common/quiche_data_reader.h", - "src/common/quiche_data_writer.cc", - "src/common/quiche_data_writer.h", - "src/common/quiche_endian.h", - "src/common/simple_linked_hash_map.h", - "src/http2/decoder/decode_buffer.cc", - "src/http2/decoder/decode_buffer.h", - "src/http2/decoder/decode_http2_structures.cc", - "src/http2/decoder/decode_http2_structures.h", - "src/http2/decoder/decode_status.cc", - "src/http2/decoder/decode_status.h", - "src/http2/decoder/frame_decoder_state.cc", - "src/http2/decoder/frame_decoder_state.h", - "src/http2/decoder/http2_frame_decoder.cc", - "src/http2/decoder/http2_frame_decoder.h", - "src/http2/decoder/http2_frame_decoder_listener.cc", - "src/http2/decoder/http2_frame_decoder_listener.h", - "src/http2/decoder/http2_structure_decoder.cc", - "src/http2/decoder/http2_structure_decoder.h", - "src/http2/decoder/payload_decoders/altsvc_payload_decoder.cc", - "src/http2/decoder/payload_decoders/altsvc_payload_decoder.h", - "src/http2/decoder/payload_decoders/continuation_payload_decoder.cc", - "src/http2/decoder/payload_decoders/continuation_payload_decoder.h", - "src/http2/decoder/payload_decoders/data_payload_decoder.cc", - "src/http2/decoder/payload_decoders/data_payload_decoder.h", - "src/http2/decoder/payload_decoders/goaway_payload_decoder.cc", - "src/http2/decoder/payload_decoders/goaway_payload_decoder.h", - "src/http2/decoder/payload_decoders/headers_payload_decoder.cc", - "src/http2/decoder/payload_decoders/headers_payload_decoder.h", - "src/http2/decoder/payload_decoders/ping_payload_decoder.cc", - "src/http2/decoder/payload_decoders/ping_payload_decoder.h", - "src/http2/decoder/payload_decoders/priority_payload_decoder.cc", - "src/http2/decoder/payload_decoders/priority_payload_decoder.h", - "src/http2/decoder/payload_decoders/priority_update_payload_decoder.cc", - "src/http2/decoder/payload_decoders/priority_update_payload_decoder.h", - "src/http2/decoder/payload_decoders/push_promise_payload_decoder.cc", - "src/http2/decoder/payload_decoders/push_promise_payload_decoder.h", - "src/http2/decoder/payload_decoders/rst_stream_payload_decoder.cc", - "src/http2/decoder/payload_decoders/rst_stream_payload_decoder.h", - "src/http2/decoder/payload_decoders/settings_payload_decoder.cc", - "src/http2/decoder/payload_decoders/settings_payload_decoder.h", - "src/http2/decoder/payload_decoders/unknown_payload_decoder.cc", - "src/http2/decoder/payload_decoders/unknown_payload_decoder.h", - "src/http2/decoder/payload_decoders/window_update_payload_decoder.cc", - "src/http2/decoder/payload_decoders/window_update_payload_decoder.h", - "src/http2/hpack/decoder/hpack_block_decoder.cc", - "src/http2/hpack/decoder/hpack_block_decoder.h", - "src/http2/hpack/decoder/hpack_decoder.cc", - "src/http2/hpack/decoder/hpack_decoder.h", - "src/http2/hpack/decoder/hpack_decoder_listener.cc", - "src/http2/hpack/decoder/hpack_decoder_listener.h", - "src/http2/hpack/decoder/hpack_decoder_state.cc", - "src/http2/hpack/decoder/hpack_decoder_state.h", - "src/http2/hpack/decoder/hpack_decoder_string_buffer.cc", - "src/http2/hpack/decoder/hpack_decoder_string_buffer.h", - "src/http2/hpack/decoder/hpack_decoder_tables.cc", - "src/http2/hpack/decoder/hpack_decoder_tables.h", - "src/http2/hpack/decoder/hpack_decoding_error.cc", - "src/http2/hpack/decoder/hpack_decoding_error.h", - "src/http2/hpack/decoder/hpack_entry_decoder.cc", - "src/http2/hpack/decoder/hpack_entry_decoder.h", - "src/http2/hpack/decoder/hpack_entry_decoder_listener.cc", - "src/http2/hpack/decoder/hpack_entry_decoder_listener.h", - "src/http2/hpack/decoder/hpack_entry_type_decoder.cc", - "src/http2/hpack/decoder/hpack_entry_type_decoder.h", - "src/http2/hpack/decoder/hpack_string_decoder.cc", - "src/http2/hpack/decoder/hpack_string_decoder.h", - "src/http2/hpack/decoder/hpack_string_decoder_listener.cc", - "src/http2/hpack/decoder/hpack_string_decoder_listener.h", - "src/http2/hpack/decoder/hpack_whole_entry_buffer.cc", - "src/http2/hpack/decoder/hpack_whole_entry_buffer.h", - "src/http2/hpack/decoder/hpack_whole_entry_listener.cc", - "src/http2/hpack/decoder/hpack_whole_entry_listener.h", - "src/http2/hpack/hpack_static_table_entries.inc", - "src/http2/hpack/http2_hpack_constants.cc", - "src/http2/hpack/http2_hpack_constants.h", - "src/http2/hpack/huffman/hpack_huffman_decoder.cc", - "src/http2/hpack/huffman/hpack_huffman_decoder.h", - "src/http2/hpack/huffman/hpack_huffman_encoder.cc", - "src/http2/hpack/huffman/hpack_huffman_encoder.h", - "src/http2/hpack/huffman/huffman_spec_tables.cc", - "src/http2/hpack/huffman/huffman_spec_tables.h", - "src/http2/hpack/varint/hpack_varint_decoder.cc", - "src/http2/hpack/varint/hpack_varint_decoder.h", - "src/http2/hpack/varint/hpack_varint_encoder.cc", - "src/http2/hpack/varint/hpack_varint_encoder.h", - "src/http2/http2_constants.cc", - "src/http2/http2_constants.h", - "src/http2/http2_structures.cc", - "src/http2/http2_structures.h", - "src/http2/platform/api/http2_bug_tracker.h", - "src/http2/platform/api/http2_containers.h", - "src/http2/platform/api/http2_estimate_memory_usage.h", - "src/http2/platform/api/http2_flag_utils.h", - "src/http2/platform/api/http2_flags.h", - "src/http2/platform/api/http2_logging.h", - "src/http2/platform/api/http2_macros.h", - "src/http2/platform/api/http2_string_utils.h", - "src/quic/core/congestion_control/bandwidth_sampler.cc", - "src/quic/core/congestion_control/bandwidth_sampler.h", - "src/quic/core/congestion_control/bbr2_drain.cc", - "src/quic/core/congestion_control/bbr2_drain.h", - "src/quic/core/congestion_control/bbr2_misc.cc", - "src/quic/core/congestion_control/bbr2_misc.h", - "src/quic/core/congestion_control/bbr2_probe_bw.cc", - "src/quic/core/congestion_control/bbr2_probe_bw.h", - "src/quic/core/congestion_control/bbr2_probe_rtt.cc", - "src/quic/core/congestion_control/bbr2_probe_rtt.h", - "src/quic/core/congestion_control/bbr2_sender.cc", - "src/quic/core/congestion_control/bbr2_sender.h", - "src/quic/core/congestion_control/bbr2_startup.cc", - "src/quic/core/congestion_control/bbr2_startup.h", - "src/quic/core/congestion_control/bbr_sender.cc", - "src/quic/core/congestion_control/bbr_sender.h", - "src/quic/core/congestion_control/cubic_bytes.cc", - "src/quic/core/congestion_control/cubic_bytes.h", - "src/quic/core/congestion_control/general_loss_algorithm.cc", - "src/quic/core/congestion_control/general_loss_algorithm.h", - "src/quic/core/congestion_control/hybrid_slow_start.cc", - "src/quic/core/congestion_control/hybrid_slow_start.h", - "src/quic/core/congestion_control/loss_detection_interface.h", - "src/quic/core/congestion_control/pacing_sender.cc", - "src/quic/core/congestion_control/pacing_sender.h", - "src/quic/core/congestion_control/prr_sender.cc", - "src/quic/core/congestion_control/prr_sender.h", - "src/quic/core/congestion_control/rtt_stats.cc", - "src/quic/core/congestion_control/rtt_stats.h", - "src/quic/core/congestion_control/send_algorithm_interface.cc", - "src/quic/core/congestion_control/send_algorithm_interface.h", - "src/quic/core/congestion_control/tcp_cubic_sender_bytes.cc", - "src/quic/core/congestion_control/tcp_cubic_sender_bytes.h", - "src/quic/core/congestion_control/uber_loss_algorithm.cc", - "src/quic/core/congestion_control/uber_loss_algorithm.h", - "src/quic/core/congestion_control/windowed_filter.h", - "src/quic/core/crypto/aead_base_decrypter.cc", - "src/quic/core/crypto/aead_base_decrypter.h", - "src/quic/core/crypto/aead_base_encrypter.cc", - "src/quic/core/crypto/aead_base_encrypter.h", - "src/quic/core/crypto/aes_128_gcm_12_decrypter.cc", - "src/quic/core/crypto/aes_128_gcm_12_decrypter.h", - "src/quic/core/crypto/aes_128_gcm_12_encrypter.cc", - "src/quic/core/crypto/aes_128_gcm_12_encrypter.h", - "src/quic/core/crypto/aes_128_gcm_decrypter.cc", - "src/quic/core/crypto/aes_128_gcm_decrypter.h", - "src/quic/core/crypto/aes_128_gcm_encrypter.cc", - "src/quic/core/crypto/aes_128_gcm_encrypter.h", - "src/quic/core/crypto/aes_256_gcm_decrypter.cc", - "src/quic/core/crypto/aes_256_gcm_decrypter.h", - "src/quic/core/crypto/aes_256_gcm_encrypter.cc", - "src/quic/core/crypto/aes_256_gcm_encrypter.h", - "src/quic/core/crypto/aes_base_decrypter.cc", - "src/quic/core/crypto/aes_base_decrypter.h", - "src/quic/core/crypto/aes_base_encrypter.cc", - "src/quic/core/crypto/aes_base_encrypter.h", - "src/quic/core/crypto/boring_utils.h", - "src/quic/core/crypto/cert_compressor.cc", - "src/quic/core/crypto/cert_compressor.h", - "src/quic/core/crypto/certificate_view.cc", - "src/quic/core/crypto/certificate_view.h", - "src/quic/core/crypto/chacha20_poly1305_decrypter.cc", - "src/quic/core/crypto/chacha20_poly1305_decrypter.h", - "src/quic/core/crypto/chacha20_poly1305_encrypter.cc", - "src/quic/core/crypto/chacha20_poly1305_encrypter.h", - "src/quic/core/crypto/chacha20_poly1305_tls_decrypter.cc", - "src/quic/core/crypto/chacha20_poly1305_tls_decrypter.h", - "src/quic/core/crypto/chacha20_poly1305_tls_encrypter.cc", - "src/quic/core/crypto/chacha20_poly1305_tls_encrypter.h", - "src/quic/core/crypto/chacha_base_decrypter.cc", - "src/quic/core/crypto/chacha_base_decrypter.h", - "src/quic/core/crypto/chacha_base_encrypter.cc", - "src/quic/core/crypto/chacha_base_encrypter.h", - "src/quic/core/crypto/channel_id.cc", - "src/quic/core/crypto/channel_id.h", - "src/quic/core/crypto/common_cert_set.cc", - "src/quic/core/crypto/common_cert_set.h", - "src/quic/core/crypto/crypto_framer.cc", - "src/quic/core/crypto/crypto_framer.h", - "src/quic/core/crypto/crypto_handshake.cc", - "src/quic/core/crypto/crypto_handshake.h", - "src/quic/core/crypto/crypto_handshake_message.cc", - "src/quic/core/crypto/crypto_handshake_message.h", - "src/quic/core/crypto/crypto_message_parser.h", - "src/quic/core/crypto/crypto_protocol.h", - "src/quic/core/crypto/crypto_secret_boxer.cc", - "src/quic/core/crypto/crypto_secret_boxer.h", - "src/quic/core/crypto/crypto_utils.cc", - "src/quic/core/crypto/crypto_utils.h", - "src/quic/core/crypto/curve25519_key_exchange.cc", - "src/quic/core/crypto/curve25519_key_exchange.h", - "src/quic/core/crypto/key_exchange.cc", - "src/quic/core/crypto/key_exchange.h", - "src/quic/core/crypto/null_decrypter.cc", - "src/quic/core/crypto/null_decrypter.h", - "src/quic/core/crypto/null_encrypter.cc", - "src/quic/core/crypto/null_encrypter.h", - "src/quic/core/crypto/p256_key_exchange.cc", - "src/quic/core/crypto/p256_key_exchange.h", - "src/quic/core/crypto/proof_source.cc", - "src/quic/core/crypto/proof_source.h", - "src/quic/core/crypto/proof_verifier.h", - "src/quic/core/crypto/quic_compressed_certs_cache.cc", - "src/quic/core/crypto/quic_compressed_certs_cache.h", - "src/quic/core/crypto/quic_crypter.cc", - "src/quic/core/crypto/quic_crypter.h", - "src/quic/core/crypto/quic_crypto_client_config.cc", - "src/quic/core/crypto/quic_crypto_client_config.h", - "src/quic/core/crypto/quic_crypto_proof.cc", - "src/quic/core/crypto/quic_crypto_proof.h", - "src/quic/core/crypto/quic_crypto_server_config.cc", - "src/quic/core/crypto/quic_crypto_server_config.h", - "src/quic/core/crypto/quic_decrypter.cc", - "src/quic/core/crypto/quic_decrypter.h", - "src/quic/core/crypto/quic_encrypter.cc", - "src/quic/core/crypto/quic_encrypter.h", - "src/quic/core/crypto/quic_hkdf.cc", - "src/quic/core/crypto/quic_hkdf.h", - "src/quic/core/crypto/quic_random.cc", - "src/quic/core/crypto/quic_random.h", - "src/quic/core/crypto/server_proof_verifier.h", - "src/quic/core/crypto/tls_client_connection.cc", - "src/quic/core/crypto/tls_client_connection.h", - "src/quic/core/crypto/tls_connection.cc", - "src/quic/core/crypto/tls_connection.h", - "src/quic/core/crypto/tls_server_connection.cc", - "src/quic/core/crypto/tls_server_connection.h", - "src/quic/core/crypto/transport_parameters.cc", - "src/quic/core/crypto/transport_parameters.h", - "src/quic/core/frames/quic_ack_frame.cc", - "src/quic/core/frames/quic_ack_frame.h", - "src/quic/core/frames/quic_ack_frequency_frame.cc", - "src/quic/core/frames/quic_ack_frequency_frame.h", - "src/quic/core/frames/quic_blocked_frame.cc", - "src/quic/core/frames/quic_blocked_frame.h", - "src/quic/core/frames/quic_connection_close_frame.cc", - "src/quic/core/frames/quic_connection_close_frame.h", - "src/quic/core/frames/quic_crypto_frame.cc", - "src/quic/core/frames/quic_crypto_frame.h", - "src/quic/core/frames/quic_frame.cc", - "src/quic/core/frames/quic_frame.h", - "src/quic/core/frames/quic_goaway_frame.cc", - "src/quic/core/frames/quic_goaway_frame.h", - "src/quic/core/frames/quic_handshake_done_frame.cc", - "src/quic/core/frames/quic_handshake_done_frame.h", - "src/quic/core/frames/quic_inlined_frame.h", - "src/quic/core/frames/quic_max_streams_frame.cc", - "src/quic/core/frames/quic_max_streams_frame.h", - "src/quic/core/frames/quic_message_frame.cc", - "src/quic/core/frames/quic_message_frame.h", - "src/quic/core/frames/quic_mtu_discovery_frame.h", - "src/quic/core/frames/quic_new_connection_id_frame.cc", - "src/quic/core/frames/quic_new_connection_id_frame.h", - "src/quic/core/frames/quic_new_token_frame.cc", - "src/quic/core/frames/quic_new_token_frame.h", - "src/quic/core/frames/quic_padding_frame.cc", - "src/quic/core/frames/quic_padding_frame.h", - "src/quic/core/frames/quic_path_challenge_frame.cc", - "src/quic/core/frames/quic_path_challenge_frame.h", - "src/quic/core/frames/quic_path_response_frame.cc", - "src/quic/core/frames/quic_path_response_frame.h", - "src/quic/core/frames/quic_ping_frame.cc", - "src/quic/core/frames/quic_ping_frame.h", - "src/quic/core/frames/quic_retire_connection_id_frame.cc", - "src/quic/core/frames/quic_retire_connection_id_frame.h", - "src/quic/core/frames/quic_rst_stream_frame.cc", - "src/quic/core/frames/quic_rst_stream_frame.h", - "src/quic/core/frames/quic_stop_sending_frame.cc", - "src/quic/core/frames/quic_stop_sending_frame.h", - "src/quic/core/frames/quic_stop_waiting_frame.cc", - "src/quic/core/frames/quic_stop_waiting_frame.h", - "src/quic/core/frames/quic_stream_frame.cc", - "src/quic/core/frames/quic_stream_frame.h", - "src/quic/core/frames/quic_streams_blocked_frame.cc", - "src/quic/core/frames/quic_streams_blocked_frame.h", - "src/quic/core/frames/quic_window_update_frame.cc", - "src/quic/core/frames/quic_window_update_frame.h", - "src/quic/core/handshaker_delegate_interface.h", - "src/quic/core/http/http_constants.cc", - "src/quic/core/http/http_constants.h", - "src/quic/core/http/http_decoder.cc", - "src/quic/core/http/http_decoder.h", - "src/quic/core/http/http_encoder.cc", - "src/quic/core/http/http_encoder.h", - "src/quic/core/http/http_frames.h", - "src/quic/core/http/quic_client_promised_info.cc", - "src/quic/core/http/quic_client_promised_info.h", - "src/quic/core/http/quic_client_push_promise_index.cc", - "src/quic/core/http/quic_client_push_promise_index.h", - "src/quic/core/http/quic_header_list.cc", - "src/quic/core/http/quic_header_list.h", - "src/quic/core/http/quic_headers_stream.cc", - "src/quic/core/http/quic_headers_stream.h", - "src/quic/core/http/quic_receive_control_stream.cc", - "src/quic/core/http/quic_receive_control_stream.h", - "src/quic/core/http/quic_send_control_stream.cc", - "src/quic/core/http/quic_send_control_stream.h", - "src/quic/core/http/quic_server_initiated_spdy_stream.cc", - "src/quic/core/http/quic_server_initiated_spdy_stream.h", - "src/quic/core/http/quic_server_session_base.cc", - "src/quic/core/http/quic_server_session_base.h", - "src/quic/core/http/quic_spdy_client_session.cc", - "src/quic/core/http/quic_spdy_client_session.h", - "src/quic/core/http/quic_spdy_client_session_base.cc", - "src/quic/core/http/quic_spdy_client_session_base.h", - "src/quic/core/http/quic_spdy_client_stream.cc", - "src/quic/core/http/quic_spdy_client_stream.h", - "src/quic/core/http/quic_spdy_session.cc", - "src/quic/core/http/quic_spdy_session.h", - "src/quic/core/http/quic_spdy_stream.cc", - "src/quic/core/http/quic_spdy_stream.h", - "src/quic/core/http/quic_spdy_stream_body_manager.cc", - "src/quic/core/http/quic_spdy_stream_body_manager.h", - "src/quic/core/http/spdy_server_push_utils.cc", - "src/quic/core/http/spdy_server_push_utils.h", - "src/quic/core/http/spdy_utils.cc", - "src/quic/core/http/spdy_utils.h", - "src/quic/core/http/web_transport_http3.cc", - "src/quic/core/http/web_transport_http3.h", - "src/quic/core/legacy_quic_stream_id_manager.cc", - "src/quic/core/legacy_quic_stream_id_manager.h", - "src/quic/core/packet_number_indexed_queue.h", - "src/quic/core/proto/cached_network_parameters_proto.h", - "src/quic/core/proto/crypto_server_config_proto.h", - "src/quic/core/proto/source_address_token_proto.h", - "src/quic/core/qpack/qpack_blocking_manager.cc", - "src/quic/core/qpack/qpack_blocking_manager.h", - "src/quic/core/qpack/qpack_decoded_headers_accumulator.cc", - "src/quic/core/qpack/qpack_decoded_headers_accumulator.h", - "src/quic/core/qpack/qpack_decoder.cc", - "src/quic/core/qpack/qpack_decoder.h", - "src/quic/core/qpack/qpack_decoder_stream_receiver.cc", - "src/quic/core/qpack/qpack_decoder_stream_receiver.h", - "src/quic/core/qpack/qpack_decoder_stream_sender.cc", - "src/quic/core/qpack/qpack_decoder_stream_sender.h", - "src/quic/core/qpack/qpack_encoder.cc", - "src/quic/core/qpack/qpack_encoder.h", - "src/quic/core/qpack/qpack_encoder_stream_receiver.cc", - "src/quic/core/qpack/qpack_encoder_stream_receiver.h", - "src/quic/core/qpack/qpack_encoder_stream_sender.cc", - "src/quic/core/qpack/qpack_encoder_stream_sender.h", - "src/quic/core/qpack/qpack_header_table.cc", - "src/quic/core/qpack/qpack_header_table.h", - "src/quic/core/qpack/qpack_index_conversions.cc", - "src/quic/core/qpack/qpack_index_conversions.h", - "src/quic/core/qpack/qpack_instruction_decoder.cc", - "src/quic/core/qpack/qpack_instruction_decoder.h", - "src/quic/core/qpack/qpack_instruction_encoder.cc", - "src/quic/core/qpack/qpack_instruction_encoder.h", - "src/quic/core/qpack/qpack_instructions.cc", - "src/quic/core/qpack/qpack_instructions.h", - "src/quic/core/qpack/qpack_progressive_decoder.cc", - "src/quic/core/qpack/qpack_progressive_decoder.h", - "src/quic/core/qpack/qpack_receive_stream.cc", - "src/quic/core/qpack/qpack_receive_stream.h", - "src/quic/core/qpack/qpack_required_insert_count.cc", - "src/quic/core/qpack/qpack_required_insert_count.h", - "src/quic/core/qpack/qpack_send_stream.cc", - "src/quic/core/qpack/qpack_send_stream.h", - "src/quic/core/qpack/qpack_static_table.cc", - "src/quic/core/qpack/qpack_static_table.h", - "src/quic/core/qpack/qpack_stream_receiver.h", - "src/quic/core/qpack/qpack_stream_sender_delegate.h", - "src/quic/core/qpack/value_splitting_header_list.cc", - "src/quic/core/qpack/value_splitting_header_list.h", - "src/quic/core/quic_ack_listener_interface.cc", - "src/quic/core/quic_ack_listener_interface.h", - "src/quic/core/quic_alarm.cc", - "src/quic/core/quic_alarm.h", - "src/quic/core/quic_alarm_factory.h", - "src/quic/core/quic_arena_scoped_ptr.h", - "src/quic/core/quic_bandwidth.cc", - "src/quic/core/quic_bandwidth.h", - "src/quic/core/quic_blocked_writer_interface.h", - "src/quic/core/quic_buffer_allocator.cc", - "src/quic/core/quic_buffer_allocator.h", - "src/quic/core/quic_circular_deque.h", - "src/quic/core/quic_clock.cc", - "src/quic/core/quic_clock.h", - "src/quic/core/quic_coalesced_packet.cc", - "src/quic/core/quic_coalesced_packet.h", - "src/quic/core/quic_config.cc", - "src/quic/core/quic_config.h", - "src/quic/core/quic_connection.cc", - "src/quic/core/quic_connection.h", - "src/quic/core/quic_connection_id.cc", - "src/quic/core/quic_connection_id.h", - "src/quic/core/quic_connection_id_manager.cc", - "src/quic/core/quic_connection_id_manager.h", - "src/quic/core/quic_connection_stats.cc", - "src/quic/core/quic_connection_stats.h", - "src/quic/core/quic_constants.cc", - "src/quic/core/quic_constants.h", - "src/quic/core/quic_control_frame_manager.cc", - "src/quic/core/quic_control_frame_manager.h", - "src/quic/core/quic_crypto_client_handshaker.cc", - "src/quic/core/quic_crypto_client_handshaker.h", - "src/quic/core/quic_crypto_client_stream.cc", - "src/quic/core/quic_crypto_client_stream.h", - "src/quic/core/quic_crypto_handshaker.cc", - "src/quic/core/quic_crypto_handshaker.h", - "src/quic/core/quic_crypto_server_stream.cc", - "src/quic/core/quic_crypto_server_stream.h", - "src/quic/core/quic_crypto_server_stream_base.cc", - "src/quic/core/quic_crypto_server_stream_base.h", - "src/quic/core/quic_crypto_stream.cc", - "src/quic/core/quic_crypto_stream.h", - "src/quic/core/quic_data_reader.cc", - "src/quic/core/quic_data_reader.h", - "src/quic/core/quic_data_writer.cc", - "src/quic/core/quic_data_writer.h", - "src/quic/core/quic_datagram_queue.cc", - "src/quic/core/quic_datagram_queue.h", - "src/quic/core/quic_flow_controller.cc", - "src/quic/core/quic_flow_controller.h", - "src/quic/core/quic_framer.cc", - "src/quic/core/quic_framer.h", - "src/quic/core/quic_idle_network_detector.cc", - "src/quic/core/quic_idle_network_detector.h", - "src/quic/core/quic_interval.h", - "src/quic/core/quic_interval_deque.h", - "src/quic/core/quic_interval_set.h", - "src/quic/core/quic_legacy_version_encapsulator.cc", - "src/quic/core/quic_legacy_version_encapsulator.h", - "src/quic/core/quic_lru_cache.h", - "src/quic/core/quic_mtu_discovery.cc", - "src/quic/core/quic_mtu_discovery.h", - "src/quic/core/quic_network_blackhole_detector.cc", - "src/quic/core/quic_network_blackhole_detector.h", - "src/quic/core/quic_one_block_arena.h", - "src/quic/core/quic_packet_creator.cc", - "src/quic/core/quic_packet_creator.h", - "src/quic/core/quic_packet_number.cc", - "src/quic/core/quic_packet_number.h", - "src/quic/core/quic_packet_writer.h", - "src/quic/core/quic_packets.cc", - "src/quic/core/quic_packets.h", - "src/quic/core/quic_path_validator.cc", - "src/quic/core/quic_path_validator.h", - "src/quic/core/quic_protocol_flags_list.h", - "src/quic/core/quic_received_packet_manager.cc", - "src/quic/core/quic_received_packet_manager.h", - "src/quic/core/quic_sent_packet_manager.cc", - "src/quic/core/quic_sent_packet_manager.h", - "src/quic/core/quic_server_id.cc", - "src/quic/core/quic_server_id.h", - "src/quic/core/quic_session.cc", - "src/quic/core/quic_session.h", - "src/quic/core/quic_simple_buffer_allocator.cc", - "src/quic/core/quic_simple_buffer_allocator.h", - "src/quic/core/quic_socket_address_coder.cc", - "src/quic/core/quic_socket_address_coder.h", - "src/quic/core/quic_stream.cc", - "src/quic/core/quic_stream.h", - "src/quic/core/quic_stream_frame_data_producer.h", - "src/quic/core/quic_stream_id_manager.cc", - "src/quic/core/quic_stream_id_manager.h", - "src/quic/core/quic_stream_send_buffer.cc", - "src/quic/core/quic_stream_send_buffer.h", - "src/quic/core/quic_stream_sequencer.cc", - "src/quic/core/quic_stream_sequencer.h", - "src/quic/core/quic_stream_sequencer_buffer.cc", - "src/quic/core/quic_stream_sequencer_buffer.h", - "src/quic/core/quic_sustained_bandwidth_recorder.cc", - "src/quic/core/quic_sustained_bandwidth_recorder.h", - "src/quic/core/quic_tag.cc", - "src/quic/core/quic_tag.h", - "src/quic/core/quic_time.cc", - "src/quic/core/quic_time.h", - "src/quic/core/quic_time_accumulator.h", - "src/quic/core/quic_transmission_info.cc", - "src/quic/core/quic_transmission_info.h", - "src/quic/core/quic_types.cc", - "src/quic/core/quic_types.h", - "src/quic/core/quic_unacked_packet_map.cc", - "src/quic/core/quic_unacked_packet_map.h", - "src/quic/core/quic_utils.cc", - "src/quic/core/quic_utils.h", - "src/quic/core/quic_version_manager.cc", - "src/quic/core/quic_version_manager.h", - "src/quic/core/quic_versions.cc", - "src/quic/core/quic_versions.h", - "src/quic/core/quic_write_blocked_list.cc", - "src/quic/core/quic_write_blocked_list.h", - "src/quic/core/session_notifier_interface.h", - "src/quic/core/stream_delegate_interface.h", - "src/quic/core/tls_client_handshaker.cc", - "src/quic/core/tls_client_handshaker.h", - "src/quic/core/tls_handshaker.cc", - "src/quic/core/tls_handshaker.h", - "src/quic/core/tls_server_handshaker.cc", - "src/quic/core/tls_server_handshaker.h", - "src/quic/core/uber_quic_stream_id_manager.cc", - "src/quic/core/uber_quic_stream_id_manager.h", - "src/quic/core/uber_received_packet_manager.cc", - "src/quic/core/uber_received_packet_manager.h", - "src/quic/core/web_transport_stream_adapter.cc", - "src/quic/core/web_transport_stream_adapter.h", - "src/quic/platform/api/quic_bug_tracker.h", - "src/quic/platform/api/quic_client_stats.h", - "src/quic/platform/api/quic_containers.h", - "src/quic/platform/api/quic_error_code_wrappers.h", - "src/quic/platform/api/quic_estimate_memory_usage.h", - "src/quic/platform/api/quic_export.h", - "src/quic/platform/api/quic_exported_stats.h", - "src/quic/platform/api/quic_file_utils.cc", - "src/quic/platform/api/quic_file_utils.h", - "src/quic/platform/api/quic_flag_utils.h", - "src/quic/platform/api/quic_flags.h", - "src/quic/platform/api/quic_hostname_utils.cc", - "src/quic/platform/api/quic_hostname_utils.h", - "src/quic/platform/api/quic_iovec.h", - "src/quic/platform/api/quic_ip_address.cc", - "src/quic/platform/api/quic_ip_address.h", - "src/quic/platform/api/quic_ip_address_family.h", - "src/quic/platform/api/quic_logging.h", - "src/quic/platform/api/quic_map_util.h", - "src/quic/platform/api/quic_mem_slice.h", - "src/quic/platform/api/quic_mem_slice_span.h", - "src/quic/platform/api/quic_mem_slice_storage.h", - "src/quic/platform/api/quic_mutex.cc", - "src/quic/platform/api/quic_mutex.h", - "src/quic/platform/api/quic_prefetch.h", - "src/quic/platform/api/quic_reference_counted.h", - "src/quic/platform/api/quic_server_stats.h", - "src/quic/platform/api/quic_sleep.h", - "src/quic/platform/api/quic_socket_address.cc", - "src/quic/platform/api/quic_socket_address.h", - "src/quic/platform/api/quic_stack_trace.h", - "src/quic/platform/api/quic_thread.h", - "src/quic/quic_transport/quic_transport_client_session.cc", - "src/quic/quic_transport/quic_transport_client_session.h", - "src/quic/quic_transport/quic_transport_protocol.h", - "src/quic/quic_transport/quic_transport_server_session.cc", - "src/quic/quic_transport/quic_transport_server_session.h", - "src/quic/quic_transport/quic_transport_session_interface.h", - "src/quic/quic_transport/quic_transport_stream.cc", - "src/quic/quic_transport/quic_transport_stream.h", - "src/quic/quic_transport/web_transport_fingerprint_proof_verifier.cc", - "src/quic/quic_transport/web_transport_fingerprint_proof_verifier.h", - "src/spdy/core/hpack/hpack_constants.cc", - "src/spdy/core/hpack/hpack_constants.h", - "src/spdy/core/hpack/hpack_decoder_adapter.cc", - "src/spdy/core/hpack/hpack_decoder_adapter.h", - "src/spdy/core/hpack/hpack_encoder.cc", - "src/spdy/core/hpack/hpack_encoder.h", - "src/spdy/core/hpack/hpack_entry.cc", - "src/spdy/core/hpack/hpack_entry.h", - "src/spdy/core/hpack/hpack_header_table.cc", - "src/spdy/core/hpack/hpack_header_table.h", - "src/spdy/core/hpack/hpack_output_stream.cc", - "src/spdy/core/hpack/hpack_output_stream.h", - "src/spdy/core/hpack/hpack_static_table.cc", - "src/spdy/core/hpack/hpack_static_table.h", - "src/spdy/core/http2_frame_decoder_adapter.cc", - "src/spdy/core/http2_frame_decoder_adapter.h", - "src/spdy/core/http2_priority_write_scheduler.h", - "src/spdy/core/priority_write_scheduler.h", - "src/spdy/core/recording_headers_handler.cc", - "src/spdy/core/recording_headers_handler.h", - "src/spdy/core/spdy_alt_svc_wire_format.cc", - "src/spdy/core/spdy_alt_svc_wire_format.h", - "src/spdy/core/spdy_bitmasks.h", - "src/spdy/core/spdy_frame_builder.cc", - "src/spdy/core/spdy_frame_builder.h", - "src/spdy/core/spdy_frame_reader.cc", - "src/spdy/core/spdy_frame_reader.h", - "src/spdy/core/spdy_framer.cc", - "src/spdy/core/spdy_framer.h", - "src/spdy/core/spdy_header_block.cc", - "src/spdy/core/spdy_header_block.h", - "src/spdy/core/spdy_header_storage.cc", - "src/spdy/core/spdy_header_storage.h", - "src/spdy/core/spdy_headers_handler_interface.h", - "src/spdy/core/spdy_intrusive_list.h", - "src/spdy/core/spdy_no_op_visitor.cc", - "src/spdy/core/spdy_no_op_visitor.h", - "src/spdy/core/spdy_pinnable_buffer_piece.cc", - "src/spdy/core/spdy_pinnable_buffer_piece.h", - "src/spdy/core/spdy_prefixed_buffer_reader.cc", - "src/spdy/core/spdy_prefixed_buffer_reader.h", - "src/spdy/core/spdy_protocol.cc", - "src/spdy/core/spdy_protocol.h", - "src/spdy/core/spdy_simple_arena.cc", - "src/spdy/core/spdy_simple_arena.h", - "src/spdy/core/write_scheduler.h", - "src/spdy/core/zero_copy_output_buffer.h", - "src/spdy/platform/api/spdy_bug_tracker.h", - "src/spdy/platform/api/spdy_containers.h", - "src/spdy/platform/api/spdy_estimate_memory_usage.h", - "src/spdy/platform/api/spdy_flags.h", - "src/spdy/platform/api/spdy_logging.h", - "src/spdy/platform/api/spdy_string_utils.h", - ] - } - deps = [ "//net:net_deps" ] public_deps = [ "//net:net_public_deps" ] } @@ -701,6 +696,7 @@ if (is_linux || is_chromeos) { } source_set("epoll_quic_tools_core") { + testonly = true sources = [ "src/quic/core/quic_default_packet_writer.cc", "src/quic/core/quic_default_packet_writer.h", @@ -732,6 +728,7 @@ if (is_linux || is_chromeos) { } executable("epoll_quic_client") { + testonly = true sources = [ "src/quic/tools/quic_client_bin.cc", "src/quic/tools/quic_epoll_client_factory.cc", @@ -744,12 +741,14 @@ if (is_linux || is_chromeos) { "//net", "//net:epoll_quic_tools", "//net:epoll_server", + "//net:quic_test_tools", "//net:simple_quic_tools", "//third_party/boringssl", ] } executable("epoll_quic_server") { + testonly = true sources = [ "src/quic/tools/quic_epoll_server_factory.cc", "src/quic/tools/quic_epoll_server_factory.h", @@ -779,6 +778,7 @@ if (is_linux || is_chromeos) { } source_set("masque_tools") { + testonly = true sources = [ "src/quic/masque/masque_client_session.cc", "src/quic/masque/masque_client_session.h", @@ -813,6 +813,7 @@ if (is_linux || is_chromeos) { } executable("masque_client") { + testonly = true sources = [ "src/quic/masque/masque_client_bin.cc" ] deps = [ ":masque_tools", @@ -825,6 +826,7 @@ if (is_linux || is_chromeos) { } executable("masque_server") { + testonly = true sources = [ "src/quic/masque/masque_server_bin.cc" ] deps = [ ":masque_tools", @@ -907,8 +909,6 @@ source_set("quic_test_tools_core") { "src/quic/test_tools/qpack/qpack_encoder_peer.h", "src/quic/test_tools/qpack/qpack_encoder_test_utils.cc", "src/quic/test_tools/qpack/qpack_encoder_test_utils.h", - "src/quic/test_tools/qpack/qpack_header_table_peer.cc", - "src/quic/test_tools/qpack/qpack_header_table_peer.h", "src/quic/test_tools/qpack/qpack_offline_decoder.cc", "src/quic/test_tools/qpack/qpack_offline_decoder.h", "src/quic/test_tools/qpack/qpack_test_utils.cc", @@ -1109,12 +1109,14 @@ source_set("simple_quic_tools_core") { } source_set("quic_client_core") { + testonly = true sources = [ "src/quic/tools/quic_toy_client.cc", "src/quic/tools/quic_toy_client.h", ] deps = [ "//net", + "//net:quic_test_tools", "//net:simple_quic_tools", ] } @@ -1183,11 +1185,14 @@ if (!is_ios) { source_set("quiche_tests") { testonly = true sources = [ - "src/common/platform/api/quiche_text_utils_test.cc", "src/common/platform/api/quiche_time_utils_test.cc", + "src/common/quiche_circular_deque_test.cc", "src/common/quiche_data_writer_test.cc", "src/common/quiche_endian_test.cc", - "src/common/simple_linked_hash_map_test.cc", + "src/common/quiche_linked_hash_map_test.cc", + "src/common/quiche_text_utils_test.cc", + "src/http2/core/http2_priority_write_scheduler_test.cc", + "src/http2/core/priority_write_scheduler_test.cc", "src/http2/decoder/decode_buffer_test.cc", "src/http2/decoder/decode_http2_structures_test.cc", "src/http2/decoder/frame_decoder_state_test_util.cc", @@ -1246,7 +1251,6 @@ source_set("quiche_tests") { "src/http2/http2_structures_test.cc", "src/http2/http2_structures_test_util.cc", "src/http2/http2_structures_test_util.h", - "src/http2/platform/api/http2_string_utils_test.cc", "src/http2/platform/api/http2_test_helpers.h", "src/http2/test_tools/frame_parts.cc", "src/http2/test_tools/frame_parts.h", @@ -1344,7 +1348,7 @@ source_set("quiche_tests") { "src/quic/core/quic_arena_scoped_ptr_test.cc", "src/quic/core/quic_bandwidth_test.cc", "src/quic/core/quic_buffered_packet_store_test.cc", - "src/quic/core/quic_circular_deque_test.cc", + "src/quic/core/quic_chaos_protector_test.cc", "src/quic/core/quic_coalesced_packet_test.cc", "src/quic/core/quic_config_test.cc", "src/quic/core/quic_connection_id_manager_test.cc", @@ -1431,10 +1435,8 @@ source_set("quiche_tests") { "src/spdy/core/hpack/hpack_output_stream_test.cc", "src/spdy/core/hpack/hpack_round_trip_test.cc", "src/spdy/core/hpack/hpack_static_table_test.cc", - "src/spdy/core/http2_priority_write_scheduler_test.cc", "src/spdy/core/mock_spdy_framer_visitor.cc", "src/spdy/core/mock_spdy_framer_visitor.h", - "src/spdy/core/priority_write_scheduler_test.cc", "src/spdy/core/spdy_alt_svc_wire_format_test.cc", "src/spdy/core/spdy_frame_builder_test.cc", "src/spdy/core/spdy_frame_reader_test.cc", @@ -1450,8 +1452,6 @@ source_set("quiche_tests") { "src/spdy/core/spdy_simple_arena_test.cc", "src/spdy/core/spdy_test_utils.cc", "src/spdy/core/spdy_test_utils.h", - "src/spdy/platform/api/spdy_string_utils_test.cc", - "src/spdy/platform/api/spdy_test_helpers.h", ] deps = [ diff --git a/chromium/net/third_party/quiche/DIR_METADATA b/chromium/net/third_party/quiche/DIR_METADATA index 123352d107a..a745a9d91c3 100644 --- a/chromium/net/third_party/quiche/DIR_METADATA +++ b/chromium/net/third_party/quiche/DIR_METADATA @@ -1,10 +1,10 @@ # Metadata information for this directory. # # For more information on DIR_METADATA files, see: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md # # For the schema of this file, see Metadata message: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto monorail { component: "Internals>Network>QUIC" diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/quic_prefetch.h b/chromium/net/third_party/quiche/src/common/platform/api/quiche_prefetch.h index 49dbe4871e8..706a7090bea 100644 --- a/chromium/net/third_party/quiche/src/quic/platform/api/quic_prefetch.h +++ b/chromium/net/third_party/quiche/src/common/platform/api/quiche_prefetch.h @@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef QUICHE_QUIC_PLATFORM_API_QUIC_PREFETCH_H_ -#define QUICHE_QUIC_PLATFORM_API_QUIC_PREFETCH_H_ +#ifndef QUICHE_COMMON_PLATFORM_API_QUICHE_PREFETCH_H_ +#define QUICHE_COMMON_PLATFORM_API_QUICHE_PREFETCH_H_ -#include "net/quic/platform/impl/quic_prefetch_impl.h" +#include "quiche_platform_impl/quiche_prefetch_impl.h" -namespace quic { +namespace quiche { // Move data into the cache before it is read, or "prefetch" it. // @@ -30,10 +30,10 @@ namespace quic { // performance, so use them only when representative benchmarks show // an improvement. -inline void QuicPrefetchT0(const void* addr) { - return QuicPrefetchT0Impl(addr); +inline void QuichePrefetchT0(const void* addr) { + return QuichePrefetchT0Impl(addr); } -} // namespace quic +} // namespace quiche -#endif // QUICHE_QUIC_PLATFORM_API_QUIC_PREFETCH_H_ +#endif // QUICHE_COMMON_PLATFORM_API_QUICHE_PREFETCH_H_ diff --git a/chromium/net/third_party/quiche/src/common/platform/api/quiche_test.h b/chromium/net/third_party/quiche/src/common/platform/api/quiche_test.h index b5847529419..1af25df1ea5 100644 --- a/chromium/net/third_party/quiche/src/common/platform/api/quiche_test.h +++ b/chromium/net/third_party/quiche/src/common/platform/api/quiche_test.h @@ -12,4 +12,7 @@ using QuicheTest = quiche::test::QuicheTest; template <class T> using QuicheTestWithParam = quiche::test::QuicheTestWithParamImpl<T>; +#define EXPECT_QUICHE_DEBUG_DEATH(condition, message) \ + EXPECT_QUICHE_DEBUG_DEATH_IMPL(condition, message) + #endif // QUICHE_COMMON_PLATFORM_API_QUICHE_TEST_H_ diff --git a/chromium/net/third_party/quiche/src/common/platform/api/quiche_test_helpers.h b/chromium/net/third_party/quiche/src/common/platform/api/quiche_test_helpers.h new file mode 100644 index 00000000000..8e773a10a01 --- /dev/null +++ b/chromium/net/third_party/quiche/src/common/platform/api/quiche_test_helpers.h @@ -0,0 +1,8 @@ +#ifndef QUICHE_COMMON_PLATFORM_API_QUICHE_TEST_HELPERS_H_ +#define QUICHE_COMMON_PLATFORM_API_QUICHE_TEST_HELPERS_H_ + +#include "net/quiche/common/platform/impl/quiche_test_helpers_impl.h" + +#define EXPECT_QUICHE_BUG EXPECT_QUICHE_BUG_IMPL + +#endif // QUICHE_COMMON_PLATFORM_API_QUICHE_TEST_HELPERS_H_ diff --git a/chromium/net/third_party/quiche/src/common/platform/default/quiche_platform_impl/quiche_prefetch_impl.h b/chromium/net/third_party/quiche/src/common/platform/default/quiche_platform_impl/quiche_prefetch_impl.h new file mode 100644 index 00000000000..89454817d87 --- /dev/null +++ b/chromium/net/third_party/quiche/src/common/platform/default/quiche_platform_impl/quiche_prefetch_impl.h @@ -0,0 +1,28 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_COMMON_PLATFORM_DEFAULT_QUICHE_PLATFORM_IMPL_QUICHE_PREFETCH_IMPL_H_ +#define QUICHE_COMMON_PLATFORM_DEFAULT_QUICHE_PLATFORM_IMPL_QUICHE_PREFETCH_IMPL_H_ + +#if defined(_MSC_VER) +#include <intrin.h> +#endif + +namespace quiche { + +inline void QuichePrefetchT0Impl(const void* addr) { +#if !defined(DISABLE_BUILTIN_PREFETCH) +#if defined(__GNUC__) || (defined(_M_ARM64) && defined(__clang__)) + __builtin_prefetch(addr, 0, 3); +#elif defined(_MSC_VER) + _mm_prefetch(reinterpret_cast<const char*>(addr), _MM_HINT_T0); +#else + (void*)addr; +#endif +#endif // !defined(DISABLE_BUILTIN_PREFETCH) +} + +} // namespace quiche + +#endif // QUICHE_COMMON_PLATFORM_DEFAULT_QUICHE_PLATFORM_IMPL_QUICHE_PREFETCH_IMPL_H_ diff --git a/chromium/net/third_party/quiche/src/common/platform/default/quiche_platform_impl/quiche_sleep_impl.h b/chromium/net/third_party/quiche/src/common/platform/default/quiche_platform_impl/quiche_sleep_impl.h new file mode 100644 index 00000000000..125af37d877 --- /dev/null +++ b/chromium/net/third_party/quiche/src/common/platform/default/quiche_platform_impl/quiche_sleep_impl.h @@ -0,0 +1,22 @@ +#ifndef QUICHE_COMMON_PLATFORM_DEFAULT_QUICHE_PLATFORM_IMPL_QUICHE_SLEEP_IMPL_H_ +#define QUICHE_COMMON_PLATFORM_DEFAULT_QUICHE_PLATFORM_IMPL_QUICHE_SLEEP_IMPL_H_ + +#include "quic/core/quic_time.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Weverything" + +#include "absl/time/clock.h" +#include "absl/time/time.h" + +#pragma clang diagnostic pop + +namespace quic { + +inline void QuicSleepImpl(QuicTime::Delta duration) { + absl::SleepFor(absl::Microseconds(duration.ToMicroseconds())); +} + +} // namespace quic + +#endif // QUICHE_COMMON_PLATFORM_DEFAULT_QUICHE_PLATFORM_IMPL_QUICHE_SLEEP_IMPL_H_ diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_circular_deque.h b/chromium/net/third_party/quiche/src/common/quiche_circular_deque.h index 44637abcbd6..42b22327f29 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_circular_deque.h +++ b/chromium/net/third_party/quiche/src/common/quiche_circular_deque.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef QUICHE_QUIC_CORE_QUIC_CIRCULAR_DEQUE_H_ -#define QUICHE_QUIC_CORE_QUIC_CIRCULAR_DEQUE_H_ +#ifndef QUICHE_COMMON_QUICHE_CIRCULAR_DEQUE_H_ +#define QUICHE_COMMON_QUICHE_CIRCULAR_DEQUE_H_ #include <algorithm> #include <cstddef> @@ -13,16 +13,16 @@ #include <ostream> #include <type_traits> -#include "quic/platform/api/quic_export.h" -#include "quic/platform/api/quic_logging.h" +#include "common/platform/api/quiche_export.h" +#include "common/platform/api/quiche_logging.h" -namespace quic { +namespace quiche { -// QuicCircularDeque is a STL-style container that is similar to std deque in +// QuicheCircularDeque is a STL-style container that is similar to std::deque in // API and std::vector in capacity management. The goal is to optimize a common // QUIC use case where we keep adding new elements to the end and removing old // elements from the beginning, under such scenarios, if the container's size() -// remain relatively stable, QuicCircularDeque requires little to no memory +// remain relatively stable, QuicheCircularDeque requires little to no memory // allocations or deallocations. // // The implementation, as the name suggests, uses a flat circular buffer to hold @@ -40,12 +40,12 @@ namespace quic { template <typename T, size_t MinCapacityIncrement = 3, typename Allocator = std::allocator<T>> -class QUIC_NO_EXPORT QuicCircularDeque { +class QUICHE_NO_EXPORT QuicheCircularDeque { using AllocatorTraits = std::allocator_traits<Allocator>; // Pointee is either T or const T. template <typename Pointee> - class QUIC_NO_EXPORT basic_iterator { + class QUICHE_NO_EXPORT basic_iterator { using size_type = typename AllocatorTraits::size_type; public: @@ -159,7 +159,7 @@ class QUIC_NO_EXPORT QuicCircularDeque { } private: - basic_iterator(const QuicCircularDeque* deque, size_type index) + basic_iterator(const QuicheCircularDeque* deque, size_type index) : deque_(deque), index_(index) {} void Increment() { @@ -191,8 +191,8 @@ class QUIC_NO_EXPORT QuicCircularDeque { return index_ + deque_->data_capacity() - deque_->begin_; } - friend class QuicCircularDeque; - const QuicCircularDeque* deque_ = nullptr; + friend class QuicheCircularDeque; + const QuicheCircularDeque* deque_ = nullptr; size_type index_ = 0; }; @@ -210,19 +210,19 @@ class QUIC_NO_EXPORT QuicCircularDeque { using reverse_iterator = std::reverse_iterator<iterator>; using const_reverse_iterator = std::reverse_iterator<const_iterator>; - QuicCircularDeque() : QuicCircularDeque(allocator_type()) {} - explicit QuicCircularDeque(const allocator_type& alloc) + QuicheCircularDeque() : QuicheCircularDeque(allocator_type()) {} + explicit QuicheCircularDeque(const allocator_type& alloc) : allocator_and_data_(alloc) {} - QuicCircularDeque(size_type count, - const T& value, - const Allocator& alloc = allocator_type()) + QuicheCircularDeque(size_type count, + const T& value, + const Allocator& alloc = allocator_type()) : allocator_and_data_(alloc) { resize(count, value); } - explicit QuicCircularDeque(size_type count, - const Allocator& alloc = allocator_type()) + explicit QuicheCircularDeque(size_type count, + const Allocator& alloc = allocator_type()) : allocator_and_data_(alloc) { resize(count); } @@ -232,25 +232,26 @@ class QUIC_NO_EXPORT QuicCircularDeque { typename = std::enable_if_t<std::is_base_of< std::input_iterator_tag, typename std::iterator_traits<InputIt>::iterator_category>::value>> - QuicCircularDeque(InputIt first, - InputIt last, - const Allocator& alloc = allocator_type()) + QuicheCircularDeque(InputIt first, + InputIt last, + const Allocator& alloc = allocator_type()) : allocator_and_data_(alloc) { AssignRange(first, last); } - QuicCircularDeque(const QuicCircularDeque& other) - : QuicCircularDeque( + QuicheCircularDeque(const QuicheCircularDeque& other) + : QuicheCircularDeque( other, AllocatorTraits::select_on_container_copy_construction( other.allocator_and_data_.allocator())) {} - QuicCircularDeque(const QuicCircularDeque& other, const allocator_type& alloc) + QuicheCircularDeque(const QuicheCircularDeque& other, + const allocator_type& alloc) : allocator_and_data_(alloc) { assign(other.begin(), other.end()); } - QuicCircularDeque(QuicCircularDeque&& other) + QuicheCircularDeque(QuicheCircularDeque&& other) : begin_(other.begin_), end_(other.end_), allocator_and_data_(std::move(other.allocator_and_data_)) { @@ -259,16 +260,16 @@ class QUIC_NO_EXPORT QuicCircularDeque { other.allocator_and_data_.data_capacity = 0; } - QuicCircularDeque(QuicCircularDeque&& other, const allocator_type& alloc) + QuicheCircularDeque(QuicheCircularDeque&& other, const allocator_type& alloc) : allocator_and_data_(alloc) { MoveRetainAllocator(std::move(other)); } - QuicCircularDeque(std::initializer_list<T> init, - const allocator_type& alloc = allocator_type()) - : QuicCircularDeque(init.begin(), init.end(), alloc) {} + QuicheCircularDeque(std::initializer_list<T> init, + const allocator_type& alloc = allocator_type()) + : QuicheCircularDeque(init.begin(), init.end(), alloc) {} - QuicCircularDeque& operator=(const QuicCircularDeque& other) { + QuicheCircularDeque& operator=(const QuicheCircularDeque& other) { if (this == &other) { return *this; } @@ -286,21 +287,21 @@ class QUIC_NO_EXPORT QuicCircularDeque { return *this; } - QuicCircularDeque& operator=(QuicCircularDeque&& other) { + QuicheCircularDeque& operator=(QuicheCircularDeque&& other) { if (this == &other) { return *this; } if (AllocatorTraits::propagate_on_container_move_assignment::value) { // Take over the storage of "other", along with its allocator. - this->~QuicCircularDeque(); - new (this) QuicCircularDeque(std::move(other)); + this->~QuicheCircularDeque(); + new (this) QuicheCircularDeque(std::move(other)); } else { MoveRetainAllocator(std::move(other)); } return *this; } - ~QuicCircularDeque() { DestroyAndDeallocateAll(); } + ~QuicheCircularDeque() { DestroyAndDeallocateAll(); } void assign(size_type count, const T& value) { ClearRetainCapacity(); @@ -333,7 +334,7 @@ class QUIC_NO_EXPORT QuicCircularDeque { } const_reference at(size_type pos) const { - return const_cast<QuicCircularDeque*>(this)->at(pos); + return const_cast<QuicheCircularDeque*>(this)->at(pos); } reference operator[](size_type pos) { return at(pos); } @@ -346,7 +347,7 @@ class QUIC_NO_EXPORT QuicCircularDeque { } const_reference front() const { - return const_cast<QuicCircularDeque*>(this)->front(); + return const_cast<QuicheCircularDeque*>(this)->front(); } reference back() { @@ -355,7 +356,7 @@ class QUIC_NO_EXPORT QuicCircularDeque { } const_reference back() const { - return const_cast<QuicCircularDeque*>(this)->back(); + return const_cast<QuicheCircularDeque*>(this)->back(); } iterator begin() { return iterator(this, begin_); } @@ -460,7 +461,7 @@ class QUIC_NO_EXPORT QuicCircularDeque { return num_elements_to_pop; } - void swap(QuicCircularDeque& other) { + void swap(QuicheCircularDeque& other) { using std::swap; swap(begin_, other.begin_); swap(end_, other.end_); @@ -479,7 +480,7 @@ class QUIC_NO_EXPORT QuicCircularDeque { } } - friend void swap(QuicCircularDeque& lhs, QuicCircularDeque& rhs) { + friend void swap(QuicheCircularDeque& lhs, QuicheCircularDeque& rhs) { lhs.swap(rhs); } @@ -487,18 +488,19 @@ class QUIC_NO_EXPORT QuicCircularDeque { return allocator_and_data_.allocator(); } - friend bool operator==(const QuicCircularDeque& lhs, - const QuicCircularDeque& rhs) { + friend bool operator==(const QuicheCircularDeque& lhs, + const QuicheCircularDeque& rhs) { return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); } - friend bool operator!=(const QuicCircularDeque& lhs, - const QuicCircularDeque& rhs) { + friend bool operator!=(const QuicheCircularDeque& lhs, + const QuicheCircularDeque& rhs) { return !(lhs == rhs); } - friend QUIC_NO_EXPORT std::ostream& operator<<(std::ostream& os, - const QuicCircularDeque& dq) { + friend QUICHE_NO_EXPORT std::ostream& operator<<( + std::ostream& os, + const QuicheCircularDeque& dq) { os << "{"; for (size_type pos = 0; pos != dq.size(); ++pos) { if (pos != 0) { @@ -511,7 +513,7 @@ class QUIC_NO_EXPORT QuicCircularDeque { } private: - void MoveRetainAllocator(QuicCircularDeque&& other) { + void MoveRetainAllocator(QuicheCircularDeque&& other) { if (get_allocator() == other.get_allocator()) { // Take over the storage of "other", with which we share an allocator. DestroyAndDeallocateAll(); @@ -752,6 +754,6 @@ class QUIC_NO_EXPORT QuicCircularDeque { AllocatorAndData allocator_and_data_; }; -} // namespace quic +} // namespace quiche -#endif // QUICHE_QUIC_CORE_QUIC_CIRCULAR_DEQUE_H_ +#endif // QUICHE_COMMON_QUICHE_CIRCULAR_DEQUE_H_ diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_circular_deque_test.cc b/chromium/net/third_party/quiche/src/common/quiche_circular_deque_test.cc index 25aa78e709a..c15d904b850 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_circular_deque_test.cc +++ b/chromium/net/third_party/quiche/src/common/quiche_circular_deque_test.cc @@ -2,19 +2,20 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "quic/core/quic_circular_deque.h" +#include "common/quiche_circular_deque.h" #include <cstddef> #include <cstdint> +#include <list> #include <memory> #include <type_traits> -#include "quic/platform/api/quic_logging.h" -#include "quic/platform/api/quic_test.h" +#include "common/platform/api/quiche_logging.h" +#include "common/platform/api/quiche_test.h" using testing::ElementsAre; -namespace quic { +namespace quiche { namespace test { namespace { @@ -106,10 +107,10 @@ void ShiftLeft(Deque* dq, bool emplace) { } } -class QuicCircularDequeTest : public QuicTest {}; +class QuicheCircularDequeTest : public QuicheTest {}; -TEST_F(QuicCircularDequeTest, Empty) { - QuicCircularDeque<int> dq; +TEST_F(QuicheCircularDequeTest, Empty) { + QuicheCircularDeque<int> dq; EXPECT_TRUE(dq.empty()); EXPECT_EQ(0u, dq.size()); dq.clear(); @@ -122,68 +123,69 @@ TEST_F(QuicCircularDequeTest, Empty) { EXPECT_TRUE(dq.empty()); EXPECT_EQ(0u, dq.size()); - EXPECT_QUIC_DEBUG_DEATH(dq.front(), ""); - EXPECT_QUIC_DEBUG_DEATH(dq.back(), ""); - EXPECT_QUIC_DEBUG_DEATH(dq.at(0), ""); - EXPECT_QUIC_DEBUG_DEATH(dq[0], ""); + EXPECT_QUICHE_DEBUG_DEATH(dq.front(), ""); + EXPECT_QUICHE_DEBUG_DEATH(dq.back(), ""); + EXPECT_QUICHE_DEBUG_DEATH(dq.at(0), ""); + EXPECT_QUICHE_DEBUG_DEATH(dq[0], ""); } -TEST_F(QuicCircularDequeTest, Constructor) { - QuicCircularDeque<int> dq; +TEST_F(QuicheCircularDequeTest, Constructor) { + QuicheCircularDeque<int> dq; EXPECT_TRUE(dq.empty()); std::allocator<int> alloc; - QuicCircularDeque<int> dq1(alloc); + QuicheCircularDeque<int> dq1(alloc); EXPECT_TRUE(dq1.empty()); - QuicCircularDeque<int> dq2(8, 100, alloc); + QuicheCircularDeque<int> dq2(8, 100, alloc); EXPECT_THAT(dq2, ElementsAre(100, 100, 100, 100, 100, 100, 100, 100)); - QuicCircularDeque<int> dq3(5, alloc); + QuicheCircularDeque<int> dq3(5, alloc); EXPECT_THAT(dq3, ElementsAre(0, 0, 0, 0, 0)); - QuicCircularDeque<int> dq4_rand_iter(dq3.begin(), dq3.end(), alloc); + QuicheCircularDeque<int> dq4_rand_iter(dq3.begin(), dq3.end(), alloc); EXPECT_THAT(dq4_rand_iter, ElementsAre(0, 0, 0, 0, 0)); EXPECT_EQ(dq4_rand_iter, dq3); std::list<int> dq4_src = {4, 4, 4, 4}; - QuicCircularDeque<int> dq4_bidi_iter(dq4_src.begin(), dq4_src.end()); + QuicheCircularDeque<int> dq4_bidi_iter(dq4_src.begin(), dq4_src.end()); EXPECT_THAT(dq4_bidi_iter, ElementsAre(4, 4, 4, 4)); - QuicCircularDeque<int> dq5(dq4_bidi_iter); + QuicheCircularDeque<int> dq5(dq4_bidi_iter); EXPECT_THAT(dq5, ElementsAre(4, 4, 4, 4)); EXPECT_EQ(dq5, dq4_bidi_iter); - QuicCircularDeque<int> dq6(dq5, alloc); + QuicheCircularDeque<int> dq6(dq5, alloc); EXPECT_THAT(dq6, ElementsAre(4, 4, 4, 4)); EXPECT_EQ(dq6, dq5); - QuicCircularDeque<int> dq7(std::move(*&dq6)); + QuicheCircularDeque<int> dq7(std::move(*&dq6)); EXPECT_THAT(dq7, ElementsAre(4, 4, 4, 4)); EXPECT_TRUE(dq6.empty()); - QuicCircularDeque<int> dq8_equal_allocator(std::move(*&dq7), alloc); + QuicheCircularDeque<int> dq8_equal_allocator(std::move(*&dq7), alloc); EXPECT_THAT(dq8_equal_allocator, ElementsAre(4, 4, 4, 4)); EXPECT_TRUE(dq7.empty()); - QuicCircularDeque<int, 3, CountingAllocator<int>> dq8_temp = {5, 6, 7, 8, 9}; - QuicCircularDeque<int, 3, CountingAllocator<int>> dq8_unequal_allocator( + QuicheCircularDeque<int, 3, CountingAllocator<int>> dq8_temp = {5, 6, 7, 8, + 9}; + QuicheCircularDeque<int, 3, CountingAllocator<int>> dq8_unequal_allocator( std::move(*&dq8_temp), CountingAllocator<int>()); EXPECT_THAT(dq8_unequal_allocator, ElementsAre(5, 6, 7, 8, 9)); EXPECT_TRUE(dq8_temp.empty()); - QuicCircularDeque<int> dq9({3, 4, 5, 6, 7}, alloc); + QuicheCircularDeque<int> dq9({3, 4, 5, 6, 7}, alloc); EXPECT_THAT(dq9, ElementsAre(3, 4, 5, 6, 7)); } -TEST_F(QuicCircularDequeTest, Assign) { +TEST_F(QuicheCircularDequeTest, Assign) { // assign() - QuicCircularDeque<int, 3, CountingAllocator<int>> dq; + QuicheCircularDeque<int, 3, CountingAllocator<int>> dq; dq.assign(7, 1); EXPECT_THAT(dq, ElementsAre(1, 1, 1, 1, 1, 1, 1)); EXPECT_EQ(1u, dq.get_allocator().allocate_count()); - QuicCircularDeque<int, 3, CountingAllocator<int>> dq2; + QuicheCircularDeque<int, 3, CountingAllocator<int>> dq2; dq2.assign(dq.begin(), dq.end()); EXPECT_THAT(dq2, ElementsAre(1, 1, 1, 1, 1, 1, 1)); EXPECT_EQ(1u, dq2.get_allocator().allocate_count()); @@ -194,7 +196,7 @@ TEST_F(QuicCircularDequeTest, Assign) { // Assign from a non random access iterator. std::list<int> dq3_src = {3, 3, 3, 3, 3}; - QuicCircularDeque<int, 3, CountingAllocator<int>> dq3; + QuicheCircularDeque<int, 3, CountingAllocator<int>> dq3; dq3.assign(dq3_src.begin(), dq3_src.end()); EXPECT_THAT(dq3, ElementsAre(3, 3, 3, 3, 3)); EXPECT_LT(1u, dq3.get_allocator().allocate_count()); @@ -203,7 +205,7 @@ TEST_F(QuicCircularDequeTest, Assign) { dq3 = *&dq3; EXPECT_THAT(dq3, ElementsAre(3, 3, 3, 3, 3)); - QuicCircularDeque< + QuicheCircularDeque< int, 3, ConfigurableAllocator<int, /*propagate_on_copy_assignment=*/std::true_type, @@ -215,7 +217,7 @@ TEST_F(QuicCircularDequeTest, Assign) { dq5 = dq4; EXPECT_THAT(dq5, ElementsAre(3, 3, 3, 3, 3)); - QuicCircularDeque< + QuicheCircularDeque< int, 3, ConfigurableAllocator<int, /*propagate_on_copy_assignment=*/std::false_type, @@ -238,7 +240,7 @@ TEST_F(QuicCircularDequeTest, Assign) { EXPECT_THAT(dq8, ElementsAre(3, 3, 3, 3, 3)); EXPECT_TRUE(dq3.empty()); - QuicCircularDeque< + QuicheCircularDeque< int, 3, ConfigurableAllocator<int, /*propagate_on_copy_assignment=*/std::true_type, @@ -252,7 +254,7 @@ TEST_F(QuicCircularDequeTest, Assign) { EXPECT_THAT(dq9, ElementsAre(2, 2, 2, 2, 2, 2)); EXPECT_TRUE(dq10.empty()); - QuicCircularDeque< + QuicheCircularDeque< int, 3, ConfigurableAllocator<int, /*propagate_on_copy_assignment=*/std::true_type, @@ -267,13 +269,13 @@ TEST_F(QuicCircularDequeTest, Assign) { EXPECT_TRUE(dq12.empty()); } -TEST_F(QuicCircularDequeTest, Access) { +TEST_F(QuicheCircularDequeTest, Access) { // at() // operator[] // front() // back() - QuicCircularDeque<int, 3, CountingAllocator<int>> dq; + QuicheCircularDeque<int, 3, CountingAllocator<int>> dq; dq.push_back(10); EXPECT_EQ(dq.front(), 10); EXPECT_EQ(dq.back(), 10); @@ -369,15 +371,15 @@ TEST_F(QuicCircularDequeTest, Access) { EXPECT_EQ(1u, dq.get_allocator().allocate_count()); } -TEST_F(QuicCircularDequeTest, Iterate) { - QuicCircularDeque<int> dq; +TEST_F(QuicheCircularDequeTest, Iterate) { + QuicheCircularDeque<int> dq; EXPECT_EQ(dq.begin(), dq.end()); EXPECT_EQ(dq.cbegin(), dq.cend()); EXPECT_EQ(dq.rbegin(), dq.rend()); EXPECT_EQ(dq.crbegin(), dq.crend()); dq.emplace_back(2); - QuicCircularDeque<int>::const_iterator citer = dq.begin(); + QuicheCircularDeque<int>::const_iterator citer = dq.begin(); EXPECT_NE(citer, dq.end()); EXPECT_EQ(*citer, 2); ++citer; @@ -389,7 +391,7 @@ TEST_F(QuicCircularDequeTest, Iterate) { EXPECT_EQ(*dq.crbegin(), 2); dq.emplace_front(1); - QuicCircularDeque<int>::const_reverse_iterator criter = dq.rbegin(); + QuicheCircularDeque<int>::const_reverse_iterator criter = dq.rbegin(); EXPECT_NE(criter, dq.rend()); EXPECT_EQ(*criter, 2); ++criter; @@ -407,42 +409,43 @@ TEST_F(QuicCircularDequeTest, Iterate) { // Forward iterate. int expected_value = 1; - for (QuicCircularDeque<int>::iterator it = dq.begin(); it != dq.end(); ++it) { + for (QuicheCircularDeque<int>::iterator it = dq.begin(); it != dq.end(); + ++it) { EXPECT_EQ(expected_value++, *it); } expected_value = 1; - for (QuicCircularDeque<int>::const_iterator it = dq.cbegin(); it != dq.cend(); - ++it) { + for (QuicheCircularDeque<int>::const_iterator it = dq.cbegin(); + it != dq.cend(); ++it) { EXPECT_EQ(expected_value++, *it); } // Reverse iterate. expected_value = 3; - for (QuicCircularDeque<int>::reverse_iterator it = dq.rbegin(); + for (QuicheCircularDeque<int>::reverse_iterator it = dq.rbegin(); it != dq.rend(); ++it) { EXPECT_EQ(expected_value--, *it); } expected_value = 3; - for (QuicCircularDeque<int>::const_reverse_iterator it = dq.crbegin(); + for (QuicheCircularDeque<int>::const_reverse_iterator it = dq.crbegin(); it != dq.crend(); ++it) { EXPECT_EQ(expected_value--, *it); } } -TEST_F(QuicCircularDequeTest, Iterator) { +TEST_F(QuicheCircularDequeTest, Iterator) { // Default constructed iterators of the same type compare equal. - EXPECT_EQ(QuicCircularDeque<int>::iterator(), - QuicCircularDeque<int>::iterator()); - EXPECT_EQ(QuicCircularDeque<int>::const_iterator(), - QuicCircularDeque<int>::const_iterator()); - EXPECT_EQ(QuicCircularDeque<int>::reverse_iterator(), - QuicCircularDeque<int>::reverse_iterator()); - EXPECT_EQ(QuicCircularDeque<int>::const_reverse_iterator(), - QuicCircularDeque<int>::const_reverse_iterator()); - - QuicCircularDeque<QuicCircularDeque<int>, 3> dqdq = { + EXPECT_EQ(QuicheCircularDeque<int>::iterator(), + QuicheCircularDeque<int>::iterator()); + EXPECT_EQ(QuicheCircularDeque<int>::const_iterator(), + QuicheCircularDeque<int>::const_iterator()); + EXPECT_EQ(QuicheCircularDeque<int>::reverse_iterator(), + QuicheCircularDeque<int>::reverse_iterator()); + EXPECT_EQ(QuicheCircularDeque<int>::const_reverse_iterator(), + QuicheCircularDeque<int>::const_reverse_iterator()); + + QuicheCircularDeque<QuicheCircularDeque<int>, 3> dqdq = { {1, 2}, {10, 20, 30}, {100, 200, 300, 400}}; // iter points to {1, 2} @@ -494,8 +497,8 @@ TEST_F(QuicCircularDequeTest, Iterator) { } } -TEST_F(QuicCircularDequeTest, Resize) { - QuicCircularDeque<int, 3, CountingAllocator<int>> dq; +TEST_F(QuicheCircularDequeTest, Resize) { + QuicheCircularDeque<int, 3, CountingAllocator<int>> dq; dq.resize(8); EXPECT_THAT(dq, ElementsAre(0, 0, 0, 0, 0, 0, 0, 0)); EXPECT_EQ(1u, dq.get_allocator().allocate_count()); @@ -503,7 +506,7 @@ TEST_F(QuicCircularDequeTest, Resize) { dq.resize(10, 5); EXPECT_THAT(dq, ElementsAre(0, 0, 0, 0, 0, 0, 0, 0, 5, 5)); - QuicCircularDeque<int, 3, CountingAllocator<int>> dq2 = dq; + QuicheCircularDeque<int, 3, CountingAllocator<int>> dq2 = dq; for (size_t new_size = dq.size(); new_size != 0; --new_size) { dq.resize(new_size); @@ -575,7 +578,7 @@ class Foo { }; } // namespace -TEST_F(QuicCircularDequeTest, RelocateNonTriviallyCopyable) { +TEST_F(QuicheCircularDequeTest, RelocateNonTriviallyCopyable) { // When relocating non-trivially-copyable objects: // - Move constructor is preferred, if available. // - Copy constructor is used otherwise. @@ -585,8 +588,8 @@ TEST_F(QuicCircularDequeTest, RelocateNonTriviallyCopyable) { using MoveConstructible = std::unique_ptr<Foo>; ASSERT_FALSE(std::is_trivially_copyable<MoveConstructible>::value); ASSERT_TRUE(std::is_move_constructible<MoveConstructible>::value); - QuicCircularDeque<MoveConstructible, 3, - CountingAllocator<MoveConstructible>> + QuicheCircularDeque<MoveConstructible, 3, + CountingAllocator<MoveConstructible>> dq1; dq1.resize(3); EXPECT_EQ(dq1.size(), dq1.capacity()); @@ -606,8 +609,8 @@ TEST_F(QuicCircularDequeTest, RelocateNonTriviallyCopyable) { using NonMoveConstructible = Foo; ASSERT_FALSE(std::is_trivially_copyable<NonMoveConstructible>::value); ASSERT_FALSE(std::is_move_constructible<NonMoveConstructible>::value); - QuicCircularDeque<NonMoveConstructible, 3, - CountingAllocator<NonMoveConstructible>> + QuicheCircularDeque<NonMoveConstructible, 3, + CountingAllocator<NonMoveConstructible>> dq2; dq2.resize(3); EXPECT_EQ(dq2.size(), dq2.capacity()); @@ -623,49 +626,49 @@ TEST_F(QuicCircularDequeTest, RelocateNonTriviallyCopyable) { } } -TEST_F(QuicCircularDequeTest, PushPop) { +TEST_F(QuicheCircularDequeTest, PushPop) { // (push|pop|emplace)_(back|front) { - QuicCircularDeque<Foo, 4, CountingAllocator<Foo>> dq(4); + QuicheCircularDeque<Foo, 4, CountingAllocator<Foo>> dq(4); for (size_t i = 0; i < dq.size(); ++i) { dq[i].Set(i + 1); } - QUIC_LOG(INFO) << "dq initialized to " << dq; + QUICHE_LOG(INFO) << "dq initialized to " << dq; EXPECT_THAT(dq, ElementsAre(Foo(1), Foo(2), Foo(3), Foo(4))); ShiftLeft(&dq, false); - QUIC_LOG(INFO) << "shift left once : " << dq; + QUICHE_LOG(INFO) << "shift left once : " << dq; EXPECT_THAT(dq, ElementsAre(Foo(2), Foo(3), Foo(4), Foo(1))); ShiftLeft(&dq, true); - QUIC_LOG(INFO) << "shift left twice: " << dq; + QUICHE_LOG(INFO) << "shift left twice: " << dq; EXPECT_THAT(dq, ElementsAre(Foo(3), Foo(4), Foo(1), Foo(2))); ASSERT_GT(&dq.front(), &dq.back()); // dq destructs with wrapped data. } { - QuicCircularDeque<Foo, 4, CountingAllocator<Foo>> dq1(4); + QuicheCircularDeque<Foo, 4, CountingAllocator<Foo>> dq1(4); for (size_t i = 0; i < dq1.size(); ++i) { dq1[i].Set(i + 1); } - QUIC_LOG(INFO) << "dq1 initialized to " << dq1; + QUICHE_LOG(INFO) << "dq1 initialized to " << dq1; EXPECT_THAT(dq1, ElementsAre(Foo(1), Foo(2), Foo(3), Foo(4))); ShiftRight(&dq1, false); - QUIC_LOG(INFO) << "shift right once : " << dq1; + QUICHE_LOG(INFO) << "shift right once : " << dq1; EXPECT_THAT(dq1, ElementsAre(Foo(4), Foo(1), Foo(2), Foo(3))); ShiftRight(&dq1, true); - QUIC_LOG(INFO) << "shift right twice: " << dq1; + QUICHE_LOG(INFO) << "shift right twice: " << dq1; EXPECT_THAT(dq1, ElementsAre(Foo(3), Foo(4), Foo(1), Foo(2))); ASSERT_GT(&dq1.front(), &dq1.back()); // dq1 destructs with wrapped data. } { // Pop n elements from front. - QuicCircularDeque<Foo, 4, CountingAllocator<Foo>> dq2(5); + QuicheCircularDeque<Foo, 4, CountingAllocator<Foo>> dq2(5); for (size_t i = 0; i < dq2.size(); ++i) { dq2[i].Set(i + 1); } @@ -679,7 +682,7 @@ TEST_F(QuicCircularDequeTest, PushPop) { } { // Pop n elements from back. - QuicCircularDeque<Foo, 4, CountingAllocator<Foo>> dq3(6); + QuicheCircularDeque<Foo, 4, CountingAllocator<Foo>> dq3(6); for (size_t i = 0; i < dq3.size(); ++i) { dq3[i].Set(i + 1); } @@ -700,11 +703,11 @@ TEST_F(QuicCircularDequeTest, PushPop) { } } -TEST_F(QuicCircularDequeTest, Allocation) { +TEST_F(QuicheCircularDequeTest, Allocation) { CountingAllocator<int> alloc; { - QuicCircularDeque<int, 3, CountingAllocator<int>> dq(alloc); + QuicheCircularDeque<int, 3, CountingAllocator<int>> dq(alloc); EXPECT_EQ(alloc, dq.get_allocator()); EXPECT_EQ(0u, dq.size()); EXPECT_EQ(0u, dq.capacity()); @@ -734,13 +737,13 @@ TEST_F(QuicCircularDequeTest, Allocation) { } // namespace } // namespace test -} // namespace quic +} // namespace quiche -// Use a non-quic namespace to make sure swap can be used via ADL. +// Use a non-quiche namespace to make sure swap can be used via ADL. namespace { template <typename T> -using SwappableAllocator = quic::test::ConfigurableAllocator< +using SwappableAllocator = quiche::test::ConfigurableAllocator< T, /*propagate_on_copy_assignment=*/std::true_type, /*propagate_on_move_assignment=*/std::true_type, @@ -748,7 +751,7 @@ using SwappableAllocator = quic::test::ConfigurableAllocator< /*equality_result=*/true>; template <typename T> -using UnswappableEqualAllocator = quic::test::ConfigurableAllocator< +using UnswappableEqualAllocator = quiche::test::ConfigurableAllocator< T, /*propagate_on_copy_assignment=*/std::true_type, /*propagate_on_move_assignment=*/std::true_type, @@ -756,19 +759,19 @@ using UnswappableEqualAllocator = quic::test::ConfigurableAllocator< /*equality_result=*/true>; template <typename T> -using UnswappableUnequalAllocator = quic::test::ConfigurableAllocator< +using UnswappableUnequalAllocator = quiche::test::ConfigurableAllocator< T, /*propagate_on_copy_assignment=*/std::true_type, /*propagate_on_move_assignment=*/std::true_type, /*propagate_on_swap=*/std::false_type, /*equality_result=*/false>; -using quic::test::QuicCircularDequeTest; +using quiche::test::QuicheCircularDequeTest; -TEST_F(QuicCircularDequeTest, Swap) { +TEST_F(QuicheCircularDequeTest, Swap) { using std::swap; - quic::QuicCircularDeque<int64_t, 3, SwappableAllocator<int64_t>> dq1, dq2; + quiche::QuicheCircularDeque<int64_t, 3, SwappableAllocator<int64_t>> dq1, dq2; dq1.push_back(10); dq1.push_back(11); dq2.push_back(20); @@ -776,14 +779,16 @@ TEST_F(QuicCircularDequeTest, Swap) { EXPECT_THAT(dq1, ElementsAre(20)); EXPECT_THAT(dq2, ElementsAre(10, 11)); - quic::QuicCircularDeque<char, 3, UnswappableEqualAllocator<char>> dq3, dq4; + quiche::QuicheCircularDeque<char, 3, UnswappableEqualAllocator<char>> dq3, + dq4; dq3 = {1, 2, 3, 4, 5}; dq4 = {6, 7, 8, 9, 0}; swap(dq3, dq4); EXPECT_THAT(dq3, ElementsAre(6, 7, 8, 9, 0)); EXPECT_THAT(dq4, ElementsAre(1, 2, 3, 4, 5)); - quic::QuicCircularDeque<int, 3, UnswappableUnequalAllocator<int>> dq5, dq6; + quiche::QuicheCircularDeque<int, 3, UnswappableUnequalAllocator<int>> dq5, + dq6; dq6.push_front(4); // Using UnswappableUnequalAllocator is ok as long as swap is not called. @@ -791,6 +796,6 @@ TEST_F(QuicCircularDequeTest, Swap) { EXPECT_THAT(dq5, ElementsAre(4)); // Undefined behavior to swap between two containers with unequal allocators. - EXPECT_QUIC_DEBUG_DEATH(swap(dq5, dq6), "Undefined swap behavior"); + EXPECT_QUICHE_DEBUG_DEATH(swap(dq5, dq6), "Undefined swap behavior"); } } // namespace diff --git a/chromium/net/third_party/quiche/src/common/quiche_data_reader.cc b/chromium/net/third_party/quiche/src/common/quiche_data_reader.cc index c196b42d2bb..f20c752bcce 100644 --- a/chromium/net/third_party/quiche/src/common/quiche_data_reader.cc +++ b/chromium/net/third_party/quiche/src/common/quiche_data_reader.cc @@ -10,7 +10,6 @@ #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" #include "common/platform/api/quiche_logging.h" -#include "common/platform/api/quiche_text_utils.h" #include "common/quiche_endian.h" namespace quiche { diff --git a/chromium/net/third_party/quiche/src/common/simple_linked_hash_map.h b/chromium/net/third_party/quiche/src/common/quiche_linked_hash_map.h index 17542a1dae6..a52863e40f5 100644 --- a/chromium/net/third_party/quiche/src/common/simple_linked_hash_map.h +++ b/chromium/net/third_party/quiche/src/common/quiche_linked_hash_map.h @@ -13,8 +13,8 @@ // mutations, except for an iterator pointing to an element that was just // deleted. -#ifndef QUICHE_COMMON_SIMPLE_LINKED_HASH_MAP_H_ -#define QUICHE_COMMON_SIMPLE_LINKED_HASH_MAP_H_ +#ifndef QUICHE_COMMON_QUICHE_LINKED_HASH_MAP_H_ +#define QUICHE_COMMON_QUICHE_LINKED_HASH_MAP_H_ #include <functional> #include <list> @@ -38,7 +38,7 @@ template <class Key, class Value, class Hash = std::hash<Key>, class Eq = std::equal_to<Key>> -class SimpleLinkedHashMap { +class QuicheLinkedHashMap { private: typedef std::list<std::pair<Key, Value>> ListType; typedef absl::node_hash_map<Key, typename ListType::iterator, Hash, Eq> @@ -53,13 +53,13 @@ class SimpleLinkedHashMap { typedef typename ListType::value_type value_type; typedef typename ListType::size_type size_type; - SimpleLinkedHashMap() = default; - explicit SimpleLinkedHashMap(size_type bucket_count) : map_(bucket_count) {} + QuicheLinkedHashMap() = default; + explicit QuicheLinkedHashMap(size_type bucket_count) : map_(bucket_count) {} - SimpleLinkedHashMap(const SimpleLinkedHashMap& other) = delete; - SimpleLinkedHashMap& operator=(const SimpleLinkedHashMap& other) = delete; - SimpleLinkedHashMap(SimpleLinkedHashMap&& other) = default; - SimpleLinkedHashMap& operator=(SimpleLinkedHashMap&& other) = default; + QuicheLinkedHashMap(const QuicheLinkedHashMap& other) = delete; + QuicheLinkedHashMap& operator=(const QuicheLinkedHashMap& other) = delete; + QuicheLinkedHashMap(QuicheLinkedHashMap&& other) = default; + QuicheLinkedHashMap& operator=(QuicheLinkedHashMap&& other) = default; // Returns an iterator to the first (insertion-ordered) element. Like a map, // this can be dereferenced to a pair<Key, Value>. @@ -127,7 +127,8 @@ class SimpleLinkedHashMap { iterator erase(iterator position) { typename MapType::iterator found = map_.find(position->first); QUICHE_CHECK(found->second == position) - << "Inconsisent iterator for map and list, or the iterator is invalid."; + << "Inconsistent iterator for map and list, or the iterator is " + "invalid."; map_.erase(found); return list_.erase(position); @@ -172,49 +173,12 @@ class SimpleLinkedHashMap { // Inserts an element into the map std::pair<iterator, bool> insert(const std::pair<Key, Value>& pair) { - // First make sure the map doesn't have a key with this value. If it does, - // return a pair with an iterator to it, and false indicating that we - // didn't insert anything. - typename MapType::iterator found = map_.find(pair.first); - if (found != map_.end()) { - return std::make_pair(found->second, false); - } - - // Otherwise, insert into the list first. - list_.push_back(pair); - - // Obtain an iterator to the newly added element. We do -- instead of - - // since list::iterator doesn't implement operator-(). - typename ListType::iterator last = list_.end(); - --last; - - QUICHE_CHECK(map_.insert(std::make_pair(pair.first, last)).second) - << "Map and list are inconsistent"; - - return std::make_pair(last, true); + return InsertInternal(pair); } // Inserts an element into the map std::pair<iterator, bool> insert(std::pair<Key, Value>&& pair) { - // First make sure the map doesn't have a key with this value. If it does, - // return a pair with an iterator to it, and false indicating that we - // didn't insert anything. - typename MapType::iterator found = map_.find(pair.first); - if (found != map_.end()) { - return std::make_pair(found->second, false); - } - - // Otherwise, insert into the list first. - list_.push_back(std::move(pair)); - - // Obtain an iterator to the newly added element. We do -- instead of - - // since list::iterator doesn't implement operator-(). - typename ListType::iterator last = list_.end(); - --last; - - QUICHE_CHECK(map_.insert(std::make_pair(last->first, last)).second) - << "Map and list are inconsistent"; - return std::make_pair(last, true); + return InsertInternal(std::move(pair)); } // Derive size_ from map_, as list::size might be O(N). @@ -234,12 +198,30 @@ class SimpleLinkedHashMap { return {ins.first->second, true}; } - void swap(SimpleLinkedHashMap& other) { + void swap(QuicheLinkedHashMap& other) { map_.swap(other.map_); list_.swap(other.list_); } private: + template <typename U> + std::pair<iterator, bool> InsertInternal(U&& pair) { + auto insert_result = map_.try_emplace(pair.first); + auto map_iter = insert_result.first; + + // If the map already contains this key, return a pair with an iterator to + // it, and false indicating that we didn't insert anything. + if (!insert_result.second) { + return {map_iter->second, false}; + } + + // Otherwise, insert into the list, and set value in map. + auto list_iter = list_.insert(list_.end(), std::forward<U>(pair)); + map_iter->second = list_iter; + + return {list_iter, true}; + } + // The map component, used for speedy lookups MapType map_; @@ -249,4 +231,4 @@ class SimpleLinkedHashMap { } // namespace quiche -#endif // QUICHE_COMMON_SIMPLE_LINKED_HASH_MAP_H_ +#endif // QUICHE_COMMON_QUICHE_LINKED_HASH_MAP_H_ diff --git a/chromium/net/third_party/quiche/src/common/simple_linked_hash_map_test.cc b/chromium/net/third_party/quiche/src/common/quiche_linked_hash_map_test.cc index 1119f0d830f..dab608532ba 100644 --- a/chromium/net/third_party/quiche/src/common/simple_linked_hash_map_test.cc +++ b/chromium/net/third_party/quiche/src/common/quiche_linked_hash_map_test.cc @@ -2,9 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Tests SimpleLinkedHashMap. +// Tests QuicheLinkedHashMap. -#include "common/simple_linked_hash_map.h" +#include "common/quiche_linked_hash_map.h" #include <memory> #include <utility> @@ -21,16 +21,16 @@ namespace test { // Tests that move constructor works. TEST(LinkedHashMapTest, Move) { // Use unique_ptr as an example of a non-copyable type. - SimpleLinkedHashMap<int, std::unique_ptr<int>> m; + QuicheLinkedHashMap<int, std::unique_ptr<int>> m; m[2] = std::make_unique<int>(12); m[3] = std::make_unique<int>(13); - SimpleLinkedHashMap<int, std::unique_ptr<int>> n = std::move(m); + QuicheLinkedHashMap<int, std::unique_ptr<int>> n = std::move(m); EXPECT_THAT(n, UnorderedElementsAre(Pair(2, Pointee(12)), Pair(3, Pointee(13)))); } TEST(LinkedHashMapTest, CanEmplaceMoveOnly) { - SimpleLinkedHashMap<int, std::unique_ptr<int>> m; + QuicheLinkedHashMap<int, std::unique_ptr<int>> m; struct Data { int k, v; }; @@ -55,7 +55,7 @@ struct NoCopy { }; TEST(LinkedHashMapTest, CanEmplaceNoMoveNoCopy) { - SimpleLinkedHashMap<int, NoCopy> m; + QuicheLinkedHashMap<int, NoCopy> m; struct Data { int k, v; }; @@ -71,7 +71,7 @@ TEST(LinkedHashMapTest, CanEmplaceNoMoveNoCopy) { } TEST(LinkedHashMapTest, ConstKeys) { - SimpleLinkedHashMap<int, int> m; + QuicheLinkedHashMap<int, int> m; m.insert(std::make_pair(1, 2)); // Test that keys are const in iteration. std::pair<int, int>& p = *m.begin(); @@ -80,14 +80,14 @@ TEST(LinkedHashMapTest, ConstKeys) { // Tests that iteration from begin() to end() works TEST(LinkedHashMapTest, Iteration) { - SimpleLinkedHashMap<int, int> m; + QuicheLinkedHashMap<int, int> m; EXPECT_TRUE(m.begin() == m.end()); m.insert(std::make_pair(2, 12)); m.insert(std::make_pair(1, 11)); m.insert(std::make_pair(3, 13)); - SimpleLinkedHashMap<int, int>::iterator i = m.begin(); + QuicheLinkedHashMap<int, int>::iterator i = m.begin(); ASSERT_TRUE(m.begin() == i); ASSERT_TRUE(m.end() != i); EXPECT_EQ(2, i->first); @@ -109,14 +109,14 @@ TEST(LinkedHashMapTest, Iteration) { // Tests that reverse iteration from rbegin() to rend() works TEST(LinkedHashMapTest, ReverseIteration) { - SimpleLinkedHashMap<int, int> m; + QuicheLinkedHashMap<int, int> m; EXPECT_TRUE(m.rbegin() == m.rend()); m.insert(std::make_pair(2, 12)); m.insert(std::make_pair(1, 11)); m.insert(std::make_pair(3, 13)); - SimpleLinkedHashMap<int, int>::reverse_iterator i = m.rbegin(); + QuicheLinkedHashMap<int, int>::reverse_iterator i = m.rbegin(); ASSERT_TRUE(m.rbegin() == i); ASSERT_TRUE(m.rend() != i); EXPECT_EQ(3, i->first); @@ -138,7 +138,7 @@ TEST(LinkedHashMapTest, ReverseIteration) { // Tests that clear() works TEST(LinkedHashMapTest, Clear) { - SimpleLinkedHashMap<int, int> m; + QuicheLinkedHashMap<int, int> m; m.insert(std::make_pair(2, 12)); m.insert(std::make_pair(1, 11)); m.insert(std::make_pair(3, 13)); @@ -156,7 +156,7 @@ TEST(LinkedHashMapTest, Clear) { // Tests that size() works. TEST(LinkedHashMapTest, Size) { - SimpleLinkedHashMap<int, int> m; + QuicheLinkedHashMap<int, int> m; EXPECT_EQ(0u, m.size()); m.insert(std::make_pair(2, 12)); EXPECT_EQ(1u, m.size()); @@ -170,7 +170,7 @@ TEST(LinkedHashMapTest, Size) { // Tests empty() TEST(LinkedHashMapTest, Empty) { - SimpleLinkedHashMap<int, int> m; + QuicheLinkedHashMap<int, int> m; ASSERT_TRUE(m.empty()); m.insert(std::make_pair(2, 12)); ASSERT_FALSE(m.empty()); @@ -179,7 +179,7 @@ TEST(LinkedHashMapTest, Empty) { } TEST(LinkedHashMapTest, Erase) { - SimpleLinkedHashMap<int, int> m; + QuicheLinkedHashMap<int, int> m; ASSERT_EQ(0u, m.size()); EXPECT_EQ(0u, m.erase(2)); // Nothing to erase yet @@ -193,7 +193,7 @@ TEST(LinkedHashMapTest, Erase) { } TEST(LinkedHashMapTest, Erase2) { - SimpleLinkedHashMap<int, int> m; + QuicheLinkedHashMap<int, int> m; ASSERT_EQ(0u, m.size()); EXPECT_EQ(0u, m.erase(2)); // Nothing to erase yet @@ -210,7 +210,7 @@ TEST(LinkedHashMapTest, Erase2) { EXPECT_EQ(2u, m.size()); // Make sure we can still iterate over everything that's left. - SimpleLinkedHashMap<int, int>::iterator it = m.begin(); + QuicheLinkedHashMap<int, int>::iterator it = m.begin(); ASSERT_TRUE(it != m.end()); EXPECT_EQ(12, it->second); ++it; @@ -232,7 +232,7 @@ TEST(LinkedHashMapTest, Erase2) { // Test that erase(iter,iter) and erase(iter) compile and work. TEST(LinkedHashMapTest, Erase3) { - SimpleLinkedHashMap<int, int> m; + QuicheLinkedHashMap<int, int> m; m.insert(std::make_pair(1, 11)); m.insert(std::make_pair(2, 12)); @@ -240,13 +240,13 @@ TEST(LinkedHashMapTest, Erase3) { m.insert(std::make_pair(4, 14)); // Erase middle two - SimpleLinkedHashMap<int, int>::iterator it2 = m.find(2); - SimpleLinkedHashMap<int, int>::iterator it4 = m.find(4); + QuicheLinkedHashMap<int, int>::iterator it2 = m.find(2); + QuicheLinkedHashMap<int, int>::iterator it4 = m.find(4); EXPECT_EQ(m.erase(it2, it4), m.find(4)); EXPECT_EQ(2u, m.size()); // Make sure we can still iterate over everything that's left. - SimpleLinkedHashMap<int, int>::iterator it = m.begin(); + QuicheLinkedHashMap<int, int>::iterator it = m.begin(); ASSERT_TRUE(it != m.end()); EXPECT_EQ(11, it->second); ++it; @@ -267,9 +267,9 @@ TEST(LinkedHashMapTest, Erase3) { } TEST(LinkedHashMapTest, Insertion) { - SimpleLinkedHashMap<int, int> m; + QuicheLinkedHashMap<int, int> m; ASSERT_EQ(0u, m.size()); - std::pair<SimpleLinkedHashMap<int, int>::iterator, bool> result; + std::pair<QuicheLinkedHashMap<int, int>::iterator, bool> result; result = m.insert(std::make_pair(2, 12)); ASSERT_EQ(1u, m.size()); @@ -284,7 +284,7 @@ TEST(LinkedHashMapTest, Insertion) { EXPECT_EQ(11, result.first->second); result = m.insert(std::make_pair(3, 13)); - SimpleLinkedHashMap<int, int>::iterator result_iterator = result.first; + QuicheLinkedHashMap<int, int>::iterator result_iterator = result.first; ASSERT_EQ(3u, m.size()); EXPECT_TRUE(result.second); EXPECT_EQ(3, result.first->first); @@ -303,7 +303,7 @@ static std::pair<int, int> Pair(int i, int j) { // Test front accessors. TEST(LinkedHashMapTest, Front) { - SimpleLinkedHashMap<int, int> m; + QuicheLinkedHashMap<int, int> m; m.insert(std::make_pair(2, 12)); m.insert(std::make_pair(1, 11)); @@ -322,7 +322,7 @@ TEST(LinkedHashMapTest, Front) { } TEST(LinkedHashMapTest, Find) { - SimpleLinkedHashMap<int, int> m; + QuicheLinkedHashMap<int, int> m; EXPECT_TRUE(m.end() == m.find(1)) << "We shouldn't find anything in an empty map."; @@ -331,7 +331,7 @@ TEST(LinkedHashMapTest, Find) { EXPECT_TRUE(m.end() == m.find(1)) << "We shouldn't find an element that doesn't exist in the map."; - std::pair<SimpleLinkedHashMap<int, int>::iterator, bool> result = + std::pair<QuicheLinkedHashMap<int, int>::iterator, bool> result = m.insert(std::make_pair(1, 11)); ASSERT_TRUE(result.second); ASSERT_TRUE(m.end() != result.first); @@ -341,7 +341,7 @@ TEST(LinkedHashMapTest, Find) { // Check that a follow-up insertion doesn't affect our original m.insert(std::make_pair(3, 13)); - SimpleLinkedHashMap<int, int>::iterator it = m.find(1); + QuicheLinkedHashMap<int, int>::iterator it = m.find(1); ASSERT_TRUE(m.end() != it); EXPECT_EQ(11, it->second); @@ -351,7 +351,7 @@ TEST(LinkedHashMapTest, Find) { } TEST(LinkedHashMapTest, Contains) { - SimpleLinkedHashMap<int, int> m; + QuicheLinkedHashMap<int, int> m; EXPECT_FALSE(m.contains(1)) << "An empty map shouldn't contain anything."; @@ -369,8 +369,8 @@ TEST(LinkedHashMapTest, Contains) { } TEST(LinkedHashMapTest, Swap) { - SimpleLinkedHashMap<int, int> m1; - SimpleLinkedHashMap<int, int> m2; + QuicheLinkedHashMap<int, int> m1; + QuicheLinkedHashMap<int, int> m2; m1.insert(std::make_pair(1, 1)); m1.insert(std::make_pair(2, 2)); m2.insert(std::make_pair(3, 3)); @@ -385,7 +385,7 @@ TEST(LinkedHashMapTest, CustomHashAndEquality) { struct CustomIntHash { size_t operator()(int x) const { return x; } }; - SimpleLinkedHashMap<int, int, CustomIntHash> m; + QuicheLinkedHashMap<int, int, CustomIntHash> m; m.insert(std::make_pair(1, 1)); EXPECT_TRUE(m.contains(1)); EXPECT_EQ(1, m[1]); diff --git a/chromium/net/third_party/quiche/src/common/quiche_text_utils.cc b/chromium/net/third_party/quiche/src/common/quiche_text_utils.cc new file mode 100644 index 00000000000..263c97e9db6 --- /dev/null +++ b/chromium/net/third_party/quiche/src/common/quiche_text_utils.cc @@ -0,0 +1,77 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "common/quiche_text_utils.h" + +#include "absl/strings/escaping.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/str_format.h" + +namespace quiche { + +// static +void QuicheTextUtils::Base64Encode(const uint8_t* data, + size_t data_len, + std::string* output) { + absl::Base64Escape(std::string(reinterpret_cast<const char*>(data), data_len), + output); + // Remove padding. + size_t len = output->size(); + if (len >= 2) { + if ((*output)[len - 1] == '=') { + len--; + if ((*output)[len - 1] == '=') { + len--; + } + output->resize(len); + } + } +} + +// static +absl::optional<std::string> QuicheTextUtils::Base64Decode( + absl::string_view input) { + std::string output; + if (!absl::Base64Unescape(input, &output)) { + return absl::nullopt; + } + return output; +} + +// static +std::string QuicheTextUtils::HexDump(absl::string_view binary_data) { + const int kBytesPerLine = 16; // Maximum bytes dumped per line. + int offset = 0; + const char* p = binary_data.data(); + int bytes_remaining = binary_data.size(); + std::string output; + while (bytes_remaining > 0) { + const int line_bytes = std::min(bytes_remaining, kBytesPerLine); + absl::StrAppendFormat(&output, "0x%04x: ", offset); + for (int i = 0; i < kBytesPerLine; ++i) { + if (i < line_bytes) { + absl::StrAppendFormat(&output, "%02x", + static_cast<unsigned char>(p[i])); + } else { + absl::StrAppend(&output, " "); + } + if (i % 2) { + absl::StrAppend(&output, " "); + } + } + absl::StrAppend(&output, " "); + for (int i = 0; i < line_bytes; ++i) { + // Replace non-printable characters and 0x20 (space) with '.' + output += absl::ascii_isgraph(p[i]) ? p[i] : '.'; + } + + bytes_remaining -= line_bytes; + offset += line_bytes; + p += line_bytes; + absl::StrAppend(&output, "\n"); + } + return output; +} + +} // namespace quiche diff --git a/chromium/net/third_party/quiche/src/common/platform/api/quiche_text_utils.h b/chromium/net/third_party/quiche/src/common/quiche_text_utils.h index 42b4115a5de..c99d9e2ac02 100644 --- a/chromium/net/third_party/quiche/src/common/platform/api/quiche_text_utils.h +++ b/chromium/net/third_party/quiche/src/common/quiche_text_utils.h @@ -2,16 +2,16 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef QUICHE_COMMON_PLATFORM_API_QUICHE_TEXT_UTILS_H_ -#define QUICHE_COMMON_PLATFORM_API_QUICHE_TEXT_UTILS_H_ +#ifndef QUICHE_COMMON_QUICHE_TEXT_UTILS_H_ +#define QUICHE_COMMON_QUICHE_TEXT_UTILS_H_ #include <string> +#include "absl/strings/ascii.h" #include "absl/strings/escaping.h" #include "absl/strings/string_view.h" #include "absl/types/optional.h" #include "common/platform/api/quiche_export.h" -#include "net/quiche/common/platform/impl/quiche_text_utils_impl.h" namespace quiche { @@ -20,47 +20,41 @@ class QUICHE_EXPORT QuicheTextUtils { public: // Returns a new string in which |data| has been converted to lower case. static std::string ToLower(absl::string_view data) { - return quiche::QuicheTextUtilsImpl::ToLower(data); + return absl::AsciiStrToLower(data); } // Removes leading and trailing whitespace from |data|. static void RemoveLeadingAndTrailingWhitespace(absl::string_view* data) { - quiche::QuicheTextUtilsImpl::RemoveLeadingAndTrailingWhitespace(data); + *data = absl::StripAsciiWhitespace(*data); } // Base64 encodes with no padding |data_len| bytes of |data| into |output|. static void Base64Encode(const uint8_t* data, size_t data_len, - std::string* output) { - return quiche::QuicheTextUtilsImpl::Base64Encode(data, data_len, output); - } + std::string* output); // Decodes a base64-encoded |input|. Returns nullopt when the input is // invalid. - static absl::optional<std::string> Base64Decode(absl::string_view input) { - return quiche::QuicheTextUtilsImpl::Base64Decode(input); - } + static absl::optional<std::string> Base64Decode(absl::string_view input); // Returns a string containing hex and ASCII representations of |binary|, // side-by-side in the style of hexdump. Non-printable characters will be // printed as '.' in the ASCII output. // For example, given the input "Hello, QUIC!\01\02\03\04", returns: // "0x0000: 4865 6c6c 6f2c 2051 5549 4321 0102 0304 Hello,.QUIC!...." - static std::string HexDump(absl::string_view binary_data) { - return quiche::QuicheTextUtilsImpl::HexDump(binary_data); - } + static std::string HexDump(absl::string_view binary_data); // Returns true if |data| contains any uppercase characters. static bool ContainsUpperCase(absl::string_view data) { - return quiche::QuicheTextUtilsImpl::ContainsUpperCase(data); + return std::any_of(data.begin(), data.end(), absl::ascii_isupper); } // Returns true if |data| contains only decimal digits. static bool IsAllDigits(absl::string_view data) { - return quiche::QuicheTextUtilsImpl::IsAllDigits(data); + return std::all_of(data.begin(), data.end(), absl::ascii_isdigit); } }; } // namespace quiche -#endif // QUICHE_COMMON_PLATFORM_API_QUICHE_TEXT_UTILS_H_ +#endif // QUICHE_COMMON_QUICHE_TEXT_UTILS_H_ diff --git a/chromium/net/third_party/quiche/src/common/platform/api/quiche_text_utils_test.cc b/chromium/net/third_party/quiche/src/common/quiche_text_utils_test.cc index d6d1f4d443e..5c10cbf931a 100644 --- a/chromium/net/third_party/quiche/src/common/platform/api/quiche_text_utils_test.cc +++ b/chromium/net/third_party/quiche/src/common/quiche_text_utils_test.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "common/platform/api/quiche_text_utils.h" +#include "common/quiche_text_utils.h" #include <string> @@ -12,9 +12,7 @@ namespace quiche { namespace test { -class QuicheTextUtilsTest : public QuicheTest {}; - -TEST_F(QuicheTextUtilsTest, ToLower) { +TEST(QuicheTextUtilsTest, ToLower) { EXPECT_EQ("lower", quiche::QuicheTextUtils::ToLower("LOWER")); EXPECT_EQ("lower", quiche::QuicheTextUtils::ToLower("lower")); EXPECT_EQ("lower", quiche::QuicheTextUtils::ToLower("lOwEr")); @@ -22,7 +20,7 @@ TEST_F(QuicheTextUtilsTest, ToLower) { EXPECT_EQ("", quiche::QuicheTextUtils::ToLower("")); } -TEST_F(QuicheTextUtilsTest, RemoveLeadingAndTrailingWhitespace) { +TEST(QuicheTextUtilsTest, RemoveLeadingAndTrailingWhitespace) { std::string input; for (auto* input : {"text", " text", " text", "text ", "text ", " text ", @@ -33,7 +31,9 @@ TEST_F(QuicheTextUtilsTest, RemoveLeadingAndTrailingWhitespace) { } } -TEST_F(QuicheTextUtilsTest, HexDump) { +TEST(QuicheTextUtilsTest, HexDump) { + // Verify output for empty input. + EXPECT_EQ("", quiche::QuicheTextUtils::HexDump(absl::HexStringToBytes(""))); // Verify output of the HexDump method is as expected. char packet[] = { 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0x51, 0x55, 0x49, 0x43, 0x21, @@ -62,7 +62,7 @@ TEST_F(QuicheTextUtilsTest, HexDump) { quiche::QuicheTextUtils::HexDump(absl::HexStringToBytes("90aaff"))); } -TEST_F(QuicheTextUtilsTest, Base64Encode) { +TEST(QuicheTextUtilsTest, Base64Encode) { std::string output; std::string input = "Hello"; quiche::QuicheTextUtils::Base64Encode( @@ -80,7 +80,7 @@ TEST_F(QuicheTextUtilsTest, Base64Encode) { output); } -TEST_F(QuicheTextUtilsTest, ContainsUpperCase) { +TEST(QuicheTextUtilsTest, ContainsUpperCase) { EXPECT_FALSE(quiche::QuicheTextUtils::ContainsUpperCase("abc")); EXPECT_FALSE(quiche::QuicheTextUtils::ContainsUpperCase("")); EXPECT_FALSE(quiche::QuicheTextUtils::ContainsUpperCase("123")); diff --git a/chromium/net/third_party/quiche/src/http2/adapter/adapter_impl_comparison_test.cc b/chromium/net/third_party/quiche/src/http2/adapter/adapter_impl_comparison_test.cc new file mode 100644 index 00000000000..11f03bb2ffe --- /dev/null +++ b/chromium/net/third_party/quiche/src/http2/adapter/adapter_impl_comparison_test.cc @@ -0,0 +1,83 @@ +#include "http2/adapter/recording_http2_visitor.h" + +#include "http2/adapter/http2_protocol.h" +#include "http2/adapter/nghttp2_adapter.h" +#include "http2/adapter/oghttp2_adapter.h" +#include "http2/adapter/test_frame_sequence.h" +#include "common/platform/api/quiche_test.h" +#include "spdy/core/spdy_protocol.h" + +namespace http2 { +namespace adapter { +namespace test { +namespace { + +TEST(AdapterImplComparisonTest, ClientHandlesFrames) { + RecordingHttp2Visitor nghttp2_visitor; + std::unique_ptr<NgHttp2Adapter> nghttp2_adapter = + NgHttp2Adapter::CreateClientAdapter(nghttp2_visitor); + + RecordingHttp2Visitor oghttp2_visitor; + OgHttp2Adapter::Options options{.perspective = Perspective::kClient}; + std::unique_ptr<OgHttp2Adapter> oghttp2_adapter = + OgHttp2Adapter::Create(oghttp2_visitor, options); + + const std::string initial_frames = TestFrameSequence() + .ServerPreface() + .Ping(42) + .WindowUpdate(0, 1000) + .Serialize(); + + nghttp2_adapter->ProcessBytes(initial_frames); + oghttp2_adapter->ProcessBytes(initial_frames); + + EXPECT_EQ(nghttp2_visitor.GetEventSequence(), + oghttp2_visitor.GetEventSequence()); + + // TODO(b/181586191): Consider consistent behavior for delivering events on + // non-existent streams between nghttp2_adapter and oghttp2_adapter. +} + +TEST(AdapterImplComparisonTest, ServerHandlesFrames) { + RecordingHttp2Visitor nghttp2_visitor; + std::unique_ptr<NgHttp2Adapter> nghttp2_adapter = + NgHttp2Adapter::CreateServerAdapter(nghttp2_visitor); + + RecordingHttp2Visitor oghttp2_visitor; + OgHttp2Adapter::Options options{.perspective = Perspective::kServer}; + std::unique_ptr<OgHttp2Adapter> oghttp2_adapter = + OgHttp2Adapter::Create(oghttp2_visitor, options); + + const std::string frames = TestFrameSequence() + .ClientPreface() + .Ping(42) + .WindowUpdate(0, 1000) + .Headers(1, + {{":method", "POST"}, + {":scheme", "https"}, + {":authority", "example.com"}, + {":path", "/this/is/request/one"}}, + /*fin=*/false) + .WindowUpdate(1, 2000) + .Data(1, "This is the request body.") + .Headers(3, + {{":method", "GET"}, + {":scheme", "http"}, + {":authority", "example.com"}, + {":path", "/this/is/request/two"}}, + /*fin=*/true) + .RstStream(3, Http2ErrorCode::CANCEL) + .Ping(47) + .Serialize(); + + nghttp2_adapter->ProcessBytes(frames); + oghttp2_adapter->ProcessBytes(frames); + + EXPECT_EQ(nghttp2_visitor.GetEventSequence(), + oghttp2_visitor.GetEventSequence()); +} + +} // namespace +} // namespace test +} // namespace adapter +} // namespace http2 diff --git a/chromium/net/third_party/quiche/src/http2/adapter/callback_visitor.cc b/chromium/net/third_party/quiche/src/http2/adapter/callback_visitor.cc new file mode 100644 index 00000000000..eaf4b6169d2 --- /dev/null +++ b/chromium/net/third_party/quiche/src/http2/adapter/callback_visitor.cc @@ -0,0 +1,215 @@ +#include "http2/adapter/callback_visitor.h" + +#include "http2/adapter/nghttp2_util.h" +#include "third_party/nghttp2/src/lib/includes/nghttp2/nghttp2.h" +#include "common/quiche_endian.h" + +// This visitor implementation needs visibility into the +// nghttp2_session_callbacks type. There's no public header, so we'll redefine +// the struct here. +struct nghttp2_session_callbacks { + nghttp2_send_callback send_callback; + nghttp2_recv_callback recv_callback; + nghttp2_on_frame_recv_callback on_frame_recv_callback; + nghttp2_on_invalid_frame_recv_callback on_invalid_frame_recv_callback; + nghttp2_on_data_chunk_recv_callback on_data_chunk_recv_callback; + nghttp2_before_frame_send_callback before_frame_send_callback; + nghttp2_on_frame_send_callback on_frame_send_callback; + nghttp2_on_frame_not_send_callback on_frame_not_send_callback; + nghttp2_on_stream_close_callback on_stream_close_callback; + nghttp2_on_begin_headers_callback on_begin_headers_callback; + nghttp2_on_header_callback on_header_callback; + nghttp2_on_header_callback2 on_header_callback2; + nghttp2_on_invalid_header_callback on_invalid_header_callback; + nghttp2_on_invalid_header_callback2 on_invalid_header_callback2; + nghttp2_select_padding_callback select_padding_callback; + nghttp2_data_source_read_length_callback read_length_callback; + nghttp2_on_begin_frame_callback on_begin_frame_callback; + nghttp2_send_data_callback send_data_callback; + nghttp2_pack_extension_callback pack_extension_callback; + nghttp2_unpack_extension_callback unpack_extension_callback; + nghttp2_on_extension_chunk_recv_callback on_extension_chunk_recv_callback; + nghttp2_error_callback error_callback; + nghttp2_error_callback2 error_callback2; +}; + +namespace http2 { +namespace adapter { + +void CallbackVisitor::OnConnectionError() { + QUICHE_LOG(FATAL) << "Not implemented"; +} + +void CallbackVisitor::OnFrameHeader(Http2StreamId stream_id, + size_t length, + uint8_t type, + uint8_t flags) { + // The general strategy is to clear |current_frame_| at the start of a new + // frame, accumulate frame information from the various callback events, then + // invoke the on_frame_recv_callback() with the accumulated frame data. + memset(¤t_frame_, 0, sizeof(current_frame_)); + current_frame_.hd.stream_id = stream_id; + current_frame_.hd.length = length; + current_frame_.hd.type = type; + current_frame_.hd.flags = flags; + callbacks_->on_begin_frame_callback(nullptr, ¤t_frame_.hd, user_data_); +} + +void CallbackVisitor::OnSettingsStart() {} + +void CallbackVisitor::OnSetting(Http2Setting setting) { + settings_.push_back({.settings_id = setting.id, .value = setting.value}); +} + +void CallbackVisitor::OnSettingsEnd() { + current_frame_.settings.niv = settings_.size(); + current_frame_.settings.iv = settings_.data(); + callbacks_->on_frame_recv_callback(nullptr, ¤t_frame_, user_data_); + settings_.clear(); +} + +void CallbackVisitor::OnSettingsAck() { + // ACK is part of the flags, which were set in OnFrameHeader(). + callbacks_->on_frame_recv_callback(nullptr, ¤t_frame_, user_data_); +} + +void CallbackVisitor::OnBeginHeadersForStream(Http2StreamId stream_id) { + auto it = stream_map_.find(stream_id); + if (it == stream_map_.end()) { + auto p = stream_map_.insert({stream_id, absl::make_unique<StreamInfo>()}); + it = p.first; + } + if (it->second->received_headers) { + // At least one headers frame has already been received. + current_frame_.headers.cat = NGHTTP2_HCAT_HEADERS; + } else { + switch (perspective_) { + case Perspective::kClient: + current_frame_.headers.cat = NGHTTP2_HCAT_RESPONSE; + break; + case Perspective::kServer: + current_frame_.headers.cat = NGHTTP2_HCAT_REQUEST; + break; + } + } + callbacks_->on_begin_headers_callback(nullptr, ¤t_frame_, user_data_); + it->second->received_headers = true; +} + +void CallbackVisitor::OnHeaderForStream(Http2StreamId stream_id, + absl::string_view name, + absl::string_view value) { + callbacks_->on_header_callback( + nullptr, ¤t_frame_, ToUint8Ptr(name.data()), name.size(), + ToUint8Ptr(value.data()), value.size(), NGHTTP2_NV_FLAG_NONE, user_data_); +} + +void CallbackVisitor::OnEndHeadersForStream(Http2StreamId stream_id) { + callbacks_->on_frame_recv_callback(nullptr, ¤t_frame_, user_data_); +} + +void CallbackVisitor::OnBeginDataForStream(Http2StreamId stream_id, + size_t payload_length) { + // TODO(b/181586191): Interpret padding, subtract padding from + // |remaining_data_|. + remaining_data_ = payload_length; + if (remaining_data_ == 0) { + callbacks_->on_frame_recv_callback(nullptr, ¤t_frame_, user_data_); + } +} + +void CallbackVisitor::OnDataForStream(Http2StreamId stream_id, + absl::string_view data) { + callbacks_->on_data_chunk_recv_callback(nullptr, current_frame_.hd.flags, + stream_id, ToUint8Ptr(data.data()), + data.size(), user_data_); + remaining_data_ -= data.size(); + if (remaining_data_ == 0) { + callbacks_->on_frame_recv_callback(nullptr, ¤t_frame_, user_data_); + } +} + +void CallbackVisitor::OnEndStream(Http2StreamId stream_id) {} + +void CallbackVisitor::OnRstStream(Http2StreamId stream_id, + Http2ErrorCode error_code) { + current_frame_.rst_stream.error_code = static_cast<uint32_t>(error_code); + callbacks_->on_frame_recv_callback(nullptr, ¤t_frame_, user_data_); +} + +void CallbackVisitor::OnCloseStream(Http2StreamId stream_id, + Http2ErrorCode error_code) { + callbacks_->on_stream_close_callback( + nullptr, stream_id, static_cast<uint32_t>(error_code), user_data_); +} + +void CallbackVisitor::OnPriorityForStream(Http2StreamId stream_id, + Http2StreamId parent_stream_id, + int weight, + bool exclusive) { + current_frame_.priority.pri_spec.stream_id = parent_stream_id; + current_frame_.priority.pri_spec.weight = weight; + current_frame_.priority.pri_spec.exclusive = exclusive; + callbacks_->on_frame_recv_callback(nullptr, ¤t_frame_, user_data_); +} + +void CallbackVisitor::OnPing(Http2PingId ping_id, bool is_ack) { + uint64_t network_order_opaque_data = + quiche::QuicheEndian::HostToNet64(ping_id); + std::memcpy(current_frame_.ping.opaque_data, &network_order_opaque_data, + sizeof(network_order_opaque_data)); + callbacks_->on_frame_recv_callback(nullptr, ¤t_frame_, user_data_); +} + +void CallbackVisitor::OnPushPromiseForStream(Http2StreamId stream_id, + Http2StreamId promised_stream_id) { + QUICHE_LOG(FATAL) << "Not implemented"; +} + +void CallbackVisitor::OnGoAway(Http2StreamId last_accepted_stream_id, + Http2ErrorCode error_code, + absl::string_view opaque_data) { + current_frame_.goaway.last_stream_id = last_accepted_stream_id; + current_frame_.goaway.error_code = static_cast<uint32_t>(error_code); + current_frame_.goaway.opaque_data = ToUint8Ptr(opaque_data.data()); + current_frame_.goaway.opaque_data_len = opaque_data.size(); + callbacks_->on_frame_recv_callback(nullptr, ¤t_frame_, user_data_); +} + +void CallbackVisitor::OnWindowUpdate(Http2StreamId stream_id, + int window_increment) { + current_frame_.window_update.window_size_increment = window_increment; + callbacks_->on_frame_recv_callback(nullptr, ¤t_frame_, user_data_); +} + +void CallbackVisitor::OnReadyToSendDataForStream(Http2StreamId stream_id, + char* destination_buffer, + size_t length, + ssize_t* written, + bool* end_stream) { + QUICHE_LOG(FATAL) << "Not implemented"; +} + +void CallbackVisitor::OnReadyToSendMetadataForStream(Http2StreamId stream_id, + char* buffer, + size_t length, + ssize_t* written) { + QUICHE_LOG(FATAL) << "Not implemented"; +} + +void CallbackVisitor::OnBeginMetadataForStream(Http2StreamId stream_id, + size_t payload_length) { + QUICHE_LOG(FATAL) << "Not implemented"; +} + +void CallbackVisitor::OnMetadataForStream(Http2StreamId stream_id, + absl::string_view metadata) { + QUICHE_LOG(FATAL) << "Not implemented"; +} + +void CallbackVisitor::OnMetadataEndForStream(Http2StreamId stream_id) { + QUICHE_LOG(FATAL) << "Not implemented"; +} + +} // namespace adapter +} // namespace http2 diff --git a/chromium/net/third_party/quiche/src/http2/adapter/callback_visitor.h b/chromium/net/third_party/quiche/src/http2/adapter/callback_visitor.h new file mode 100644 index 00000000000..94746bf8edb --- /dev/null +++ b/chromium/net/third_party/quiche/src/http2/adapter/callback_visitor.h @@ -0,0 +1,92 @@ +#ifndef QUICHE_HTTP2_ADAPTER_CALLBACK_VISITOR_H_ +#define QUICHE_HTTP2_ADAPTER_CALLBACK_VISITOR_H_ + +#include <memory> +#include <vector> + +#include "absl/container/flat_hash_map.h" +#include "http2/adapter/http2_visitor_interface.h" +#include "http2/adapter/nghttp2_util.h" +#include "third_party/nghttp2/src/lib/includes/nghttp2/nghttp2.h" + +namespace http2 { +namespace adapter { + +// This visitor implementation accepts a set of nghttp2 callbacks and a "user +// data" pointer, and invokes the callbacks according to HTTP/2 events received. +class CallbackVisitor : public Http2VisitorInterface { + public: + explicit CallbackVisitor(Perspective perspective, + nghttp2_session_callbacks_unique_ptr callbacks, + void* user_data) + : perspective_(perspective), + callbacks_(std::move(callbacks)), + user_data_(user_data) {} + + void OnConnectionError() override; + void OnFrameHeader(Http2StreamId stream_id, + size_t length, + uint8_t type, + uint8_t flags) override; + void OnSettingsStart() override; + void OnSetting(Http2Setting setting) override; + void OnSettingsEnd() override; + void OnSettingsAck() override; + void OnBeginHeadersForStream(Http2StreamId stream_id) override; + void OnHeaderForStream(Http2StreamId stream_id, + absl::string_view name, + absl::string_view value) override; + void OnEndHeadersForStream(Http2StreamId stream_id) override; + void OnBeginDataForStream(Http2StreamId stream_id, + size_t payload_length) override; + void OnDataForStream(Http2StreamId stream_id, + absl::string_view data) override; + void OnEndStream(Http2StreamId stream_id) override; + void OnRstStream(Http2StreamId stream_id, Http2ErrorCode error_code) override; + void OnCloseStream(Http2StreamId stream_id, + Http2ErrorCode error_code) override; + void OnPriorityForStream(Http2StreamId stream_id, + Http2StreamId parent_stream_id, + int weight, + bool exclusive) override; + void OnPing(Http2PingId ping_id, bool is_ack) override; + void OnPushPromiseForStream(Http2StreamId stream_id, + Http2StreamId promised_stream_id) override; + void OnGoAway(Http2StreamId last_accepted_stream_id, + Http2ErrorCode error_code, + absl::string_view opaque_data) override; + void OnWindowUpdate(Http2StreamId stream_id, int window_increment) override; + void OnReadyToSendDataForStream(Http2StreamId stream_id, + char* destination_buffer, + size_t length, + ssize_t* written, + bool* end_stream) override; + void OnReadyToSendMetadataForStream(Http2StreamId stream_id, + char* buffer, + size_t length, + ssize_t* written) override; + void OnBeginMetadataForStream(Http2StreamId stream_id, + size_t payload_length) override; + void OnMetadataForStream(Http2StreamId stream_id, + absl::string_view metadata) override; + void OnMetadataEndForStream(Http2StreamId stream_id) override; + + private: + Perspective perspective_; + nghttp2_session_callbacks_unique_ptr callbacks_; + void* user_data_; + + nghttp2_frame current_frame_; + std::vector<nghttp2_settings_entry> settings_; + size_t remaining_data_ = 0; + + struct StreamInfo { + bool received_headers = false; + }; + absl::flat_hash_map<Http2StreamId, std::unique_ptr<StreamInfo>> stream_map_; +}; + +} // namespace adapter +} // namespace http2 + +#endif // QUICHE_HTTP2_ADAPTER_CALLBACK_VISITOR_H_ diff --git a/chromium/net/third_party/quiche/src/http2/adapter/callback_visitor_test.cc b/chromium/net/third_party/quiche/src/http2/adapter/callback_visitor_test.cc new file mode 100644 index 00000000000..4dfcb5fcddb --- /dev/null +++ b/chromium/net/third_party/quiche/src/http2/adapter/callback_visitor_test.cc @@ -0,0 +1,260 @@ +#include "http2/adapter/callback_visitor.h" + +#include "http2/adapter/mock_nghttp2_callbacks.h" +#include "http2/adapter/test_utils.h" +#include "common/platform/api/quiche_test.h" + +namespace http2 { +namespace adapter { +namespace test { +namespace { + +using testing::_; + +enum FrameType { + DATA, + HEADERS, + PRIORITY, + RST_STREAM, + SETTINGS, + PUSH_PROMISE, + PING, + GOAWAY, + WINDOW_UPDATE, +}; + +// Tests connection-level events. +TEST(ClientCallbackVisitorUnitTest, ConnectionFrames) { + testing::StrictMock<MockNghttp2Callbacks> callbacks; + CallbackVisitor visitor(Perspective::kClient, + MockNghttp2Callbacks::GetCallbacks(), &callbacks); + + testing::InSequence seq; + + // SETTINGS + EXPECT_CALL(callbacks, OnBeginFrame(HasFrameHeader(0, SETTINGS, _))); + visitor.OnFrameHeader(0, 0, SETTINGS, 0); + + visitor.OnSettingsStart(); + EXPECT_CALL(callbacks, OnFrameRecv(IsSettings(testing::IsEmpty()))); + visitor.OnSettingsEnd(); + + // PING + EXPECT_CALL(callbacks, OnBeginFrame(HasFrameHeader(0, PING, _))); + visitor.OnFrameHeader(0, 8, PING, 0); + + EXPECT_CALL(callbacks, OnFrameRecv(IsPing(42))); + visitor.OnPing(42, false); + + // WINDOW_UPDATE + EXPECT_CALL(callbacks, OnBeginFrame(HasFrameHeader(0, WINDOW_UPDATE, _))); + visitor.OnFrameHeader(0, 4, WINDOW_UPDATE, 0); + + EXPECT_CALL(callbacks, OnFrameRecv(IsWindowUpdate(1000))); + visitor.OnWindowUpdate(0, 1000); + + // PING ack + EXPECT_CALL(callbacks, + OnBeginFrame(HasFrameHeader(0, PING, NGHTTP2_FLAG_ACK))); + visitor.OnFrameHeader(0, 8, PING, 1); + + EXPECT_CALL(callbacks, OnFrameRecv(IsPingAck(247))); + visitor.OnPing(247, true); + + // GOAWAY + EXPECT_CALL(callbacks, OnBeginFrame(HasFrameHeader(0, GOAWAY, 0))); + visitor.OnFrameHeader(0, 19, GOAWAY, 0); + + EXPECT_CALL(callbacks, OnFrameRecv(IsGoAway(5, NGHTTP2_ENHANCE_YOUR_CALM, + "calm down!!"))); + visitor.OnGoAway(5, Http2ErrorCode::ENHANCE_YOUR_CALM, "calm down!!"); +} + +TEST(ClientCallbackVisitorUnitTest, StreamFrames) { + testing::StrictMock<MockNghttp2Callbacks> callbacks; + CallbackVisitor visitor(Perspective::kClient, + MockNghttp2Callbacks::GetCallbacks(), &callbacks); + + testing::InSequence seq; + + // HEADERS on stream 1 + EXPECT_CALL(callbacks, OnBeginFrame(HasFrameHeader(1, HEADERS, _))); + visitor.OnFrameHeader(1, 23, HEADERS, 4); + + EXPECT_CALL(callbacks, + OnBeginHeaders(IsHeaders(1, _, NGHTTP2_HCAT_RESPONSE))); + visitor.OnBeginHeadersForStream(1); + + EXPECT_CALL(callbacks, OnHeader(_, ":status", "200", _)); + visitor.OnHeaderForStream(1, ":status", "200"); + + EXPECT_CALL(callbacks, OnHeader(_, "server", "my-fake-server", _)); + visitor.OnHeaderForStream(1, "server", "my-fake-server"); + + EXPECT_CALL(callbacks, + OnHeader(_, "date", "Tue, 6 Apr 2021 12:54:01 GMT", _)); + visitor.OnHeaderForStream(1, "date", "Tue, 6 Apr 2021 12:54:01 GMT"); + + EXPECT_CALL(callbacks, OnHeader(_, "trailer", "x-server-status", _)); + visitor.OnHeaderForStream(1, "trailer", "x-server-status"); + + EXPECT_CALL(callbacks, OnFrameRecv(IsHeaders(1, _, NGHTTP2_HCAT_RESPONSE))); + visitor.OnEndHeadersForStream(1); + + // DATA for stream 1 + EXPECT_CALL(callbacks, OnBeginFrame(HasFrameHeader(1, DATA, 0))); + visitor.OnFrameHeader(1, 26, DATA, 0); + + visitor.OnBeginDataForStream(1, 26); + EXPECT_CALL(callbacks, OnDataChunkRecv(0, 1, "This is the response body.")); + EXPECT_CALL(callbacks, OnFrameRecv(IsData(1, _, 0))); + visitor.OnDataForStream(1, "This is the response body."); + + // Trailers for stream 1, with a different nghttp2 "category". + EXPECT_CALL(callbacks, OnBeginFrame(HasFrameHeader(1, HEADERS, _))); + visitor.OnFrameHeader(1, 23, HEADERS, 4); + + EXPECT_CALL(callbacks, OnBeginHeaders(IsHeaders(1, _, NGHTTP2_HCAT_HEADERS))); + visitor.OnBeginHeadersForStream(1); + + EXPECT_CALL(callbacks, OnHeader(_, "x-server-status", "OK", _)); + visitor.OnHeaderForStream(1, "x-server-status", "OK"); + + EXPECT_CALL(callbacks, OnFrameRecv(IsHeaders(1, _, NGHTTP2_HCAT_HEADERS))); + visitor.OnEndHeadersForStream(1); + + // RST_STREAM on stream 3 + EXPECT_CALL(callbacks, OnBeginFrame(HasFrameHeader(3, RST_STREAM, 0))); + visitor.OnFrameHeader(3, 4, RST_STREAM, 0); + + EXPECT_CALL(callbacks, OnFrameRecv(IsRstStream(3, NGHTTP2_INTERNAL_ERROR))); + visitor.OnRstStream(3, Http2ErrorCode::INTERNAL_ERROR); + + EXPECT_CALL(callbacks, OnStreamClose(3, NGHTTP2_INTERNAL_ERROR)); + visitor.OnCloseStream(3, Http2ErrorCode::INTERNAL_ERROR); + + // More stream close events + EXPECT_CALL(callbacks, + OnBeginFrame(HasFrameHeader(1, DATA, NGHTTP2_FLAG_END_STREAM))); + visitor.OnFrameHeader(1, 0, DATA, 1); + + EXPECT_CALL(callbacks, OnFrameRecv(IsData(1, _, NGHTTP2_FLAG_END_STREAM))); + visitor.OnBeginDataForStream(1, 0); + visitor.OnEndStream(1); + + EXPECT_CALL(callbacks, OnStreamClose(1, NGHTTP2_NO_ERROR)); + visitor.OnCloseStream(1, Http2ErrorCode::NO_ERROR); + + EXPECT_CALL(callbacks, OnBeginFrame(HasFrameHeader(5, RST_STREAM, _))); + visitor.OnFrameHeader(5, 4, RST_STREAM, 0); + + EXPECT_CALL(callbacks, OnFrameRecv(IsRstStream(5, NGHTTP2_REFUSED_STREAM))); + visitor.OnRstStream(5, Http2ErrorCode::REFUSED_STREAM); + + EXPECT_CALL(callbacks, OnStreamClose(5, NGHTTP2_REFUSED_STREAM)); + visitor.OnCloseStream(5, Http2ErrorCode::REFUSED_STREAM); +} + +TEST(ServerCallbackVisitorUnitTest, ConnectionFrames) { + testing::StrictMock<MockNghttp2Callbacks> callbacks; + CallbackVisitor visitor(Perspective::kServer, + MockNghttp2Callbacks::GetCallbacks(), &callbacks); + + testing::InSequence seq; + + // SETTINGS + EXPECT_CALL(callbacks, OnBeginFrame(HasFrameHeader(0, SETTINGS, _))); + visitor.OnFrameHeader(0, 0, SETTINGS, 0); + + visitor.OnSettingsStart(); + EXPECT_CALL(callbacks, OnFrameRecv(IsSettings(testing::IsEmpty()))); + visitor.OnSettingsEnd(); + + // PING + EXPECT_CALL(callbacks, OnBeginFrame(HasFrameHeader(0, PING, _))); + visitor.OnFrameHeader(0, 8, PING, 0); + + EXPECT_CALL(callbacks, OnFrameRecv(IsPing(42))); + visitor.OnPing(42, false); + + // WINDOW_UPDATE + EXPECT_CALL(callbacks, OnBeginFrame(HasFrameHeader(0, WINDOW_UPDATE, _))); + visitor.OnFrameHeader(0, 4, WINDOW_UPDATE, 0); + + EXPECT_CALL(callbacks, OnFrameRecv(IsWindowUpdate(1000))); + visitor.OnWindowUpdate(0, 1000); + + // PING ack + EXPECT_CALL(callbacks, + OnBeginFrame(HasFrameHeader(0, PING, NGHTTP2_FLAG_ACK))); + visitor.OnFrameHeader(0, 8, PING, 1); + + EXPECT_CALL(callbacks, OnFrameRecv(IsPingAck(247))); + visitor.OnPing(247, true); +} + +TEST(ServerCallbackVisitorUnitTest, StreamFrames) { + testing::StrictMock<MockNghttp2Callbacks> callbacks; + CallbackVisitor visitor(Perspective::kServer, + MockNghttp2Callbacks::GetCallbacks(), &callbacks); + + testing::InSequence seq; + + // HEADERS on stream 1 + EXPECT_CALL(callbacks, OnBeginFrame(HasFrameHeader( + 1, HEADERS, NGHTTP2_FLAG_END_HEADERS))); + visitor.OnFrameHeader(1, 23, HEADERS, 4); + + EXPECT_CALL(callbacks, OnBeginHeaders(IsHeaders(1, NGHTTP2_FLAG_END_HEADERS, + NGHTTP2_HCAT_REQUEST))); + visitor.OnBeginHeadersForStream(1); + + EXPECT_CALL(callbacks, OnHeader(_, ":method", "POST", _)); + visitor.OnHeaderForStream(1, ":method", "POST"); + + EXPECT_CALL(callbacks, OnHeader(_, ":path", "/example/path", _)); + visitor.OnHeaderForStream(1, ":path", "/example/path"); + + EXPECT_CALL(callbacks, OnHeader(_, ":scheme", "https", _)); + visitor.OnHeaderForStream(1, ":scheme", "https"); + + EXPECT_CALL(callbacks, OnHeader(_, ":authority", "example.com", _)); + visitor.OnHeaderForStream(1, ":authority", "example.com"); + + EXPECT_CALL(callbacks, OnHeader(_, "accept", "text/html", _)); + visitor.OnHeaderForStream(1, "accept", "text/html"); + + EXPECT_CALL(callbacks, OnFrameRecv(IsHeaders(1, NGHTTP2_FLAG_END_HEADERS, + NGHTTP2_HCAT_REQUEST))); + visitor.OnEndHeadersForStream(1); + + // DATA on stream 1 + EXPECT_CALL(callbacks, + OnBeginFrame(HasFrameHeader(1, DATA, NGHTTP2_FLAG_END_STREAM))); + visitor.OnFrameHeader(1, 25, DATA, NGHTTP2_FLAG_END_STREAM); + + visitor.OnBeginDataForStream(1, 25); + EXPECT_CALL(callbacks, OnDataChunkRecv(NGHTTP2_FLAG_END_STREAM, 1, + "This is the request body.")); + EXPECT_CALL(callbacks, OnFrameRecv(IsData(1, _, NGHTTP2_FLAG_END_STREAM))); + visitor.OnDataForStream(1, "This is the request body."); + visitor.OnEndStream(1); + + EXPECT_CALL(callbacks, OnStreamClose(1, NGHTTP2_NO_ERROR)); + visitor.OnCloseStream(1, Http2ErrorCode::NO_ERROR); + + // RST_STREAM on stream 3 + EXPECT_CALL(callbacks, OnBeginFrame(HasFrameHeader(3, RST_STREAM, 0))); + visitor.OnFrameHeader(3, 4, RST_STREAM, 0); + + EXPECT_CALL(callbacks, OnFrameRecv(IsRstStream(3, NGHTTP2_INTERNAL_ERROR))); + visitor.OnRstStream(3, Http2ErrorCode::INTERNAL_ERROR); + + EXPECT_CALL(callbacks, OnStreamClose(3, NGHTTP2_INTERNAL_ERROR)); + visitor.OnCloseStream(3, Http2ErrorCode::INTERNAL_ERROR); +} + +} // namespace +} // namespace test +} // namespace adapter +} // namespace http2 diff --git a/chromium/net/third_party/quiche/src/http2/adapter/data_source.cc b/chromium/net/third_party/quiche/src/http2/adapter/data_source.cc new file mode 100644 index 00000000000..13f89d28581 --- /dev/null +++ b/chromium/net/third_party/quiche/src/http2/adapter/data_source.cc @@ -0,0 +1,23 @@ +#include "http2/adapter/data_source.h" + +namespace http2 { +namespace adapter { + +StringDataSource::StringDataSource(std::string data) + : data_(std::move(data)), remaining_(data_) { + state_ = remaining_.empty() ? DONE : READY; +} + +absl::string_view StringDataSource::NextData() const { + return remaining_; +} + +void StringDataSource::Consume(size_t bytes) { + remaining_.remove_prefix(std::min(bytes, remaining_.size())); + if (remaining_.empty()) { + state_ = DONE; + } +} + +} // namespace adapter +} // namespace http2 diff --git a/chromium/net/third_party/quiche/src/http2/adapter/data_source.h b/chromium/net/third_party/quiche/src/http2/adapter/data_source.h new file mode 100644 index 00000000000..e170104a597 --- /dev/null +++ b/chromium/net/third_party/quiche/src/http2/adapter/data_source.h @@ -0,0 +1,53 @@ +#ifndef QUICHE_HTTP2_ADAPTER_DATA_SOURCE_H_ +#define QUICHE_HTTP2_ADAPTER_DATA_SOURCE_H_ + +#include <string> + +#include "absl/strings/string_view.h" + +namespace http2 { +namespace adapter { + +// Represents a HTTP message body. +class DataSource { + public: + virtual ~DataSource() {} + + enum State { + // The source is not done, but cannot currently provide more data. + NOT_READY, + // The source can provide more data. + READY, + // The source is done. + DONE, + }; + + State state() const { return state_; } + + // The next range of data provided by this data source. + virtual absl::string_view NextData() const = 0; + + // Indicates that |bytes| bytes have been consumed by the caller. + virtual void Consume(size_t bytes) = 0; + + protected: + State state_ = NOT_READY; +}; + +// A simple implementation constructible from a string_view or std::string. +class StringDataSource : public DataSource { + public: + explicit StringDataSource(std::string data); + + absl::string_view NextData() const override; + void Consume(size_t bytes) override; + + private: + const std::string data_; + absl::string_view remaining_; +}; + +} // namespace adapter +} // namespace http2 + +#endif // QUICHE_HTTP2_ADAPTER_DATA_SOURCE_H_ diff --git a/chromium/net/third_party/quiche/src/http2/adapter/data_source_test.cc b/chromium/net/third_party/quiche/src/http2/adapter/data_source_test.cc new file mode 100644 index 00000000000..c290124b430 --- /dev/null +++ b/chromium/net/third_party/quiche/src/http2/adapter/data_source_test.cc @@ -0,0 +1,40 @@ +#include "http2/adapter/data_source.h" + +#include "common/platform/api/quiche_test.h" + +namespace http2 { +namespace adapter { +namespace test { +namespace { + +TEST(StringDataSourceTest, EmptyString) { + StringDataSource source(""); + + EXPECT_EQ(source.state(), DataSource::DONE); + EXPECT_THAT(source.NextData(), testing::IsEmpty()); +} + +TEST(StringDataSourceTest, PartialConsume) { + StringDataSource source("I'm a HTTP message body. Really!"); + + EXPECT_EQ(source.state(), DataSource::READY); + EXPECT_THAT(source.NextData(), testing::Not(testing::IsEmpty())); + source.Consume(6); + EXPECT_EQ(source.state(), DataSource::READY); + EXPECT_THAT(source.NextData(), testing::StartsWith("HTTP")); + + source.Consume(0); + EXPECT_EQ(source.state(), DataSource::READY); + EXPECT_THAT(source.NextData(), testing::StartsWith("HTTP")); + + // Consumes more than the remaining bytes available. + source.Consume(50); + EXPECT_THAT(source.NextData(), testing::IsEmpty()) + << "next data: " << source.NextData(); + EXPECT_EQ(source.state(), DataSource::DONE); +} + +} // namespace +} // namespace test +} // namespace adapter +} // namespace http2 diff --git a/chromium/net/third_party/quiche/src/http2/adapter/http2_adapter.h b/chromium/net/third_party/quiche/src/http2/adapter/http2_adapter.h index 5ea6045af22..ef2ae0a5baf 100644 --- a/chromium/net/third_party/quiche/src/http2/adapter/http2_adapter.h +++ b/chromium/net/third_party/quiche/src/http2/adapter/http2_adapter.h @@ -19,11 +19,6 @@ namespace adapter { // implementations. class Http2Adapter { public: - enum class Perspective { - kClient, - kServer, - }; - Http2Adapter(const Http2Adapter&) = delete; Http2Adapter& operator=(const Http2Adapter&) = delete; @@ -79,6 +74,10 @@ class Http2Adapter { virtual void MarkDataConsumedForStream(Http2StreamId stream_id, size_t num_bytes) = 0; + // Submits a RST_STREAM for the given stream. + virtual void SubmitRst(Http2StreamId stream_id, + Http2ErrorCode error_code) = 0; + protected: // Subclasses should expose a public factory method for constructing and // initializing (via Initialize()) adapter instances. diff --git a/chromium/net/third_party/quiche/src/http2/adapter/http2_protocol.cc b/chromium/net/third_party/quiche/src/http2/adapter/http2_protocol.cc index 18e8985ff4b..8d59aeedda0 100644 --- a/chromium/net/third_party/quiche/src/http2/adapter/http2_protocol.cc +++ b/chromium/net/third_party/quiche/src/http2/adapter/http2_protocol.cc @@ -12,6 +12,15 @@ const char kHttp2AuthorityPseudoHeader[] = ":authority"; const char kHttp2PathPseudoHeader[] = ":path"; const char kHttp2StatusPseudoHeader[] = ":status"; +std::pair<absl::string_view, bool> GetStringView(const HeaderRep& rep) { + if (absl::holds_alternative<absl::string_view>(rep)) { + return std::make_pair(absl::get<absl::string_view>(rep), true); + } else { + absl::string_view view = absl::get<std::string>(rep); + return std::make_pair(view, false); + } +} + absl::string_view Http2SettingsIdToString(uint16_t id) { switch (id) { case Http2KnownSettingsId::HEADER_TABLE_SIZE: diff --git a/chromium/net/third_party/quiche/src/http2/adapter/http2_protocol.h b/chromium/net/third_party/quiche/src/http2/adapter/http2_protocol.h index 49e5f161620..1e1dd39a21a 100644 --- a/chromium/net/third_party/quiche/src/http2/adapter/http2_protocol.h +++ b/chromium/net/third_party/quiche/src/http2/adapter/http2_protocol.h @@ -8,6 +8,7 @@ #include "base/integral_types.h" #include "absl/base/attributes.h" #include "absl/strings/string_view.h" +#include "absl/types/variant.h" namespace http2 { namespace adapter { @@ -21,9 +22,16 @@ using Http2SettingsId = uint16_t; // Represents the payload of an HTTP/2 PING frame. using Http2PingId = uint64_t; +// Represents a single header name or value. +using HeaderRep = absl::variant<absl::string_view, std::string>; + +// Boolean return value is true if |rep| holds a string_view, which is assumed +// to have an indefinite lifetime. +std::pair<absl::string_view, bool> GetStringView(const HeaderRep& rep); + // Represents an HTTP/2 header field. A header field is a key-value pair with // lowercase keys (as specified in RFC 7540 Section 8.1.2). -using Header = std::pair<std::string, std::string>; +using Header = std::pair<HeaderRep, HeaderRep>; // Represents an HTTP/2 SETTINGS key-value parameter. struct Http2Setting { @@ -99,6 +107,11 @@ absl::string_view Http2SettingsIdToString(uint16_t id); // Section 7 definitions. absl::string_view Http2ErrorCodeToString(Http2ErrorCode error_code); +enum class Perspective { + kClient, + kServer, +}; + } // namespace adapter } // namespace http2 diff --git a/chromium/net/third_party/quiche/src/http2/adapter/http2_session.h b/chromium/net/third_party/quiche/src/http2/adapter/http2_session.h index ddbed4477b5..0a6321c0ccc 100644 --- a/chromium/net/third_party/quiche/src/http2/adapter/http2_session.h +++ b/chromium/net/third_party/quiche/src/http2/adapter/http2_session.h @@ -26,15 +26,6 @@ class Http2Session { virtual int GetRemoteWindowSize() const = 0; }; -class Http2Options { - public: - Http2Options() = default; - virtual ~Http2Options() {} - - // This method returns an opaque reference to the underlying type. - virtual void* GetOptions() = 0; -}; - } // namespace adapter } // namespace http2 diff --git a/chromium/net/third_party/quiche/src/http2/adapter/http2_util.cc b/chromium/net/third_party/quiche/src/http2/adapter/http2_util.cc index 40deeb29332..e054a82e4ca 100644 --- a/chromium/net/third_party/quiche/src/http2/adapter/http2_util.cc +++ b/chromium/net/third_party/quiche/src/http2/adapter/http2_util.cc @@ -36,5 +36,38 @@ spdy::SpdyErrorCode TranslateErrorCode(Http2ErrorCode code) { } } +Http2ErrorCode TranslateErrorCode(spdy::SpdyErrorCode code) { + switch (code) { + case spdy::ERROR_CODE_NO_ERROR: + return Http2ErrorCode::NO_ERROR; + case spdy::ERROR_CODE_PROTOCOL_ERROR: + return Http2ErrorCode::PROTOCOL_ERROR; + case spdy::ERROR_CODE_INTERNAL_ERROR: + return Http2ErrorCode::INTERNAL_ERROR; + case spdy::ERROR_CODE_FLOW_CONTROL_ERROR: + return Http2ErrorCode::FLOW_CONTROL_ERROR; + case spdy::ERROR_CODE_SETTINGS_TIMEOUT: + return Http2ErrorCode::SETTINGS_TIMEOUT; + case spdy::ERROR_CODE_STREAM_CLOSED: + return Http2ErrorCode::STREAM_CLOSED; + case spdy::ERROR_CODE_FRAME_SIZE_ERROR: + return Http2ErrorCode::FRAME_SIZE_ERROR; + case spdy::ERROR_CODE_REFUSED_STREAM: + return Http2ErrorCode::REFUSED_STREAM; + case spdy::ERROR_CODE_CANCEL: + return Http2ErrorCode::CANCEL; + case spdy::ERROR_CODE_COMPRESSION_ERROR: + return Http2ErrorCode::COMPRESSION_ERROR; + case spdy::ERROR_CODE_CONNECT_ERROR: + return Http2ErrorCode::CONNECT_ERROR; + case spdy::ERROR_CODE_ENHANCE_YOUR_CALM: + return Http2ErrorCode::ENHANCE_YOUR_CALM; + case spdy::ERROR_CODE_INADEQUATE_SECURITY: + return Http2ErrorCode::INADEQUATE_SECURITY; + case spdy::ERROR_CODE_HTTP_1_1_REQUIRED: + return Http2ErrorCode::HTTP_1_1_REQUIRED; + } +} + } // namespace adapter } // namespace http2 diff --git a/chromium/net/third_party/quiche/src/http2/adapter/http2_util.h b/chromium/net/third_party/quiche/src/http2/adapter/http2_util.h index e9ae2a59561..3ace28b2ce9 100644 --- a/chromium/net/third_party/quiche/src/http2/adapter/http2_util.h +++ b/chromium/net/third_party/quiche/src/http2/adapter/http2_util.h @@ -8,6 +8,7 @@ namespace http2 { namespace adapter { spdy::SpdyErrorCode TranslateErrorCode(Http2ErrorCode code); +Http2ErrorCode TranslateErrorCode(spdy::SpdyErrorCode code); } // namespace adapter } // namespace http2 diff --git a/chromium/net/third_party/quiche/src/http2/adapter/http2_visitor_interface.h b/chromium/net/third_party/quiche/src/http2/adapter/http2_visitor_interface.h index 765e9f43896..12729e75651 100644 --- a/chromium/net/third_party/quiche/src/http2/adapter/http2_visitor_interface.h +++ b/chromium/net/third_party/quiche/src/http2/adapter/http2_visitor_interface.h @@ -34,7 +34,7 @@ namespace adapter { // - OnHeaderForStream() // - OnEndHeadersForStream() // - OnRstStream() -// - OnAbortStream() +// - OnCloseStream() // // Request closed mid-stream, e.g., with error code NO_ERROR: // - OnBeginHeadersForStream() @@ -43,8 +43,7 @@ namespace adapter { // - OnRstStream() // - OnCloseStream() // -// More details are at RFC 7540 (go/http2spec), and more examples are at -// http://google3/net/http2/server/lib/internal/h2/nghttp2/nghttp2_server_adapter_test.cc. +// More details are at RFC 7540 (go/http2spec). class Http2VisitorInterface { public: Http2VisitorInterface(const Http2VisitorInterface&) = delete; @@ -54,6 +53,12 @@ class Http2VisitorInterface { // Called when a connection-level processing error has been encountered. virtual void OnConnectionError() = 0; + // Called when the header for a frame is received. + virtual void OnFrameHeader(Http2StreamId stream_id, + size_t length, + uint8_t type, + uint8_t flags) {} + // Called when a non-ack SETTINGS frame is received. virtual void OnSettingsStart() = 0; @@ -97,18 +102,12 @@ class Http2VisitorInterface { virtual void OnEndStream(Http2StreamId stream_id) = 0; // Called when the connection receives a RST_STREAM for a stream. This call - // will be followed by either OnCloseStream() or OnAbortStream(). + // will be followed by either OnCloseStream(). virtual void OnRstStream(Http2StreamId stream_id, Http2ErrorCode error_code) = 0; - // Called when a stream is closed with error code NO_ERROR. Compare with - // OnAbortStream(). - virtual void OnCloseStream(Http2StreamId stream_id) = 0; - - // Called when a stream is aborted, i.e., closed for the reason indicated by - // the given |error_code|, where error_code != NO_ERROR. Compare with - // OnCloseStream(). - virtual void OnAbortStream(Http2StreamId stream_id, + // Called when a stream is closed. + virtual void OnCloseStream(Http2StreamId stream_id, Http2ErrorCode error_code) = 0; // Called when the connection receives a PRIORITY frame. diff --git a/chromium/net/third_party/quiche/src/http2/adapter/mock_http2_visitor.h b/chromium/net/third_party/quiche/src/http2/adapter/mock_http2_visitor.h index a5c83712fd7..171d40f443f 100644 --- a/chromium/net/third_party/quiche/src/http2/adapter/mock_http2_visitor.h +++ b/chromium/net/third_party/quiche/src/http2/adapter/mock_http2_visitor.h @@ -14,6 +14,11 @@ class MockHttp2Visitor : public Http2VisitorInterface { MockHttp2Visitor() = default; MOCK_METHOD(void, OnConnectionError, (), (override)); + MOCK_METHOD( + void, + OnFrameHeader, + (Http2StreamId stream_id, size_t length, uint8_t type, uint8_t flags), + (override)); MOCK_METHOD(void, OnSettingsStart, (), (override)); MOCK_METHOD(void, OnSetting, (Http2Setting setting), (override)); MOCK_METHOD(void, OnSettingsEnd, (), (override)); @@ -52,10 +57,8 @@ class MockHttp2Visitor : public Http2VisitorInterface { (Http2StreamId stream_id, Http2ErrorCode error_code), (override)); - MOCK_METHOD(void, OnCloseStream, (Http2StreamId stream_id), (override)); - MOCK_METHOD(void, - OnAbortStream, + OnCloseStream, (Http2StreamId stream_id, Http2ErrorCode error_code), (override)); diff --git a/chromium/net/third_party/quiche/src/http2/adapter/mock_nghttp2_callbacks.cc b/chromium/net/third_party/quiche/src/http2/adapter/mock_nghttp2_callbacks.cc new file mode 100644 index 00000000000..4699a371add --- /dev/null +++ b/chromium/net/third_party/quiche/src/http2/adapter/mock_nghttp2_callbacks.cc @@ -0,0 +1,123 @@ +#include "http2/adapter/mock_nghttp2_callbacks.h" + +#include "http2/adapter/nghttp2_util.h" + +namespace http2 { +namespace adapter { +namespace test { + +/* static */ +nghttp2_session_callbacks_unique_ptr MockNghttp2Callbacks::GetCallbacks() { + nghttp2_session_callbacks* callbacks; + nghttp2_session_callbacks_new(&callbacks); + + // All of the callback implementations below just delegate to the mock methods + // of |user_data|, which is assumed to be a MockNghttp2Callbacks*. + nghttp2_session_callbacks_set_send_callback( + callbacks, + [](nghttp2_session*, const uint8_t* data, size_t length, int flags, + void* user_data) -> ssize_t { + return static_cast<MockNghttp2Callbacks*>(user_data)->Send(data, length, + flags); + }); + + nghttp2_session_callbacks_set_send_data_callback( + callbacks, + [](nghttp2_session*, nghttp2_frame* frame, const uint8_t* framehd, + size_t length, nghttp2_data_source* source, void* user_data) -> int { + return static_cast<MockNghttp2Callbacks*>(user_data)->SendData( + frame, framehd, length, source); + }); + + nghttp2_session_callbacks_set_on_begin_headers_callback( + callbacks, + [](nghttp2_session*, const nghttp2_frame* frame, void* user_data) -> int { + return static_cast<MockNghttp2Callbacks*>(user_data)->OnBeginHeaders( + frame); + }); + + nghttp2_session_callbacks_set_on_header_callback( + callbacks, + [](nghttp2_session*, const nghttp2_frame* frame, const uint8_t* raw_name, + size_t name_length, const uint8_t* raw_value, size_t value_length, + uint8_t flags, void* user_data) -> int { + absl::string_view name = ToStringView(raw_name, name_length); + absl::string_view value = ToStringView(raw_value, value_length); + return static_cast<MockNghttp2Callbacks*>(user_data)->OnHeader( + frame, name, value, flags); + }); + + nghttp2_session_callbacks_set_on_data_chunk_recv_callback( + callbacks, + [](nghttp2_session*, uint8_t flags, int32_t stream_id, + const uint8_t* data, size_t len, void* user_data) -> int { + absl::string_view chunk = ToStringView(data, len); + return static_cast<MockNghttp2Callbacks*>(user_data)->OnDataChunkRecv( + flags, stream_id, chunk); + }); + + nghttp2_session_callbacks_set_on_begin_frame_callback( + callbacks, + [](nghttp2_session*, const nghttp2_frame_hd* hd, void* user_data) -> int { + return static_cast<MockNghttp2Callbacks*>(user_data)->OnBeginFrame(hd); + }); + + nghttp2_session_callbacks_set_on_frame_recv_callback( + callbacks, + [](nghttp2_session*, const nghttp2_frame* frame, void* user_data) -> int { + return static_cast<MockNghttp2Callbacks*>(user_data)->OnFrameRecv( + frame); + }); + + nghttp2_session_callbacks_set_on_stream_close_callback( + callbacks, + [](nghttp2_session*, int32_t stream_id, uint32_t error_code, + void* user_data) -> int { + return static_cast<MockNghttp2Callbacks*>(user_data)->OnStreamClose( + stream_id, error_code); + }); + + nghttp2_session_callbacks_set_on_frame_send_callback( + callbacks, + [](nghttp2_session*, const nghttp2_frame* frame, void* user_data) -> int { + return static_cast<MockNghttp2Callbacks*>(user_data)->OnFrameSend( + frame); + }); + + nghttp2_session_callbacks_set_before_frame_send_callback( + callbacks, + [](nghttp2_session*, const nghttp2_frame* frame, void* user_data) -> int { + return static_cast<MockNghttp2Callbacks*>(user_data)->BeforeFrameSend( + frame); + }); + + nghttp2_session_callbacks_set_on_frame_not_send_callback( + callbacks, + [](nghttp2_session*, const nghttp2_frame* frame, int lib_error_code, + void* user_data) -> int { + return static_cast<MockNghttp2Callbacks*>(user_data)->OnFrameNotSend( + frame, lib_error_code); + }); + + nghttp2_session_callbacks_set_on_invalid_frame_recv_callback( + callbacks, + [](nghttp2_session*, const nghttp2_frame* frame, int error_code, + void* user_data) -> int { + return static_cast<MockNghttp2Callbacks*>(user_data) + ->OnInvalidFrameRecv(frame, error_code); + }); + + nghttp2_session_callbacks_set_error_callback2( + callbacks, + [](nghttp2_session* session, int lib_error_code, const char* msg, + size_t len, void* user_data) -> int { + return static_cast<MockNghttp2Callbacks*>(user_data)->OnErrorCallback2( + lib_error_code, msg, len); + }); + + return MakeCallbacksPtr(callbacks); +} + +} // namespace test +} // namespace adapter +} // namespace http2 diff --git a/chromium/net/third_party/quiche/src/http2/adapter/mock_nghttp2_callbacks.h b/chromium/net/third_party/quiche/src/http2/adapter/mock_nghttp2_callbacks.h new file mode 100644 index 00000000000..e2794575c8d --- /dev/null +++ b/chromium/net/third_party/quiche/src/http2/adapter/mock_nghttp2_callbacks.h @@ -0,0 +1,80 @@ +#ifndef QUICHE_HTTP2_ADAPTER_MOCK_NGHTTP2_CALLBACKS_H_ +#define QUICHE_HTTP2_ADAPTER_MOCK_NGHTTP2_CALLBACKS_H_ + +#include "absl/strings/string_view.h" +#include "http2/adapter/nghttp2_util.h" +#include "third_party/nghttp2/src/lib/includes/nghttp2/nghttp2.h" +#include "common/platform/api/quiche_test.h" + +namespace http2 { +namespace adapter { +namespace test { + +// This class provides a set of mock nghttp2 callbacks for use in unit test +// expectations. +class MockNghttp2Callbacks { + public: + MockNghttp2Callbacks() = default; + + // The caller takes ownership of the |nghttp2_session_callbacks|. + static nghttp2_session_callbacks_unique_ptr GetCallbacks(); + + MOCK_METHOD(ssize_t, + Send, + (const uint8_t* data, size_t length, int flags), + ()); + + MOCK_METHOD(int, + SendData, + (nghttp2_frame * frame, + const uint8_t* framehd, + size_t length, + nghttp2_data_source* source), + ()); + + MOCK_METHOD(int, OnBeginHeaders, (const nghttp2_frame* frame), ()); + + MOCK_METHOD(int, + OnHeader, + (const nghttp2_frame* frame, + absl::string_view name, + absl::string_view value, + uint8_t flags), + ()); + + MOCK_METHOD(int, + OnDataChunkRecv, + (uint8_t flags, int32_t stream_id, absl::string_view data), + ()); + + MOCK_METHOD(int, OnBeginFrame, (const nghttp2_frame_hd* hd), ()); + + MOCK_METHOD(int, OnFrameRecv, (const nghttp2_frame* frame), ()); + + MOCK_METHOD(int, OnStreamClose, (int32_t stream_id, uint32_t error_code), ()); + + MOCK_METHOD(int, BeforeFrameSend, (const nghttp2_frame* frame), ()); + + MOCK_METHOD(int, OnFrameSend, (const nghttp2_frame* frame), ()); + + MOCK_METHOD(int, + OnFrameNotSend, + (const nghttp2_frame* frame, int lib_error_code), + ()); + + MOCK_METHOD(int, + OnInvalidFrameRecv, + (const nghttp2_frame* frame, int error_code), + ()); + + MOCK_METHOD(int, + OnErrorCallback2, + (int lib_error_code, const char* msg, size_t len), + ()); +}; + +} // namespace test +} // namespace adapter +} // namespace http2 + +#endif // QUICHE_HTTP2_ADAPTER_MOCK_NGHTTP2_CALLBACKS_H_ diff --git a/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_adapter.cc b/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_adapter.cc new file mode 100644 index 00000000000..878c040ef72 --- /dev/null +++ b/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_adapter.cc @@ -0,0 +1,149 @@ +#include "http2/adapter/nghttp2_adapter.h" + +#include "absl/algorithm/container.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/string_view.h" +#include "http2/adapter/nghttp2_callbacks.h" +#include "third_party/nghttp2/src/lib/includes/nghttp2/nghttp2.h" +#include "common/platform/api/quiche_logging.h" +#include "common/quiche_endian.h" + +namespace http2 { +namespace adapter { + +/* static */ +std::unique_ptr<NgHttp2Adapter> NgHttp2Adapter::CreateClientAdapter( + Http2VisitorInterface& visitor) { + auto adapter = new NgHttp2Adapter(visitor, Perspective::kClient); + adapter->Initialize(); + return absl::WrapUnique(adapter); +} + +/* static */ +std::unique_ptr<NgHttp2Adapter> NgHttp2Adapter::CreateServerAdapter( + Http2VisitorInterface& visitor) { + auto adapter = new NgHttp2Adapter(visitor, Perspective::kServer); + adapter->Initialize(); + return absl::WrapUnique(adapter); +} + +ssize_t NgHttp2Adapter::ProcessBytes(absl::string_view bytes) { + const ssize_t processed_bytes = session_->ProcessBytes(bytes); + if (processed_bytes < 0) { + visitor_.OnConnectionError(); + } + return processed_bytes; +} + +void NgHttp2Adapter::SubmitSettings(absl::Span<const Http2Setting> settings) { + // Submit SETTINGS, converting each Http2Setting to an nghttp2_settings_entry. + std::vector<nghttp2_settings_entry> nghttp2_settings; + absl::c_transform(settings, std::back_inserter(nghttp2_settings), + [](const Http2Setting& setting) { + return nghttp2_settings_entry{setting.id, setting.value}; + }); + nghttp2_submit_settings(session_->raw_ptr(), NGHTTP2_FLAG_NONE, + nghttp2_settings.data(), nghttp2_settings.size()); +} + +void NgHttp2Adapter::SubmitPriorityForStream(Http2StreamId stream_id, + Http2StreamId parent_stream_id, + int weight, + bool exclusive) { + nghttp2_priority_spec priority_spec; + nghttp2_priority_spec_init(&priority_spec, parent_stream_id, weight, + static_cast<int>(exclusive)); + nghttp2_submit_priority(session_->raw_ptr(), NGHTTP2_FLAG_NONE, stream_id, + &priority_spec); +} + +void NgHttp2Adapter::SubmitPing(Http2PingId ping_id) { + uint8_t opaque_data[8] = {}; + Http2PingId ping_id_to_serialize = quiche::QuicheEndian::HostToNet64(ping_id); + std::memcpy(opaque_data, &ping_id_to_serialize, sizeof(Http2PingId)); + nghttp2_submit_ping(session_->raw_ptr(), NGHTTP2_FLAG_NONE, opaque_data); +} + +void NgHttp2Adapter::SubmitGoAway(Http2StreamId last_accepted_stream_id, + Http2ErrorCode error_code, + absl::string_view opaque_data) { + nghttp2_submit_goaway(session_->raw_ptr(), NGHTTP2_FLAG_NONE, + last_accepted_stream_id, + static_cast<uint32_t>(error_code), + ToUint8Ptr(opaque_data.data()), opaque_data.size()); +} + +void NgHttp2Adapter::SubmitWindowUpdate(Http2StreamId stream_id, + int window_increment) { + nghttp2_submit_window_update(session_->raw_ptr(), NGHTTP2_FLAG_NONE, + stream_id, window_increment); +} + +void NgHttp2Adapter::SubmitMetadata(Http2StreamId stream_id, + bool end_metadata) { + QUICHE_LOG(DFATAL) << "Not implemented"; +} + +std::string NgHttp2Adapter::GetBytesToWrite(absl::optional<size_t> max_bytes) { + ssize_t num_bytes = 0; + std::string result; + do { + const uint8_t* data = nullptr; + num_bytes = nghttp2_session_mem_send(session_->raw_ptr(), &data); + if (num_bytes > 0) { + absl::StrAppend( + &result, + absl::string_view(reinterpret_cast<const char*>(data), num_bytes)); + } else if (num_bytes < 0) { + visitor_.OnConnectionError(); + } + } while (num_bytes > 0); + return result; +} + +int NgHttp2Adapter::GetPeerConnectionWindow() const { + return session_->GetRemoteWindowSize(); +} + +void NgHttp2Adapter::MarkDataConsumedForStream(Http2StreamId stream_id, + size_t num_bytes) { + int rc = session_->Consume(stream_id, num_bytes); + if (rc != 0) { + QUICHE_LOG(ERROR) << "Error " << rc << " marking " << num_bytes + << " bytes consumed for stream " << stream_id; + } +} + +void NgHttp2Adapter::SubmitRst(Http2StreamId stream_id, + Http2ErrorCode error_code) { + int status = + nghttp2_submit_rst_stream(session_->raw_ptr(), NGHTTP2_FLAG_NONE, + stream_id, static_cast<uint32_t>(error_code)); + if (status < 0) { + QUICHE_LOG(WARNING) << "Reset stream failed: " << stream_id + << " with status code " << status; + } +} + +NgHttp2Adapter::NgHttp2Adapter(Http2VisitorInterface& visitor, + Perspective perspective) + : Http2Adapter(visitor), visitor_(visitor), perspective_(perspective) {} + +NgHttp2Adapter::~NgHttp2Adapter() {} + +void NgHttp2Adapter::Initialize() { + nghttp2_option* options; + nghttp2_option_new(&options); + // Set some common options for compatibility. + nghttp2_option_set_no_closed_streams(options, 1); + nghttp2_option_set_no_auto_window_update(options, 1); + nghttp2_option_set_max_send_header_block_length(options, 0x2000000); + nghttp2_option_set_max_outbound_ack(options, 10000); + + session_ = + absl::make_unique<NgHttp2Session>(perspective_, callbacks::Create(), + options, static_cast<void*>(&visitor_)); +} + +} // namespace adapter +} // namespace http2 diff --git a/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_adapter.h b/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_adapter.h new file mode 100644 index 00000000000..13c2ffcc3f4 --- /dev/null +++ b/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_adapter.h @@ -0,0 +1,97 @@ +#ifndef QUICHE_HTTP2_ADAPTER_NGHTTP2_ADAPTER_H_ +#define QUICHE_HTTP2_ADAPTER_NGHTTP2_ADAPTER_H_ + +#include "http2/adapter/http2_adapter.h" +#include "http2/adapter/http2_protocol.h" +#include "http2/adapter/nghttp2_session.h" +#include "http2/adapter/nghttp2_util.h" + +namespace http2 { +namespace adapter { + +class NgHttp2Adapter : public Http2Adapter { + public: + ~NgHttp2Adapter() override; + + // Creates an adapter that functions as a client. + static std::unique_ptr<NgHttp2Adapter> CreateClientAdapter( + Http2VisitorInterface& visitor); + + // Creates an adapter that functions as a server. + static std::unique_ptr<NgHttp2Adapter> CreateServerAdapter( + Http2VisitorInterface& visitor); + + // Processes the incoming |bytes| as HTTP/2 and invokes callbacks on the + // |visitor_| as appropriate. + ssize_t ProcessBytes(absl::string_view bytes) override; + + // Submits the |settings| to be written to the peer, e.g., as part of the + // HTTP/2 connection preface. + void SubmitSettings(absl::Span<const Http2Setting> settings) override; + + // Submits a PRIORITY frame for the given stream. + void SubmitPriorityForStream(Http2StreamId stream_id, + Http2StreamId parent_stream_id, + int weight, + bool exclusive) override; + + // Submits a PING on the connection. Note that nghttp2 automatically submits + // PING acks upon receiving non-ack PINGs from the peer, so callers only use + // this method to originate PINGs. See nghttp2_option_set_no_auto_ping_ack(). + void SubmitPing(Http2PingId ping_id) override; + + // Submits a GOAWAY on the connection. Note that |last_accepted_stream_id| + // refers to stream IDs initiated by the peer. For client-side, this last + // stream ID must be even (or 0); for server-side, this last stream ID must be + // odd (or 0). + // TODO(birenroy): Add a graceful shutdown behavior to the API. + void SubmitGoAway(Http2StreamId last_accepted_stream_id, + Http2ErrorCode error_code, + absl::string_view opaque_data) override; + + // Submits a WINDOW_UPDATE for the given stream (a |stream_id| of 0 indicates + // a connection-level WINDOW_UPDATE). + void SubmitWindowUpdate(Http2StreamId stream_id, + int window_increment) override; + + // Submits a METADATA frame for the given stream (a |stream_id| of 0 indicates + // connection-level METADATA). If |end_metadata|, the frame will also have the + // END_METADATA flag set. + void SubmitMetadata(Http2StreamId stream_id, bool end_metadata) override; + + // Returns serialized bytes for writing to the wire. Writes should be + // submitted to Nghttp2Adapter first, so that Nghttp2Adapter has data to + // serialize and return in this method. + std::string GetBytesToWrite(absl::optional<size_t> max_bytes) override; + + // Returns the connection-level flow control window for the peer. + int GetPeerConnectionWindow() const override; + + // Marks the given amount of data as consumed for the given stream, which + // enables the nghttp2 layer to trigger WINDOW_UPDATEs as appropriate. + void MarkDataConsumedForStream(Http2StreamId stream_id, + size_t num_bytes) override; + + // Submits a RST_STREAM with the desired |error_code|. + void SubmitRst(Http2StreamId stream_id, Http2ErrorCode error_code) override; + + // TODO(b/181586191): Temporary accessor until equivalent functionality is + // available in this adapter class. + NgHttp2Session& session() { return *session_; } + + private: + NgHttp2Adapter(Http2VisitorInterface& visitor, Perspective perspective); + + // Performs any necessary initialization of the underlying HTTP/2 session, + // such as preparing initial SETTINGS. + void Initialize(); + + std::unique_ptr<NgHttp2Session> session_; + Http2VisitorInterface& visitor_; + Perspective perspective_; +}; + +} // namespace adapter +} // namespace http2 + +#endif // QUICHE_HTTP2_ADAPTER_NGHTTP2_ADAPTER_H_ diff --git a/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_adapter_test.cc b/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_adapter_test.cc new file mode 100644 index 00000000000..3aec115dbeb --- /dev/null +++ b/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_adapter_test.cc @@ -0,0 +1,255 @@ +#include "http2/adapter/nghttp2_adapter.h" + +#include "http2/adapter/mock_http2_visitor.h" +#include "http2/adapter/test_frame_sequence.h" +#include "http2/adapter/test_utils.h" +#include "common/platform/api/quiche_test.h" + +namespace http2 { +namespace adapter { +namespace test { +namespace { + +using testing::_; + +enum FrameType { + DATA, + HEADERS, + PRIORITY, + RST_STREAM, + SETTINGS, + PUSH_PROMISE, + PING, + GOAWAY, + WINDOW_UPDATE, +}; + +TEST(NgHttp2AdapterTest, ClientConstruction) { + testing::StrictMock<MockHttp2Visitor> visitor; + auto adapter = NgHttp2Adapter::CreateClientAdapter(visitor); + ASSERT_NE(nullptr, adapter); + EXPECT_TRUE(adapter->session().want_read()); + EXPECT_FALSE(adapter->session().want_write()); +} + +TEST(NgHttp2AdapterTest, ClientHandlesFrames) { + testing::StrictMock<MockHttp2Visitor> visitor; + auto adapter = NgHttp2Adapter::CreateClientAdapter(visitor); + std::string serialized = adapter->GetBytesToWrite(absl::nullopt); + EXPECT_THAT(serialized, testing::StrEq(spdy::kHttp2ConnectionHeaderPrefix)); + + const std::string initial_frames = TestFrameSequence() + .ServerPreface() + .Ping(42) + .WindowUpdate(0, 1000) + .Serialize(); + testing::InSequence s; + + // Server preface (empty SETTINGS) + EXPECT_CALL(visitor, OnFrameHeader(0, 0, SETTINGS, 0)); + EXPECT_CALL(visitor, OnSettingsStart()); + EXPECT_CALL(visitor, OnSettingsEnd()); + + EXPECT_CALL(visitor, OnFrameHeader(0, 8, PING, 0)); + EXPECT_CALL(visitor, OnPing(42, false)); + EXPECT_CALL(visitor, OnFrameHeader(0, 4, WINDOW_UPDATE, 0)); + EXPECT_CALL(visitor, OnWindowUpdate(0, 1000)); + + const ssize_t initial_result = adapter->ProcessBytes(initial_frames); + EXPECT_EQ(initial_frames.size(), initial_result); + + EXPECT_EQ(adapter->GetPeerConnectionWindow(), + kDefaultInitialStreamWindowSize + 1000); + // Some bytes should have been serialized. + serialized = adapter->GetBytesToWrite(absl::nullopt); + EXPECT_THAT(serialized, EqualsFrames({spdy::SpdyFrameType::SETTINGS, + spdy::SpdyFrameType::PING})); + + const std::vector<const Header> headers1 = + ToHeaders({{":method", "GET"}, + {":scheme", "http"}, + {":authority", "example.com"}, + {":path", "/this/is/request/one"}}); + const auto nvs1 = GetNghttp2Nvs(headers1); + + const std::vector<const Header> headers2 = + ToHeaders({{":method", "GET"}, + {":scheme", "http"}, + {":authority", "example.com"}, + {":path", "/this/is/request/two"}}); + const auto nvs2 = GetNghttp2Nvs(headers2); + + const std::vector<const Header> headers3 = + ToHeaders({{":method", "GET"}, + {":scheme", "http"}, + {":authority", "example.com"}, + {":path", "/this/is/request/three"}}); + const auto nvs3 = GetNghttp2Nvs(headers3); + + const int32_t stream_id1 = + nghttp2_submit_request(adapter->session().raw_ptr(), nullptr, nvs1.data(), + nvs1.size(), nullptr, nullptr); + ASSERT_GT(stream_id1, 0); + QUICHE_LOG(INFO) << "Created stream: " << stream_id1; + + const int32_t stream_id2 = + nghttp2_submit_request(adapter->session().raw_ptr(), nullptr, nvs2.data(), + nvs2.size(), nullptr, nullptr); + ASSERT_GT(stream_id2, 0); + QUICHE_LOG(INFO) << "Created stream: " << stream_id2; + + const int32_t stream_id3 = + nghttp2_submit_request(adapter->session().raw_ptr(), nullptr, nvs3.data(), + nvs3.size(), nullptr, nullptr); + ASSERT_GT(stream_id3, 0); + QUICHE_LOG(INFO) << "Created stream: " << stream_id3; + + serialized = adapter->GetBytesToWrite(absl::nullopt); + EXPECT_THAT(serialized, EqualsFrames({spdy::SpdyFrameType::HEADERS, + spdy::SpdyFrameType::HEADERS, + spdy::SpdyFrameType::HEADERS})); + + const std::string stream_frames = + TestFrameSequence() + .Headers(1, + {{":status", "200"}, + {"server", "my-fake-server"}, + {"date", "Tue, 6 Apr 2021 12:54:01 GMT"}}, + /*fin=*/false) + .Data(1, "This is the response body.") + .RstStream(3, Http2ErrorCode::INTERNAL_ERROR) + .GoAway(5, Http2ErrorCode::ENHANCE_YOUR_CALM, "calm down!!") + .Serialize(); + + EXPECT_CALL(visitor, OnFrameHeader(1, _, HEADERS, 4)); + EXPECT_CALL(visitor, OnBeginHeadersForStream(1)); + EXPECT_CALL(visitor, OnHeaderForStream(1, ":status", "200")); + EXPECT_CALL(visitor, OnHeaderForStream(1, "server", "my-fake-server")); + EXPECT_CALL(visitor, + OnHeaderForStream(1, "date", "Tue, 6 Apr 2021 12:54:01 GMT")); + EXPECT_CALL(visitor, OnEndHeadersForStream(1)); + EXPECT_CALL(visitor, OnFrameHeader(1, 26, DATA, 0)); + EXPECT_CALL(visitor, OnBeginDataForStream(1, 26)); + EXPECT_CALL(visitor, OnDataForStream(1, "This is the response body.")); + EXPECT_CALL(visitor, OnFrameHeader(3, 4, RST_STREAM, 0)); + EXPECT_CALL(visitor, OnRstStream(3, Http2ErrorCode::INTERNAL_ERROR)); + EXPECT_CALL(visitor, OnCloseStream(3, Http2ErrorCode::INTERNAL_ERROR)); + EXPECT_CALL(visitor, OnFrameHeader(0, 19, GOAWAY, 0)); + EXPECT_CALL(visitor, + OnGoAway(5, Http2ErrorCode::ENHANCE_YOUR_CALM, "calm down!!")); + const ssize_t stream_result = adapter->ProcessBytes(stream_frames); + EXPECT_EQ(stream_frames.size(), stream_result); + + // Even though the client recieved a GOAWAY, streams 1 and 5 are still active. + EXPECT_TRUE(adapter->session().want_read()); + + EXPECT_CALL(visitor, OnFrameHeader(1, 0, DATA, 1)); + EXPECT_CALL(visitor, OnBeginDataForStream(1, 0)); + EXPECT_CALL(visitor, OnEndStream(1)); + EXPECT_CALL(visitor, OnCloseStream(1, Http2ErrorCode::NO_ERROR)); + EXPECT_CALL(visitor, OnFrameHeader(5, 4, RST_STREAM, 0)); + EXPECT_CALL(visitor, OnRstStream(5, Http2ErrorCode::REFUSED_STREAM)); + EXPECT_CALL(visitor, OnCloseStream(5, Http2ErrorCode::REFUSED_STREAM)); + adapter->ProcessBytes(TestFrameSequence() + .Data(1, "", true) + .RstStream(5, Http2ErrorCode::REFUSED_STREAM) + .Serialize()); + // After receiving END_STREAM for 1 and RST_STREAM for 5, the session no + // longer expects reads. + EXPECT_FALSE(adapter->session().want_read()); + + // Client will not have anything else to write. + EXPECT_FALSE(adapter->session().want_write()); + serialized = adapter->GetBytesToWrite(absl::nullopt); + EXPECT_THAT(serialized, testing::IsEmpty()); +} + +TEST(NgHttp2AdapterTest, ServerConstruction) { + testing::StrictMock<MockHttp2Visitor> visitor; + auto adapter = NgHttp2Adapter::CreateServerAdapter(visitor); + ASSERT_NE(nullptr, adapter); + EXPECT_TRUE(adapter->session().want_read()); + EXPECT_FALSE(adapter->session().want_write()); +} + +TEST(NgHttp2AdapterTest, ServerHandlesFrames) { + testing::StrictMock<MockHttp2Visitor> visitor; + auto adapter = NgHttp2Adapter::CreateServerAdapter(visitor); + + const std::string frames = TestFrameSequence() + .ClientPreface() + .Ping(42) + .WindowUpdate(0, 1000) + .Headers(1, + {{":method", "POST"}, + {":scheme", "https"}, + {":authority", "example.com"}, + {":path", "/this/is/request/one"}}, + /*fin=*/false) + .WindowUpdate(1, 2000) + .Data(1, "This is the request body.") + .Headers(3, + {{":method", "GET"}, + {":scheme", "http"}, + {":authority", "example.com"}, + {":path", "/this/is/request/two"}}, + /*fin=*/true) + .RstStream(3, Http2ErrorCode::CANCEL) + .Ping(47) + .Serialize(); + testing::InSequence s; + + // Client preface (empty SETTINGS) + EXPECT_CALL(visitor, OnFrameHeader(0, 0, SETTINGS, 0)); + EXPECT_CALL(visitor, OnSettingsStart()); + EXPECT_CALL(visitor, OnSettingsEnd()); + + EXPECT_CALL(visitor, OnFrameHeader(0, 8, PING, 0)); + EXPECT_CALL(visitor, OnPing(42, false)); + EXPECT_CALL(visitor, OnFrameHeader(0, 4, WINDOW_UPDATE, 0)); + EXPECT_CALL(visitor, OnWindowUpdate(0, 1000)); + EXPECT_CALL(visitor, OnFrameHeader(1, _, HEADERS, 4)); + EXPECT_CALL(visitor, OnBeginHeadersForStream(1)); + EXPECT_CALL(visitor, OnHeaderForStream(1, ":method", "POST")); + EXPECT_CALL(visitor, OnHeaderForStream(1, ":scheme", "https")); + EXPECT_CALL(visitor, OnHeaderForStream(1, ":authority", "example.com")); + EXPECT_CALL(visitor, OnHeaderForStream(1, ":path", "/this/is/request/one")); + EXPECT_CALL(visitor, OnEndHeadersForStream(1)); + EXPECT_CALL(visitor, OnFrameHeader(1, 4, WINDOW_UPDATE, 0)); + EXPECT_CALL(visitor, OnWindowUpdate(1, 2000)); + EXPECT_CALL(visitor, OnFrameHeader(1, 25, DATA, 0)); + EXPECT_CALL(visitor, OnBeginDataForStream(1, 25)); + EXPECT_CALL(visitor, OnDataForStream(1, "This is the request body.")); + EXPECT_CALL(visitor, OnFrameHeader(3, _, HEADERS, 5)); + EXPECT_CALL(visitor, OnBeginHeadersForStream(3)); + EXPECT_CALL(visitor, OnHeaderForStream(3, ":method", "GET")); + EXPECT_CALL(visitor, OnHeaderForStream(3, ":scheme", "http")); + EXPECT_CALL(visitor, OnHeaderForStream(3, ":authority", "example.com")); + EXPECT_CALL(visitor, OnHeaderForStream(3, ":path", "/this/is/request/two")); + EXPECT_CALL(visitor, OnEndHeadersForStream(3)); + EXPECT_CALL(visitor, OnEndStream(3)); + EXPECT_CALL(visitor, OnFrameHeader(3, 4, RST_STREAM, 0)); + EXPECT_CALL(visitor, OnRstStream(3, Http2ErrorCode::CANCEL)); + EXPECT_CALL(visitor, OnCloseStream(3, Http2ErrorCode::CANCEL)); + EXPECT_CALL(visitor, OnFrameHeader(0, 8, PING, 0)); + EXPECT_CALL(visitor, OnPing(47, false)); + + const ssize_t result = adapter->ProcessBytes(frames); + EXPECT_EQ(frames.size(), result); + + EXPECT_EQ(adapter->GetPeerConnectionWindow(), + kDefaultInitialStreamWindowSize + 1000); + + EXPECT_TRUE(adapter->session().want_write()); + // Some bytes should have been serialized. + std::string serialized = adapter->GetBytesToWrite(absl::nullopt); + // SETTINGS ack, two PING acks. + EXPECT_THAT(serialized, EqualsFrames({spdy::SpdyFrameType::SETTINGS, + spdy::SpdyFrameType::PING, + spdy::SpdyFrameType::PING})); +} + +} // namespace +} // namespace test +} // namespace adapter +} // namespace http2 diff --git a/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_callbacks.cc b/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_callbacks.cc index 337f230b796..8774873c95f 100644 --- a/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_callbacks.cc +++ b/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_callbacks.cc @@ -14,11 +14,14 @@ namespace http2 { namespace adapter { +namespace callbacks { int OnBeginFrame(nghttp2_session* /* session */, const nghttp2_frame_hd* header, void* user_data) { auto* visitor = static_cast<Http2VisitorInterface*>(user_data); + visitor->OnFrameHeader(header->stream_id, header->length, header->type, + header->flags); if (header->type == NGHTTP2_DATA) { visitor->OnBeginDataForStream(header->stream_id, header->length); } @@ -30,6 +33,8 @@ int OnFrameReceived(nghttp2_session* /* session */, void* user_data) { auto* visitor = static_cast<Http2VisitorInterface*>(user_data); const Http2StreamId stream_id = frame->hd.stream_id; + QUICHE_VLOG(2) << "Frame " << static_cast<int>(frame->hd.type) + << " for stream " << stream_id; switch (frame->hd.type) { // The beginning of the DATA frame is handled in OnBeginFrame(), and the // beginning of the header block is handled in client/server-specific @@ -158,11 +163,7 @@ int OnStreamClosed(nghttp2_session* /* session */, uint32_t error_code, void* user_data) { auto* visitor = static_cast<Http2VisitorInterface*>(user_data); - if (error_code == static_cast<uint32_t>(Http2ErrorCode::NO_ERROR)) { - visitor->OnCloseStream(stream_id); - } else { - visitor->OnAbortStream(stream_id, ToHttp2ErrorCode(error_code)); - } + visitor->OnCloseStream(stream_id, ToHttp2ErrorCode(error_code)); return 0; } @@ -185,5 +186,24 @@ ssize_t OnReadyToReadDataForStream(nghttp2_session* /* session */, return bytes_to_send; } +nghttp2_session_callbacks_unique_ptr Create() { + nghttp2_session_callbacks* callbacks; + nghttp2_session_callbacks_new(&callbacks); + + nghttp2_session_callbacks_set_on_begin_frame_callback(callbacks, + &OnBeginFrame); + nghttp2_session_callbacks_set_on_frame_recv_callback(callbacks, + &OnFrameReceived); + nghttp2_session_callbacks_set_on_begin_headers_callback(callbacks, + &OnBeginHeaders); + nghttp2_session_callbacks_set_on_header_callback2(callbacks, &OnHeader); + nghttp2_session_callbacks_set_on_data_chunk_recv_callback(callbacks, + &OnDataChunk); + nghttp2_session_callbacks_set_on_stream_close_callback(callbacks, + &OnStreamClosed); + return MakeCallbacksPtr(callbacks); +} + +} // namespace callbacks } // namespace adapter } // namespace http2 diff --git a/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_callbacks.h b/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_callbacks.h index 7e6ce7c38d2..5fbaee041c5 100644 --- a/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_callbacks.h +++ b/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_callbacks.h @@ -2,10 +2,12 @@ #define QUICHE_HTTP2_ADAPTER_NGHTTP2_CALLBACKS_H_ #include "http2/adapter/http2_protocol.h" +#include "http2/adapter/nghttp2_util.h" #include "third_party/nghttp2/src/lib/includes/nghttp2/nghttp2.h" namespace http2 { namespace adapter { +namespace callbacks { // The following functions are nghttp2 callbacks that Nghttp2Adapter sets at the // beginning of its lifetime. It is expected that |user_data| holds an @@ -46,6 +48,9 @@ ssize_t OnReadyToReadDataForStream(nghttp2_session* session, nghttp2_data_source* source, void* user_data); +nghttp2_session_callbacks_unique_ptr Create(); + +} // namespace callbacks } // namespace adapter } // namespace http2 diff --git a/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_session.cc b/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_session.cc new file mode 100644 index 00000000000..d434b06e0f5 --- /dev/null +++ b/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_session.cc @@ -0,0 +1,70 @@ +#include "http2/adapter/nghttp2_session.h" + +#include "common/platform/api/quiche_logging.h" + +namespace http2 { +namespace adapter { +namespace { + +void DeleteOptions(nghttp2_option* options) { + if (options) { + nghttp2_option_del(options); + } +} + +} // namespace + +NgHttp2Session::NgHttp2Session(Perspective perspective, + nghttp2_session_callbacks_unique_ptr callbacks, + nghttp2_option* options, + void* userdata) + : session_(MakeSessionPtr(nullptr)), + options_(options, DeleteOptions), + perspective_(perspective) { + nghttp2_session* session; + switch (perspective) { + case Perspective::kClient: + nghttp2_session_client_new2(&session, callbacks.get(), userdata, + options_.get()); + break; + case Perspective::kServer: + nghttp2_session_server_new2(&session, callbacks.get(), userdata, + options_.get()); + break; + } + session_.reset(session); +} + +NgHttp2Session::~NgHttp2Session() { + // Can't invoke want_read() or want_write(), as they are virtual methods. + const bool pending_reads = nghttp2_session_want_read(session_.get()) != 0; + const bool pending_writes = nghttp2_session_want_write(session_.get()) != 0; + QUICHE_LOG_IF(WARNING, pending_reads || pending_writes) + << "Shutting down connection with pending reads: " << pending_reads + << " or pending writes: " << pending_writes; +} + +ssize_t NgHttp2Session::ProcessBytes(absl::string_view bytes) { + return nghttp2_session_mem_recv( + session_.get(), reinterpret_cast<const uint8_t*>(bytes.data()), + bytes.size()); +} + +int NgHttp2Session::Consume(Http2StreamId stream_id, size_t num_bytes) { + return nghttp2_session_consume(session_.get(), stream_id, num_bytes); +} + +bool NgHttp2Session::want_read() const { + return nghttp2_session_want_read(session_.get()) != 0; +} + +bool NgHttp2Session::want_write() const { + return nghttp2_session_want_write(session_.get()) != 0; +} + +int NgHttp2Session::GetRemoteWindowSize() const { + return nghttp2_session_get_remote_window_size(session_.get()); +} + +} // namespace adapter +} // namespace http2 diff --git a/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_session.h b/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_session.h new file mode 100644 index 00000000000..d446a07c75b --- /dev/null +++ b/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_session.h @@ -0,0 +1,42 @@ +#ifndef QUICHE_HTTP2_ADAPTER_NGHTTP2_SESSION_H_ +#define QUICHE_HTTP2_ADAPTER_NGHTTP2_SESSION_H_ + +#include "http2/adapter/http2_session.h" +#include "http2/adapter/nghttp2_util.h" +#include "third_party/nghttp2/src/lib/includes/nghttp2/nghttp2.h" + +namespace http2 { +namespace adapter { + +// A C++ wrapper around common nghttp2_session operations. +class NgHttp2Session : public Http2Session { + public: + // Takes ownership of |options|. + NgHttp2Session(Perspective perspective, + nghttp2_session_callbacks_unique_ptr callbacks, + nghttp2_option* options, + void* userdata); + ~NgHttp2Session() override; + + ssize_t ProcessBytes(absl::string_view bytes) override; + + int Consume(Http2StreamId stream_id, size_t num_bytes) override; + + bool want_read() const override; + bool want_write() const override; + int GetRemoteWindowSize() const override; + + nghttp2_session* raw_ptr() const { return session_.get(); } + + private: + using OptionsDeleter = void (&)(nghttp2_option*); + + nghttp2_session_unique_ptr session_; + std::unique_ptr<nghttp2_option, OptionsDeleter> options_; + Perspective perspective_; +}; + +} // namespace adapter +} // namespace http2 + +#endif // QUICHE_HTTP2_ADAPTER_NGHTTP2_SESSION_H_ diff --git a/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_session_test.cc b/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_session_test.cc new file mode 100644 index 00000000000..169d2f20dd0 --- /dev/null +++ b/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_session_test.cc @@ -0,0 +1,295 @@ +#include "http2/adapter/nghttp2_session.h" + +#include "http2/adapter/mock_http2_visitor.h" +#include "http2/adapter/nghttp2_callbacks.h" +#include "http2/adapter/nghttp2_util.h" +#include "http2/adapter/test_frame_sequence.h" +#include "http2/adapter/test_utils.h" +#include "common/platform/api/quiche_test.h" + +namespace http2 { +namespace adapter { +namespace test { +namespace { + +using testing::_; + +enum FrameType { + DATA, + HEADERS, + PRIORITY, + RST_STREAM, + SETTINGS, + PUSH_PROMISE, + PING, + GOAWAY, + WINDOW_UPDATE, +}; + +ssize_t SaveSessionOutput(nghttp2_session* /* session*/, + const uint8_t* data, + size_t length, + int /* flags */, + void* user_data) { + auto visitor = static_cast<DataSavingVisitor*>(user_data); + visitor->Save(ToStringView(data, length)); + return length; +} + +class NgHttp2SessionTest : public testing::Test { + public: + nghttp2_option* CreateOptions() { + nghttp2_option* options; + nghttp2_option_new(&options); + nghttp2_option_set_no_auto_window_update(options, 1); + return options; + } + + nghttp2_session_callbacks_unique_ptr CreateCallbacks() { + nghttp2_session_callbacks_unique_ptr callbacks = callbacks::Create(); + nghttp2_session_callbacks_set_send_callback(callbacks.get(), + &SaveSessionOutput); + return callbacks; + } + + DataSavingVisitor visitor_; +}; + +TEST_F(NgHttp2SessionTest, ClientConstruction) { + NgHttp2Session session(Perspective::kClient, CreateCallbacks(), + CreateOptions(), &visitor_); + EXPECT_TRUE(session.want_read()); + EXPECT_FALSE(session.want_write()); + EXPECT_EQ(session.GetRemoteWindowSize(), kDefaultInitialStreamWindowSize); + EXPECT_NE(session.raw_ptr(), nullptr); +} + +TEST_F(NgHttp2SessionTest, ClientHandlesFrames) { + NgHttp2Session session(Perspective::kClient, CreateCallbacks(), + CreateOptions(), &visitor_); + + ASSERT_EQ(0, nghttp2_session_send(session.raw_ptr())); + ASSERT_GT(visitor_.data().size(), 0); + + const std::string initial_frames = TestFrameSequence() + .ServerPreface() + .Ping(42) + .WindowUpdate(0, 1000) + .Serialize(); + testing::InSequence s; + + // Server preface (empty SETTINGS) + EXPECT_CALL(visitor_, OnFrameHeader(0, 0, SETTINGS, 0)); + EXPECT_CALL(visitor_, OnSettingsStart()); + EXPECT_CALL(visitor_, OnSettingsEnd()); + + EXPECT_CALL(visitor_, OnFrameHeader(0, 8, PING, 0)); + EXPECT_CALL(visitor_, OnPing(42, false)); + EXPECT_CALL(visitor_, OnFrameHeader(0, 4, WINDOW_UPDATE, 0)); + EXPECT_CALL(visitor_, OnWindowUpdate(0, 1000)); + + const ssize_t initial_result = session.ProcessBytes(initial_frames); + EXPECT_EQ(initial_frames.size(), initial_result); + + EXPECT_EQ(session.GetRemoteWindowSize(), + kDefaultInitialStreamWindowSize + 1000); + ASSERT_EQ(0, nghttp2_session_send(session.raw_ptr())); + // Some bytes should have been serialized. + absl::string_view serialized = visitor_.data(); + ASSERT_THAT(serialized, + testing::StartsWith(spdy::kHttp2ConnectionHeaderPrefix)); + serialized.remove_prefix(strlen(spdy::kHttp2ConnectionHeaderPrefix)); + EXPECT_THAT(serialized, EqualsFrames({spdy::SpdyFrameType::SETTINGS, + spdy::SpdyFrameType::PING})); + visitor_.Clear(); + + const std::vector<const Header> headers1 = + ToHeaders({{":method", "GET"}, + {":scheme", "http"}, + {":authority", "example.com"}, + {":path", "/this/is/request/one"}}); + const auto nvs1 = GetNghttp2Nvs(headers1); + + const std::vector<const Header> headers2 = + ToHeaders({{":method", "GET"}, + {":scheme", "http"}, + {":authority", "example.com"}, + {":path", "/this/is/request/two"}}); + const auto nvs2 = GetNghttp2Nvs(headers2); + + const std::vector<const Header> headers3 = + ToHeaders({{":method", "GET"}, + {":scheme", "http"}, + {":authority", "example.com"}, + {":path", "/this/is/request/three"}}); + const auto nvs3 = GetNghttp2Nvs(headers3); + + const int32_t stream_id1 = nghttp2_submit_request( + session.raw_ptr(), nullptr, nvs1.data(), nvs1.size(), nullptr, nullptr); + ASSERT_GT(stream_id1, 0); + QUICHE_LOG(INFO) << "Created stream: " << stream_id1; + + const int32_t stream_id2 = nghttp2_submit_request( + session.raw_ptr(), nullptr, nvs2.data(), nvs2.size(), nullptr, nullptr); + ASSERT_GT(stream_id2, 0); + QUICHE_LOG(INFO) << "Created stream: " << stream_id2; + + const int32_t stream_id3 = nghttp2_submit_request( + session.raw_ptr(), nullptr, nvs3.data(), nvs3.size(), nullptr, nullptr); + ASSERT_GT(stream_id3, 0); + QUICHE_LOG(INFO) << "Created stream: " << stream_id3; + + ASSERT_EQ(0, nghttp2_session_send(session.raw_ptr())); + serialized = visitor_.data(); + EXPECT_THAT(serialized, EqualsFrames({spdy::SpdyFrameType::HEADERS, + spdy::SpdyFrameType::HEADERS, + spdy::SpdyFrameType::HEADERS})); + visitor_.Clear(); + + const std::string stream_frames = + TestFrameSequence() + .Headers(1, + {{":status", "200"}, + {"server", "my-fake-server"}, + {"date", "Tue, 6 Apr 2021 12:54:01 GMT"}}, + /*fin=*/false) + .Data(1, "This is the response body.") + .RstStream(3, Http2ErrorCode::INTERNAL_ERROR) + .GoAway(5, Http2ErrorCode::ENHANCE_YOUR_CALM, "calm down!!") + .Serialize(); + + EXPECT_CALL(visitor_, OnFrameHeader(1, _, HEADERS, 4)); + EXPECT_CALL(visitor_, OnBeginHeadersForStream(1)); + EXPECT_CALL(visitor_, OnHeaderForStream(1, ":status", "200")); + EXPECT_CALL(visitor_, OnHeaderForStream(1, "server", "my-fake-server")); + EXPECT_CALL(visitor_, + OnHeaderForStream(1, "date", "Tue, 6 Apr 2021 12:54:01 GMT")); + EXPECT_CALL(visitor_, OnEndHeadersForStream(1)); + EXPECT_CALL(visitor_, OnFrameHeader(1, 26, DATA, 0)); + EXPECT_CALL(visitor_, OnBeginDataForStream(1, 26)); + EXPECT_CALL(visitor_, OnDataForStream(1, "This is the response body.")); + EXPECT_CALL(visitor_, OnFrameHeader(3, 4, RST_STREAM, 0)); + EXPECT_CALL(visitor_, OnRstStream(3, Http2ErrorCode::INTERNAL_ERROR)); + EXPECT_CALL(visitor_, OnCloseStream(3, Http2ErrorCode::INTERNAL_ERROR)); + EXPECT_CALL(visitor_, OnFrameHeader(0, 19, GOAWAY, 0)); + EXPECT_CALL(visitor_, + OnGoAway(5, Http2ErrorCode::ENHANCE_YOUR_CALM, "calm down!!")); + const ssize_t stream_result = session.ProcessBytes(stream_frames); + EXPECT_EQ(stream_frames.size(), stream_result); + + // Even though the client recieved a GOAWAY, streams 1 and 5 are still active. + EXPECT_TRUE(session.want_read()); + + EXPECT_CALL(visitor_, OnFrameHeader(1, 0, DATA, 1)); + EXPECT_CALL(visitor_, OnBeginDataForStream(1, 0)); + EXPECT_CALL(visitor_, OnEndStream(1)); + EXPECT_CALL(visitor_, OnCloseStream(1, Http2ErrorCode::NO_ERROR)); + EXPECT_CALL(visitor_, OnFrameHeader(5, 4, RST_STREAM, 0)); + EXPECT_CALL(visitor_, OnRstStream(5, Http2ErrorCode::REFUSED_STREAM)); + EXPECT_CALL(visitor_, OnCloseStream(5, Http2ErrorCode::REFUSED_STREAM)); + session.ProcessBytes(TestFrameSequence() + .Data(1, "", true) + .RstStream(5, Http2ErrorCode::REFUSED_STREAM) + .Serialize()); + // After receiving END_STREAM for 1 and RST_STREAM for 5, the session no + // longer expects reads. + EXPECT_FALSE(session.want_read()); + + // Client will not have anything else to write. + EXPECT_FALSE(session.want_write()); + ASSERT_EQ(0, nghttp2_session_send(session.raw_ptr())); + serialized = visitor_.data(); + EXPECT_EQ(serialized.size(), 0); +} + +TEST_F(NgHttp2SessionTest, ServerConstruction) { + NgHttp2Session session(Perspective::kServer, CreateCallbacks(), + CreateOptions(), &visitor_); + EXPECT_TRUE(session.want_read()); + EXPECT_FALSE(session.want_write()); + EXPECT_EQ(session.GetRemoteWindowSize(), kDefaultInitialStreamWindowSize); + EXPECT_NE(session.raw_ptr(), nullptr); +} + +TEST_F(NgHttp2SessionTest, ServerHandlesFrames) { + NgHttp2Session session(Perspective::kServer, CreateCallbacks(), + CreateOptions(), &visitor_); + + const std::string frames = TestFrameSequence() + .ClientPreface() + .Ping(42) + .WindowUpdate(0, 1000) + .Headers(1, + {{":method", "POST"}, + {":scheme", "https"}, + {":authority", "example.com"}, + {":path", "/this/is/request/one"}}, + /*fin=*/false) + .WindowUpdate(1, 2000) + .Data(1, "This is the request body.") + .Headers(3, + {{":method", "GET"}, + {":scheme", "http"}, + {":authority", "example.com"}, + {":path", "/this/is/request/two"}}, + /*fin=*/true) + .RstStream(3, Http2ErrorCode::CANCEL) + .Ping(47) + .Serialize(); + testing::InSequence s; + + // Client preface (empty SETTINGS) + EXPECT_CALL(visitor_, OnFrameHeader(0, 0, SETTINGS, 0)); + EXPECT_CALL(visitor_, OnSettingsStart()); + EXPECT_CALL(visitor_, OnSettingsEnd()); + + EXPECT_CALL(visitor_, OnFrameHeader(0, 8, PING, 0)); + EXPECT_CALL(visitor_, OnPing(42, false)); + EXPECT_CALL(visitor_, OnFrameHeader(0, 4, WINDOW_UPDATE, 0)); + EXPECT_CALL(visitor_, OnWindowUpdate(0, 1000)); + EXPECT_CALL(visitor_, OnFrameHeader(1, _, HEADERS, 4)); + EXPECT_CALL(visitor_, OnBeginHeadersForStream(1)); + EXPECT_CALL(visitor_, OnHeaderForStream(1, ":method", "POST")); + EXPECT_CALL(visitor_, OnHeaderForStream(1, ":scheme", "https")); + EXPECT_CALL(visitor_, OnHeaderForStream(1, ":authority", "example.com")); + EXPECT_CALL(visitor_, OnHeaderForStream(1, ":path", "/this/is/request/one")); + EXPECT_CALL(visitor_, OnEndHeadersForStream(1)); + EXPECT_CALL(visitor_, OnFrameHeader(1, 4, WINDOW_UPDATE, 0)); + EXPECT_CALL(visitor_, OnWindowUpdate(1, 2000)); + EXPECT_CALL(visitor_, OnFrameHeader(1, 25, DATA, 0)); + EXPECT_CALL(visitor_, OnBeginDataForStream(1, 25)); + EXPECT_CALL(visitor_, OnDataForStream(1, "This is the request body.")); + EXPECT_CALL(visitor_, OnFrameHeader(3, _, HEADERS, 5)); + EXPECT_CALL(visitor_, OnBeginHeadersForStream(3)); + EXPECT_CALL(visitor_, OnHeaderForStream(3, ":method", "GET")); + EXPECT_CALL(visitor_, OnHeaderForStream(3, ":scheme", "http")); + EXPECT_CALL(visitor_, OnHeaderForStream(3, ":authority", "example.com")); + EXPECT_CALL(visitor_, OnHeaderForStream(3, ":path", "/this/is/request/two")); + EXPECT_CALL(visitor_, OnEndHeadersForStream(3)); + EXPECT_CALL(visitor_, OnEndStream(3)); + EXPECT_CALL(visitor_, OnFrameHeader(3, 4, RST_STREAM, 0)); + EXPECT_CALL(visitor_, OnRstStream(3, Http2ErrorCode::CANCEL)); + EXPECT_CALL(visitor_, OnCloseStream(3, Http2ErrorCode::CANCEL)); + EXPECT_CALL(visitor_, OnFrameHeader(0, 8, PING, 0)); + EXPECT_CALL(visitor_, OnPing(47, false)); + + const ssize_t result = session.ProcessBytes(frames); + EXPECT_EQ(frames.size(), result); + + EXPECT_EQ(session.GetRemoteWindowSize(), + kDefaultInitialStreamWindowSize + 1000); + + EXPECT_TRUE(session.want_write()); + ASSERT_EQ(0, nghttp2_session_send(session.raw_ptr())); + // Some bytes should have been serialized. + absl::string_view serialized = visitor_.data(); + // SETTINGS ack, two PING acks. + EXPECT_THAT(serialized, EqualsFrames({spdy::SpdyFrameType::SETTINGS, + spdy::SpdyFrameType::PING, + spdy::SpdyFrameType::PING})); +} + +} // namespace +} // namespace test +} // namespace adapter +} // namespace http2 diff --git a/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_util.cc b/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_util.cc index e1341481ae5..8d23a55278a 100644 --- a/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_util.cc +++ b/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_util.cc @@ -10,6 +10,31 @@ namespace http2 { namespace adapter { +namespace { + +void DeleteCallbacks(nghttp2_session_callbacks* callbacks) { + if (callbacks) { + nghttp2_session_callbacks_del(callbacks); + } +} + +void DeleteSession(nghttp2_session* session) { + if (session) { + nghttp2_session_del(session); + } +} + +} // namespace + +nghttp2_session_callbacks_unique_ptr MakeCallbacksPtr( + nghttp2_session_callbacks* callbacks) { + return nghttp2_session_callbacks_unique_ptr(callbacks, DeleteCallbacks); +} + +nghttp2_session_unique_ptr MakeSessionPtr(nghttp2_session* session) { + return nghttp2_session_unique_ptr(session, DeleteSession); +} + uint8_t* ToUint8Ptr(char* str) { return reinterpret_cast<uint8_t*>(str); } uint8_t* ToUint8Ptr(const char* str) { return const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(str)); @@ -25,16 +50,30 @@ absl::string_view ToStringView(uint8_t* pointer, size_t length) { return absl::string_view(reinterpret_cast<const char*>(pointer), length); } -std::vector<nghttp2_nv> GetRequestNghttp2Nvs(absl::Span<const Header> headers) { +absl::string_view ToStringView(const uint8_t* pointer, size_t length) { + return absl::string_view(reinterpret_cast<const char*>(pointer), length); +} + +std::vector<nghttp2_nv> GetNghttp2Nvs(absl::Span<const Header> headers) { const int num_headers = headers.size(); auto nghttp2_nvs = std::vector<nghttp2_nv>(num_headers); for (int i = 0; i < num_headers; ++i) { nghttp2_nv header; - header.name = ToUint8Ptr(&headers[i].first[0]); - header.namelen = headers[i].first.size(); - header.value = ToUint8Ptr(&headers[i].second[0]); - header.valuelen = headers[i].second.size(); - header.flags = NGHTTP2_FLAG_NONE; + uint8_t flags = NGHTTP2_NV_FLAG_NONE; + + const auto [name, no_copy_name] = GetStringView(headers[i].first); + header.name = ToUint8Ptr(name.data()); + header.namelen = name.size(); + if (no_copy_name) { + flags |= NGHTTP2_NV_FLAG_NO_COPY_NAME; + } + const auto [value, no_copy_value] = GetStringView(headers[i].second); + header.value = ToUint8Ptr(value.data()); + header.valuelen = value.size(); + if (no_copy_value) { + flags |= NGHTTP2_NV_FLAG_NO_COPY_VALUE; + } + header.flags = flags; nghttp2_nvs.push_back(std::move(header)); } diff --git a/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_util.h b/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_util.h index 3fcbfcd068c..e2c3e7a37c7 100644 --- a/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_util.h +++ b/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_util.h @@ -20,15 +20,28 @@ inline constexpr int kStreamCallbackFailureStatus = NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; inline constexpr int kCancelStatus = NGHTTP2_ERR_CANCEL; +using CallbacksDeleter = void (&)(nghttp2_session_callbacks*); +using SessionDeleter = void (&)(nghttp2_session*); + +using nghttp2_session_callbacks_unique_ptr = + std::unique_ptr<nghttp2_session_callbacks, CallbacksDeleter>; +using nghttp2_session_unique_ptr = + std::unique_ptr<nghttp2_session, SessionDeleter>; + +nghttp2_session_callbacks_unique_ptr MakeCallbacksPtr( + nghttp2_session_callbacks* callbacks); +nghttp2_session_unique_ptr MakeSessionPtr(nghttp2_session* session); + uint8_t* ToUint8Ptr(char* str); uint8_t* ToUint8Ptr(const char* str); absl::string_view ToStringView(nghttp2_rcbuf* rc_buffer); absl::string_view ToStringView(uint8_t* pointer, size_t length); +absl::string_view ToStringView(const uint8_t* pointer, size_t length); -// Returns the nghttp2 header structure from the given request |headers|, which +// Returns the nghttp2 header structure from the given |headers|, which // must have the correct pseudoheaders preceding other headers. -std::vector<nghttp2_nv> GetRequestNghttp2Nvs(absl::Span<const Header> headers); +std::vector<nghttp2_nv> GetNghttp2Nvs(absl::Span<const Header> headers); // Returns the nghttp2 header structure from the given response |headers|, with // the :status pseudoheader first based on the given |response_code|. The diff --git a/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_adapter.cc b/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_adapter.cc index 7b7d2a2229b..9f287facb9f 100644 --- a/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_adapter.cc +++ b/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_adapter.cc @@ -1,12 +1,9 @@ #include "http2/adapter/oghttp2_adapter.h" -#include <list> - #include "absl/memory/memory.h" #include "absl/strings/str_cat.h" #include "http2/adapter/http2_util.h" -#include "http2/adapter/window_manager.h" -#include "spdy/core/spdy_framer.h" +#include "common/platform/api/quiche_bug_tracker.h" #include "spdy/core/spdy_protocol.h" namespace http2 { @@ -23,70 +20,6 @@ using spdy::SpdyWindowUpdateIR; } // namespace -struct StreamState { - WindowManager window_manager; -}; - -class OgHttp2Adapter::OgHttp2Session : public Http2Session { - public: - OgHttp2Session(Http2VisitorInterface& /*visitor*/, Options /*options*/) {} - ~OgHttp2Session() override {} - - ssize_t ProcessBytes(absl::string_view bytes) override { - SPDY_BUG(oghttp2_process_bytes) << "Not implemented"; - return 0; - } - - int Consume(Http2StreamId stream_id, size_t num_bytes) override { - auto it = stream_map_.find(stream_id); - if (it == stream_map_.end()) { - // TODO(b/181586191): LOG_ERROR rather than SPDY_BUG. - SPDY_BUG(stream_consume_notfound) - << "Stream " << stream_id << " not found"; - } else { - it->second.window_manager.MarkDataFlushed(num_bytes); - } - return 0; // Remove? - } - - bool want_read() const override { return false; } - bool want_write() const override { - return !frames_.empty() || !serialized_prefix_.empty(); - } - int GetRemoteWindowSize() const override { - SPDY_BUG(peer_window_not_updated) << "Not implemented"; - return peer_window_; - } - - void EnqueueFrame(std::unique_ptr<spdy::SpdyFrameIR> frame) { - frames_.push_back(std::move(frame)); - } - - std::string GetBytesToWrite(absl::optional<size_t> max_bytes) { - const size_t serialized_max = - max_bytes ? max_bytes.value() : std::numeric_limits<size_t>::max(); - std::string serialized = std::move(serialized_prefix_); - while (serialized.size() < serialized_max && !frames_.empty()) { - spdy::SpdySerializedFrame frame = - framer_.SerializeFrame(*frames_.front()); - absl::StrAppend(&serialized, absl::string_view(frame)); - frames_.pop_front(); - } - if (serialized.size() > serialized_max) { - serialized_prefix_ = serialized.substr(serialized_max); - serialized.resize(serialized_max); - } - return serialized; - } - - private: - spdy::SpdyFramer framer_{spdy::SpdyFramer::ENABLE_COMPRESSION}; - absl::flat_hash_map<Http2StreamId, StreamState> stream_map_; - std::list<std::unique_ptr<SpdyFrameIR>> frames_; - std::string serialized_prefix_; - int peer_window_ = 65535; -}; - /* static */ std::unique_ptr<OgHttp2Adapter> OgHttp2Adapter::Create( Http2VisitorInterface& visitor, @@ -135,7 +68,7 @@ void OgHttp2Adapter::SubmitWindowUpdate(Http2StreamId stream_id, } void OgHttp2Adapter::SubmitMetadata(Http2StreamId stream_id, bool fin) { - SPDY_BUG(oghttp2_submit_metadata) << "Not implemented"; + QUICHE_BUG(oghttp2_submit_metadata) << "Not implemented"; } std::string OgHttp2Adapter::GetBytesToWrite(absl::optional<size_t> max_bytes) { @@ -151,6 +84,12 @@ void OgHttp2Adapter::MarkDataConsumedForStream(Http2StreamId stream_id, session_->Consume(stream_id, num_bytes); } +void OgHttp2Adapter::SubmitRst(Http2StreamId stream_id, + Http2ErrorCode error_code) { + session_->EnqueueFrame(absl::make_unique<spdy::SpdyRstStreamIR>( + stream_id, TranslateErrorCode(error_code))); +} + const Http2Session& OgHttp2Adapter::session() const { return *session_; } diff --git a/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_adapter.h b/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_adapter.h index 1f32cfc6ddd..572ba04e9fc 100644 --- a/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_adapter.h +++ b/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_adapter.h @@ -5,15 +5,14 @@ #include "http2/adapter/http2_adapter.h" #include "http2/adapter/http2_session.h" +#include "http2/adapter/oghttp2_session.h" namespace http2 { namespace adapter { class OgHttp2Adapter : public Http2Adapter { public: - struct Options { - Perspective context; - }; + using Options = OgHttp2Session::Options; static std::unique_ptr<OgHttp2Adapter> Create(Http2VisitorInterface& visitor, Options options); @@ -37,13 +36,13 @@ class OgHttp2Adapter : public Http2Adapter { int GetPeerConnectionWindow() const override; void MarkDataConsumedForStream(Http2StreamId stream_id, size_t num_bytes) override; + void SubmitRst(Http2StreamId stream_id, Http2ErrorCode error_code) override; const Http2Session& session() const; private: OgHttp2Adapter(Http2VisitorInterface& visitor, Options options); - class OgHttp2Session; std::unique_ptr<OgHttp2Session> session_; }; diff --git a/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_adapter_test.cc b/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_adapter_test.cc index 3c04c06d7ec..4c849f6fd6d 100644 --- a/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_adapter_test.cc +++ b/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_adapter_test.cc @@ -1,9 +1,10 @@ #include "http2/adapter/oghttp2_adapter.h" #include "http2/adapter/mock_http2_visitor.h" +#include "http2/adapter/test_frame_sequence.h" #include "http2/adapter/test_utils.h" #include "common/platform/api/quiche_test.h" -#include "spdy/platform/api/spdy_test_helpers.h" +#include "common/platform/api/quiche_test_helpers.h" namespace http2 { namespace adapter { @@ -13,7 +14,7 @@ namespace { class OgHttp2AdapterTest : public testing::Test { protected: void SetUp() override { - OgHttp2Adapter::Options options; + OgHttp2Adapter::Options options{.perspective = Perspective::kServer}; adapter_ = OgHttp2Adapter::Create(http2_visitor_, options); } @@ -22,27 +23,32 @@ class OgHttp2AdapterTest : public testing::Test { }; TEST_F(OgHttp2AdapterTest, ProcessBytes) { - EXPECT_SPDY_BUG(adapter_->ProcessBytes("fake data"), "Not implemented"); + testing::InSequence seq; + EXPECT_CALL(http2_visitor_, OnFrameHeader(0, 0, 4, 0)); + EXPECT_CALL(http2_visitor_, OnSettingsStart()); + EXPECT_CALL(http2_visitor_, OnSettingsEnd()); + EXPECT_CALL(http2_visitor_, OnFrameHeader(0, 8, 6, 0)); + EXPECT_CALL(http2_visitor_, OnPing(17, false)); + adapter_->ProcessBytes( + TestFrameSequence().ClientPreface().Ping(17).Serialize()); } TEST_F(OgHttp2AdapterTest, SubmitMetadata) { - EXPECT_SPDY_BUG(adapter_->SubmitMetadata(3, true), "Not implemented"); + EXPECT_QUICHE_BUG(adapter_->SubmitMetadata(3, true), "Not implemented"); } TEST_F(OgHttp2AdapterTest, GetPeerConnectionWindow) { - int peer_window = 0; - EXPECT_SPDY_BUG(peer_window = adapter_->GetPeerConnectionWindow(), - "Not implemented"); + const int peer_window = adapter_->GetPeerConnectionWindow(); EXPECT_GT(peer_window, 0); } TEST_F(OgHttp2AdapterTest, MarkDataConsumedForStream) { - EXPECT_SPDY_BUG(adapter_->MarkDataConsumedForStream(1, 11), - "Stream 1 not found"); + EXPECT_QUICHE_BUG(adapter_->MarkDataConsumedForStream(1, 11), + "Stream 1 not found"); } TEST_F(OgHttp2AdapterTest, TestSerialize) { - EXPECT_FALSE(adapter_->session().want_read()); + EXPECT_TRUE(adapter_->session().want_read()); EXPECT_FALSE(adapter_->session().want_write()); adapter_->SubmitSettings( @@ -50,16 +56,18 @@ TEST_F(OgHttp2AdapterTest, TestSerialize) { EXPECT_TRUE(adapter_->session().want_write()); adapter_->SubmitPriorityForStream(3, 1, 255, true); + adapter_->SubmitRst(3, Http2ErrorCode::CANCEL); adapter_->SubmitPing(42); adapter_->SubmitGoAway(13, Http2ErrorCode::NO_ERROR, ""); adapter_->SubmitWindowUpdate(3, 127); EXPECT_TRUE(adapter_->session().want_write()); - EXPECT_THAT(adapter_->GetBytesToWrite(absl::nullopt), - ContainsFrames( - {spdy::SpdyFrameType::SETTINGS, spdy::SpdyFrameType::PRIORITY, - spdy::SpdyFrameType::PING, spdy::SpdyFrameType::GOAWAY, - spdy::SpdyFrameType::WINDOW_UPDATE})); + EXPECT_THAT( + adapter_->GetBytesToWrite(absl::nullopt), + EqualsFrames( + {spdy::SpdyFrameType::SETTINGS, spdy::SpdyFrameType::PRIORITY, + spdy::SpdyFrameType::RST_STREAM, spdy::SpdyFrameType::PING, + spdy::SpdyFrameType::GOAWAY, spdy::SpdyFrameType::WINDOW_UPDATE})); EXPECT_FALSE(adapter_->session().want_write()); } @@ -78,8 +86,8 @@ TEST_F(OgHttp2AdapterTest, TestPartialSerialize) { EXPECT_FALSE(adapter_->session().want_write()); EXPECT_THAT( absl::StrCat(first_part, second_part), - ContainsFrames({spdy::SpdyFrameType::SETTINGS, - spdy::SpdyFrameType::GOAWAY, spdy::SpdyFrameType::PING})); + EqualsFrames({spdy::SpdyFrameType::SETTINGS, spdy::SpdyFrameType::GOAWAY, + spdy::SpdyFrameType::PING})); } } // namespace diff --git a/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_session.cc b/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_session.cc new file mode 100644 index 00000000000..2222fed4b6b --- /dev/null +++ b/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_session.cc @@ -0,0 +1,231 @@ +#include "http2/adapter/oghttp2_session.h" + +#include "absl/strings/escaping.h" + +namespace http2 { +namespace adapter { + +void OgHttp2Session::PassthroughHeadersHandler::OnHeaderBlockStart() { + visitor_.OnBeginHeadersForStream(stream_id_); +} + +void OgHttp2Session::PassthroughHeadersHandler::OnHeader( + absl::string_view key, + absl::string_view value) { + visitor_.OnHeaderForStream(stream_id_, key, value); +} + +void OgHttp2Session::PassthroughHeadersHandler::OnHeaderBlockEnd( + size_t /* uncompressed_header_bytes */, + size_t /* compressed_header_bytes */) { + visitor_.OnEndHeadersForStream(stream_id_); +} + +OgHttp2Session::OgHttp2Session(Http2VisitorInterface& visitor, Options options) + : visitor_(visitor), headers_handler_(visitor), options_(options) { + decoder_.set_visitor(this); + if (options_.perspective == Perspective::kServer) { + remaining_preface_ = {spdy::kHttp2ConnectionHeaderPrefix, + spdy::kHttp2ConnectionHeaderPrefixSize}; + } +} + +OgHttp2Session::~OgHttp2Session() {} + +ssize_t OgHttp2Session::ProcessBytes(absl::string_view bytes) { + ssize_t preface_consumed = 0; + if (!remaining_preface_.empty()) { + QUICHE_VLOG(2) << "Preface bytes remaining: " << remaining_preface_.size(); + // decoder_ does not understand the client connection preface. + size_t min_size = std::min(remaining_preface_.size(), bytes.size()); + if (!absl::StartsWith(remaining_preface_, bytes.substr(0, min_size))) { + // Preface doesn't match! + QUICHE_DLOG(INFO) << "Preface doesn't match! Expected: [" + << absl::CEscape(remaining_preface_) << "], actual: [" + << absl::CEscape(bytes) << "]"; + visitor_.OnConnectionError(); + return -1; + } + remaining_preface_.remove_prefix(min_size); + bytes.remove_prefix(min_size); + if (!remaining_preface_.empty()) { + QUICHE_VLOG(2) << "Preface bytes remaining: " + << remaining_preface_.size(); + return min_size; + } + preface_consumed = min_size; + } + ssize_t result = decoder_.ProcessInput(bytes.data(), bytes.size()); + return result < 0 ? result : result + preface_consumed; +} + +int OgHttp2Session::Consume(Http2StreamId stream_id, size_t num_bytes) { + auto it = stream_map_.find(stream_id); + if (it == stream_map_.end()) { + // TODO(b/181586191): LOG_ERROR rather than QUICHE_BUG. + QUICHE_BUG(stream_consume_notfound) + << "Stream " << stream_id << " not found"; + } else { + it->second.window_manager.MarkDataFlushed(num_bytes); + } + return 0; // Remove? +} + +void OgHttp2Session::EnqueueFrame(std::unique_ptr<spdy::SpdyFrameIR> frame) { + frames_.push_back(std::move(frame)); +} + +std::string OgHttp2Session::GetBytesToWrite(absl::optional<size_t> max_bytes) { + const size_t serialized_max = + max_bytes ? max_bytes.value() : std::numeric_limits<size_t>::max(); + std::string serialized = std::move(serialized_prefix_); + while (serialized.size() < serialized_max && !frames_.empty()) { + spdy::SpdySerializedFrame frame = framer_.SerializeFrame(*frames_.front()); + absl::StrAppend(&serialized, absl::string_view(frame)); + frames_.pop_front(); + } + if (serialized.size() > serialized_max) { + serialized_prefix_ = serialized.substr(serialized_max); + serialized.resize(serialized_max); + } + return serialized; +} + +void OgHttp2Session::OnError(http2::Http2DecoderAdapter::SpdyFramerError error, + std::string detailed_error) { + QUICHE_VLOG(1) << "Error: " + << http2::Http2DecoderAdapter::SpdyFramerErrorToString(error) + << " details: " << detailed_error; + visitor_.OnConnectionError(); +} + +void OgHttp2Session::OnCommonHeader(spdy::SpdyStreamId stream_id, + size_t length, + uint8_t type, + uint8_t flags) { + visitor_.OnFrameHeader(stream_id, length, type, flags); +} + +void OgHttp2Session::OnDataFrameHeader(spdy::SpdyStreamId stream_id, + size_t length, + bool fin) { + visitor_.OnBeginDataForStream(stream_id, length); +} + +void OgHttp2Session::OnStreamFrameData(spdy::SpdyStreamId stream_id, + const char* data, + size_t len) { + visitor_.OnDataForStream(stream_id, absl::string_view(data, len)); +} + +void OgHttp2Session::OnStreamEnd(spdy::SpdyStreamId stream_id) { + visitor_.OnEndStream(stream_id); +} + +void OgHttp2Session::OnStreamPadLength(spdy::SpdyStreamId /*stream_id*/, + size_t /*value*/) { + // TODO(181586191): handle padding +} + +void OgHttp2Session::OnStreamPadding(spdy::SpdyStreamId stream_id, size_t len) { + // TODO(181586191): handle padding +} + +spdy::SpdyHeadersHandlerInterface* OgHttp2Session::OnHeaderFrameStart( + spdy::SpdyStreamId stream_id) { + headers_handler_.set_stream_id(stream_id); + return &headers_handler_; +} + +void OgHttp2Session::OnHeaderFrameEnd(spdy::SpdyStreamId stream_id) { + headers_handler_.set_stream_id(0); +} + +void OgHttp2Session::OnRstStream(spdy::SpdyStreamId stream_id, + spdy::SpdyErrorCode error_code) { + visitor_.OnRstStream(stream_id, TranslateErrorCode(error_code)); + visitor_.OnCloseStream(stream_id, TranslateErrorCode(error_code)); +} + +void OgHttp2Session::OnSettings() { + visitor_.OnSettingsStart(); +} + +void OgHttp2Session::OnSetting(spdy::SpdySettingsId id, uint32_t value) { + visitor_.OnSetting({id, value}); +} + +void OgHttp2Session::OnSettingsEnd() { + visitor_.OnSettingsEnd(); +} + +void OgHttp2Session::OnSettingsAck() { + visitor_.OnSettingsAck(); +} + +void OgHttp2Session::OnPing(spdy::SpdyPingId unique_id, bool is_ack) { + visitor_.OnPing(unique_id, is_ack); +} + +void OgHttp2Session::OnGoAway(spdy::SpdyStreamId last_accepted_stream_id, + spdy::SpdyErrorCode error_code) { + received_goaway_ = true; + visitor_.OnGoAway(last_accepted_stream_id, TranslateErrorCode(error_code), + ""); +} + +bool OgHttp2Session::OnGoAwayFrameData(const char* goaway_data, size_t len) { + // Opaque data is currently ignored. + return true; +} + +void OgHttp2Session::OnHeaders(spdy::SpdyStreamId stream_id, + bool has_priority, + int weight, + spdy::SpdyStreamId parent_stream_id, + bool exclusive, + bool fin, + bool end) {} + +void OgHttp2Session::OnWindowUpdate(spdy::SpdyStreamId stream_id, + int delta_window_size) { + if (stream_id == 0) { + peer_window_ += delta_window_size; + } else { + auto it = stream_map_.find(stream_id); + if (it == stream_map_.end()) { + QUICHE_VLOG(1) << "Stream " << stream_id << " not found!"; + } else { + it->second.send_window += delta_window_size; + } + } + visitor_.OnWindowUpdate(stream_id, delta_window_size); +} + +void OgHttp2Session::OnPushPromise(spdy::SpdyStreamId stream_id, + spdy::SpdyStreamId promised_stream_id, + bool end) {} + +void OgHttp2Session::OnContinuation(spdy::SpdyStreamId stream_id, bool end) {} + +void OgHttp2Session::OnAltSvc(spdy::SpdyStreamId /*stream_id*/, + absl::string_view /*origin*/, + const spdy::SpdyAltSvcWireFormat:: + AlternativeServiceVector& /*altsvc_vector*/) { +} + +void OgHttp2Session::OnPriority(spdy::SpdyStreamId stream_id, + spdy::SpdyStreamId parent_stream_id, + int weight, + bool exclusive) {} + +void OgHttp2Session::OnPriorityUpdate(spdy::SpdyStreamId prioritized_stream_id, + absl::string_view priority_field_value) {} + +bool OgHttp2Session::OnUnknownFrame(spdy::SpdyStreamId stream_id, + uint8_t frame_type) { + return true; +} + +} // namespace adapter +} // namespace http2 diff --git a/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_session.h b/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_session.h new file mode 100644 index 00000000000..b0bc28b7002 --- /dev/null +++ b/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_session.h @@ -0,0 +1,141 @@ +#ifndef QUICHE_HTTP2_ADAPTER_OGHTTP2_SESSION_H_ +#define QUICHE_HTTP2_ADAPTER_OGHTTP2_SESSION_H_ + +#include <list> + +#include "http2/adapter/http2_session.h" +#include "http2/adapter/http2_util.h" +#include "http2/adapter/http2_visitor_interface.h" +#include "http2/adapter/window_manager.h" +#include "common/platform/api/quiche_bug_tracker.h" +#include "spdy/core/http2_frame_decoder_adapter.h" +#include "spdy/core/spdy_framer.h" + +namespace http2 { +namespace adapter { + +// This class manages state associated with a single multiplexed HTTP/2 session. +class OgHttp2Session : public Http2Session, + public spdy::SpdyFramerVisitorInterface { + public: + struct Options { + Perspective perspective = Perspective::kClient; + }; + + OgHttp2Session(Http2VisitorInterface& visitor, Options /*options*/); + ~OgHttp2Session() override; + + // Enqueues a frame for transmission to the peer. + void EnqueueFrame(std::unique_ptr<spdy::SpdyFrameIR> frame); + + // If |want_write()| returns true, this method will return a non-empty string + // containing serialized HTTP/2 frames to write to the peer. + std::string GetBytesToWrite(absl::optional<size_t> max_bytes); + + // From Http2Session. + ssize_t ProcessBytes(absl::string_view bytes) override; + int Consume(Http2StreamId stream_id, size_t num_bytes) override; + bool want_read() const override { return !received_goaway_; } + bool want_write() const override { + return !frames_.empty() || !serialized_prefix_.empty(); + } + int GetRemoteWindowSize() const override { + return peer_window_; + } + + // From SpdyFramerVisitorInterface + void OnError(http2::Http2DecoderAdapter::SpdyFramerError error, + std::string detailed_error) override; + void OnCommonHeader(spdy::SpdyStreamId /*stream_id*/, + size_t /*length*/, + uint8_t /*type*/, + uint8_t /*flags*/) override; + void OnDataFrameHeader(spdy::SpdyStreamId stream_id, + size_t length, + bool fin) override; + void OnStreamFrameData(spdy::SpdyStreamId stream_id, + const char* data, + size_t len) override; + void OnStreamEnd(spdy::SpdyStreamId stream_id) override; + void OnStreamPadLength(spdy::SpdyStreamId /*stream_id*/, + size_t /*value*/) override; + void OnStreamPadding(spdy::SpdyStreamId stream_id, size_t len) override; + spdy::SpdyHeadersHandlerInterface* OnHeaderFrameStart( + spdy::SpdyStreamId stream_id) override; + void OnHeaderFrameEnd(spdy::SpdyStreamId stream_id) override; + void OnRstStream(spdy::SpdyStreamId stream_id, + spdy::SpdyErrorCode error_code) override; + void OnSettings() override; + void OnSetting(spdy::SpdySettingsId id, uint32_t value) override; + void OnSettingsEnd() override; + void OnSettingsAck() override; + void OnPing(spdy::SpdyPingId unique_id, bool is_ack) override; + void OnGoAway(spdy::SpdyStreamId last_accepted_stream_id, + spdy::SpdyErrorCode error_code) override; + bool OnGoAwayFrameData(const char* goaway_data, size_t len); + void OnHeaders(spdy::SpdyStreamId stream_id, + bool has_priority, + int weight, + spdy::SpdyStreamId parent_stream_id, + bool exclusive, + bool fin, + bool end) override; + void OnWindowUpdate(spdy::SpdyStreamId stream_id, + int delta_window_size) override; + void OnPushPromise(spdy::SpdyStreamId stream_id, + spdy::SpdyStreamId promised_stream_id, + bool end) override; + void OnContinuation(spdy::SpdyStreamId stream_id, bool end) override; + void OnAltSvc(spdy::SpdyStreamId /*stream_id*/, + absl::string_view /*origin*/, + const spdy::SpdyAltSvcWireFormat:: + AlternativeServiceVector& /*altsvc_vector*/); + void OnPriority(spdy::SpdyStreamId stream_id, + spdy::SpdyStreamId parent_stream_id, + int weight, + bool exclusive) override; + void OnPriorityUpdate(spdy::SpdyStreamId prioritized_stream_id, + absl::string_view priority_field_value) override; + bool OnUnknownFrame(spdy::SpdyStreamId stream_id, + uint8_t frame_type) override; + + private: + struct StreamState { + WindowManager window_manager; + int32_t send_window = 65535; + bool half_closed_local = false; + bool half_closed_remote = false; + }; + + class PassthroughHeadersHandler : public spdy::SpdyHeadersHandlerInterface { + public: + explicit PassthroughHeadersHandler(Http2VisitorInterface& visitor) + : visitor_(visitor) {} + void set_stream_id(Http2StreamId stream_id) { stream_id_ = stream_id; } + void OnHeaderBlockStart() override; + void OnHeader(absl::string_view key, absl::string_view value) override; + void OnHeaderBlockEnd(size_t /* uncompressed_header_bytes */, + size_t /* compressed_header_bytes */) override; + + private: + Http2VisitorInterface& visitor_; + Http2StreamId stream_id_ = 0; + }; + + Http2VisitorInterface& visitor_; + spdy::SpdyFramer framer_{spdy::SpdyFramer::ENABLE_COMPRESSION}; + http2::Http2DecoderAdapter decoder_; + absl::flat_hash_map<Http2StreamId, StreamState> stream_map_; + std::list<std::unique_ptr<spdy::SpdyFrameIR>> frames_; + PassthroughHeadersHandler headers_handler_; + std::string serialized_prefix_; + absl::string_view remaining_preface_; + int peer_window_ = 65535; + Options options_; + bool received_goaway_ = false; +}; + +} // namespace adapter +} // namespace http2 + +#endif // QUICHE_HTTP2_ADAPTER_OGHTTP2_SESSION_H_ diff --git a/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_session_test.cc b/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_session_test.cc new file mode 100644 index 00000000000..ab155697d5d --- /dev/null +++ b/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_session_test.cc @@ -0,0 +1,179 @@ +#include "http2/adapter/oghttp2_session.h" + +#include "http2/adapter/mock_http2_visitor.h" +#include "http2/adapter/test_frame_sequence.h" +#include "common/platform/api/quiche_test.h" + +namespace http2 { +namespace adapter { +namespace test { +namespace { + +using testing::_; + +enum FrameType { + DATA, + HEADERS, + PRIORITY, + RST_STREAM, + SETTINGS, + PUSH_PROMISE, + PING, + GOAWAY, + WINDOW_UPDATE, +}; + +} // namespace + +TEST(OgHttp2SessionTest, ClientConstruction) { + testing::StrictMock<MockHttp2Visitor> visitor; + OgHttp2Session session( + visitor, OgHttp2Session::Options{.perspective = Perspective::kClient}); + EXPECT_TRUE(session.want_read()); + EXPECT_FALSE(session.want_write()); + EXPECT_EQ(session.GetRemoteWindowSize(), kDefaultInitialStreamWindowSize); +} + +TEST(OgHttp2SessionTest, ClientHandlesFrames) { + testing::StrictMock<MockHttp2Visitor> visitor; + OgHttp2Session session( + visitor, OgHttp2Session::Options{.perspective = Perspective::kClient}); + + const std::string initial_frames = TestFrameSequence() + .ServerPreface() + .Ping(42) + .WindowUpdate(0, 1000) + .Serialize(); + testing::InSequence s; + + // Server preface (empty SETTINGS) + EXPECT_CALL(visitor, OnFrameHeader(0, 0, SETTINGS, 0)); + EXPECT_CALL(visitor, OnSettingsStart()); + EXPECT_CALL(visitor, OnSettingsEnd()); + + EXPECT_CALL(visitor, OnFrameHeader(0, 8, PING, 0)); + EXPECT_CALL(visitor, OnPing(42, false)); + EXPECT_CALL(visitor, OnFrameHeader(0, 4, WINDOW_UPDATE, 0)); + EXPECT_CALL(visitor, OnWindowUpdate(0, 1000)); + + const ssize_t initial_result = session.ProcessBytes(initial_frames); + EXPECT_EQ(initial_frames.size(), initial_result); + + EXPECT_EQ(session.GetRemoteWindowSize(), + kDefaultInitialStreamWindowSize + 1000); + + // Should OgHttp2Session require that streams 1 and 3 have been created? + + const std::string stream_frames = + TestFrameSequence() + .Headers(1, + {{":status", "200"}, + {"server", "my-fake-server"}, + {"date", "Tue, 6 Apr 2021 12:54:01 GMT"}}, + /*fin=*/false) + .Data(1, "This is the response body.") + .RstStream(3, Http2ErrorCode::INTERNAL_ERROR) + .GoAway(5, Http2ErrorCode::ENHANCE_YOUR_CALM, "calm down!!") + .Serialize(); + + EXPECT_CALL(visitor, OnFrameHeader(1, _, HEADERS, 4)); + EXPECT_CALL(visitor, OnBeginHeadersForStream(1)); + EXPECT_CALL(visitor, OnHeaderForStream(1, ":status", "200")); + EXPECT_CALL(visitor, OnHeaderForStream(1, "server", "my-fake-server")); + EXPECT_CALL(visitor, + OnHeaderForStream(1, "date", "Tue, 6 Apr 2021 12:54:01 GMT")); + EXPECT_CALL(visitor, OnEndHeadersForStream(1)); + EXPECT_CALL(visitor, OnFrameHeader(1, 26, DATA, 0)); + EXPECT_CALL(visitor, OnBeginDataForStream(1, 26)); + EXPECT_CALL(visitor, OnDataForStream(1, "This is the response body.")); + EXPECT_CALL(visitor, OnFrameHeader(3, 4, RST_STREAM, 0)); + EXPECT_CALL(visitor, OnRstStream(3, Http2ErrorCode::INTERNAL_ERROR)); + EXPECT_CALL(visitor, OnCloseStream(3, Http2ErrorCode::INTERNAL_ERROR)); + EXPECT_CALL(visitor, OnFrameHeader(0, 19, GOAWAY, 0)); + EXPECT_CALL(visitor, OnGoAway(5, Http2ErrorCode::ENHANCE_YOUR_CALM, "")); + const ssize_t stream_result = session.ProcessBytes(stream_frames); + EXPECT_EQ(stream_frames.size(), stream_result); +} + +TEST(OgHttp2SessionTest, ServerConstruction) { + testing::StrictMock<MockHttp2Visitor> visitor; + OgHttp2Session session( + visitor, OgHttp2Session::Options{.perspective = Perspective::kServer}); + EXPECT_TRUE(session.want_read()); + EXPECT_FALSE(session.want_write()); + EXPECT_EQ(session.GetRemoteWindowSize(), kDefaultInitialStreamWindowSize); +} + +TEST(OgHttp2SessionTest, ServerHandlesFrames) { + testing::StrictMock<MockHttp2Visitor> visitor; + OgHttp2Session session( + visitor, OgHttp2Session::Options{.perspective = Perspective::kServer}); + + const std::string frames = TestFrameSequence() + .ClientPreface() + .Ping(42) + .WindowUpdate(0, 1000) + .Headers(1, + {{":method", "POST"}, + {":scheme", "https"}, + {":authority", "example.com"}, + {":path", "/this/is/request/one"}}, + /*fin=*/false) + .WindowUpdate(1, 2000) + .Data(1, "This is the request body.") + .Headers(3, + {{":method", "GET"}, + {":scheme", "http"}, + {":authority", "example.com"}, + {":path", "/this/is/request/two"}}, + /*fin=*/true) + .RstStream(3, Http2ErrorCode::CANCEL) + .Ping(47) + .Serialize(); + testing::InSequence s; + + // Client preface (empty SETTINGS) + EXPECT_CALL(visitor, OnFrameHeader(0, 0, SETTINGS, 0)); + EXPECT_CALL(visitor, OnSettingsStart()); + EXPECT_CALL(visitor, OnSettingsEnd()); + + EXPECT_CALL(visitor, OnFrameHeader(0, 8, PING, 0)); + EXPECT_CALL(visitor, OnPing(42, false)); + EXPECT_CALL(visitor, OnFrameHeader(0, 4, WINDOW_UPDATE, 0)); + EXPECT_CALL(visitor, OnWindowUpdate(0, 1000)); + EXPECT_CALL(visitor, OnFrameHeader(1, _, HEADERS, 4)); + EXPECT_CALL(visitor, OnBeginHeadersForStream(1)); + EXPECT_CALL(visitor, OnHeaderForStream(1, ":method", "POST")); + EXPECT_CALL(visitor, OnHeaderForStream(1, ":scheme", "https")); + EXPECT_CALL(visitor, OnHeaderForStream(1, ":authority", "example.com")); + EXPECT_CALL(visitor, OnHeaderForStream(1, ":path", "/this/is/request/one")); + EXPECT_CALL(visitor, OnEndHeadersForStream(1)); + EXPECT_CALL(visitor, OnFrameHeader(1, 4, WINDOW_UPDATE, 0)); + EXPECT_CALL(visitor, OnWindowUpdate(1, 2000)); + EXPECT_CALL(visitor, OnFrameHeader(1, 25, DATA, 0)); + EXPECT_CALL(visitor, OnBeginDataForStream(1, 25)); + EXPECT_CALL(visitor, OnDataForStream(1, "This is the request body.")); + EXPECT_CALL(visitor, OnFrameHeader(3, _, HEADERS, 5)); + EXPECT_CALL(visitor, OnBeginHeadersForStream(3)); + EXPECT_CALL(visitor, OnHeaderForStream(3, ":method", "GET")); + EXPECT_CALL(visitor, OnHeaderForStream(3, ":scheme", "http")); + EXPECT_CALL(visitor, OnHeaderForStream(3, ":authority", "example.com")); + EXPECT_CALL(visitor, OnHeaderForStream(3, ":path", "/this/is/request/two")); + EXPECT_CALL(visitor, OnEndHeadersForStream(3)); + EXPECT_CALL(visitor, OnEndStream(3)); + EXPECT_CALL(visitor, OnFrameHeader(3, 4, RST_STREAM, 0)); + EXPECT_CALL(visitor, OnRstStream(3, Http2ErrorCode::CANCEL)); + EXPECT_CALL(visitor, OnCloseStream(3, Http2ErrorCode::CANCEL)); + EXPECT_CALL(visitor, OnFrameHeader(0, 8, PING, 0)); + EXPECT_CALL(visitor, OnPing(47, false)); + + const ssize_t result = session.ProcessBytes(frames); + EXPECT_EQ(frames.size(), result); + + EXPECT_EQ(session.GetRemoteWindowSize(), + kDefaultInitialStreamWindowSize + 1000); +} + +} // namespace test +} // namespace adapter +} // namespace http2 diff --git a/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_util.cc b/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_util.cc new file mode 100644 index 00000000000..3ed13dcf46e --- /dev/null +++ b/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_util.cc @@ -0,0 +1,17 @@ +#include "http2/adapter/oghttp2_util.h" + +namespace http2 { +namespace adapter { + +spdy::SpdyHeaderBlock ToHeaderBlock(absl::Span<const Header> headers) { + spdy::SpdyHeaderBlock block; + for (const Header& header : headers) { + absl::string_view name = GetStringView(header.first).first; + absl::string_view value = GetStringView(header.second).first; + block[name] = value; + } + return block; +} + +} // namespace adapter +} // namespace http2 diff --git a/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_util.h b/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_util.h new file mode 100644 index 00000000000..e222c96ccfd --- /dev/null +++ b/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_util.h @@ -0,0 +1,16 @@ +#ifndef QUICHE_HTTP2_ADAPTER_OGHTTP2_UTIL_H_ +#define QUICHE_HTTP2_ADAPTER_OGHTTP2_UTIL_H_ + +#include "absl/types/span.h" +#include "http2/adapter/http2_protocol.h" +#include "spdy/core/spdy_header_block.h" + +namespace http2 { +namespace adapter { + +spdy::SpdyHeaderBlock ToHeaderBlock(absl::Span<const Header> headers); + +} // namespace adapter +} // namespace http2 + +#endif // QUICHE_HTTP2_ADAPTER_OGHTTP2_UTIL_H_ diff --git a/chromium/net/third_party/quiche/src/http2/adapter/recording_http2_visitor.cc b/chromium/net/third_party/quiche/src/http2/adapter/recording_http2_visitor.cc new file mode 100644 index 00000000000..78ec423e25e --- /dev/null +++ b/chromium/net/third_party/quiche/src/http2/adapter/recording_http2_visitor.cc @@ -0,0 +1,155 @@ +#include "http2/adapter/recording_http2_visitor.h" + +#include "absl/strings/str_format.h" +#include "http2/adapter/http2_protocol.h" + +namespace http2 { +namespace adapter { +namespace test { + +void RecordingHttp2Visitor::OnConnectionError() { + events_.push_back("OnConnectionError"); +} + +void RecordingHttp2Visitor::OnFrameHeader(Http2StreamId stream_id, + size_t length, + uint8_t type, + uint8_t flags) { + events_.push_back(absl::StrFormat("OnFrameHeader %d %d %d %d", stream_id, + length, type, flags)); +} + +void RecordingHttp2Visitor::OnSettingsStart() { + events_.push_back("OnSettingsStart"); +} + +void RecordingHttp2Visitor::OnSetting(Http2Setting setting) { + events_.push_back(absl::StrFormat( + "OnSetting %s %d", Http2SettingsIdToString(setting.id), setting.value)); +} + +void RecordingHttp2Visitor::OnSettingsEnd() { + events_.push_back("OnSettingsEnd"); +} + +void RecordingHttp2Visitor::OnSettingsAck() { + events_.push_back("OnSettingsAck"); +} + +void RecordingHttp2Visitor::OnBeginHeadersForStream(Http2StreamId stream_id) { + events_.push_back(absl::StrFormat("OnBeginHeadersForStream %d", stream_id)); +} + +void RecordingHttp2Visitor::OnHeaderForStream(Http2StreamId stream_id, + absl::string_view name, + absl::string_view value) { + events_.push_back( + absl::StrFormat("OnHeaderForStream %d %s %s", stream_id, name, value)); +} + +void RecordingHttp2Visitor::OnEndHeadersForStream(Http2StreamId stream_id) { + events_.push_back(absl::StrFormat("OnEndHeadersForStream %d", stream_id)); +} + +void RecordingHttp2Visitor::OnBeginDataForStream(Http2StreamId stream_id, + size_t payload_length) { + events_.push_back( + absl::StrFormat("OnBeginDataForStream %d %d", stream_id, payload_length)); +} + +void RecordingHttp2Visitor::OnDataForStream(Http2StreamId stream_id, + absl::string_view data) { + events_.push_back(absl::StrFormat("OnDataForStream %d %s", stream_id, data)); +} + +void RecordingHttp2Visitor::OnEndStream(Http2StreamId stream_id) { + events_.push_back(absl::StrFormat("OnEndStream %d", stream_id)); +} + +void RecordingHttp2Visitor::OnRstStream(Http2StreamId stream_id, + Http2ErrorCode error_code) { + events_.push_back(absl::StrFormat("OnRstStream %d %s", stream_id, + Http2ErrorCodeToString(error_code))); +} + +void RecordingHttp2Visitor::OnCloseStream(Http2StreamId stream_id, + Http2ErrorCode error_code) { + events_.push_back(absl::StrFormat("OnCloseStream %d %s", stream_id, + Http2ErrorCodeToString(error_code))); +} + +void RecordingHttp2Visitor::OnPriorityForStream(Http2StreamId stream_id, + Http2StreamId parent_stream_id, + int weight, + bool exclusive) { + events_.push_back(absl::StrFormat("OnPriorityForStream %d %d %d %d", + stream_id, parent_stream_id, weight, + exclusive)); +} + +void RecordingHttp2Visitor::OnPing(Http2PingId ping_id, bool is_ack) { + events_.push_back(absl::StrFormat("OnPing %d %d", ping_id, is_ack)); +} + +void RecordingHttp2Visitor::OnPushPromiseForStream( + Http2StreamId stream_id, + Http2StreamId promised_stream_id) { + events_.push_back(absl::StrFormat("OnPushPromiseForStream %d %d", stream_id, + promised_stream_id)); +} + +void RecordingHttp2Visitor::OnGoAway(Http2StreamId last_accepted_stream_id, + Http2ErrorCode error_code, + absl::string_view opaque_data) { + events_.push_back( + absl::StrFormat("OnGoAway %d %s %s", last_accepted_stream_id, + Http2ErrorCodeToString(error_code), opaque_data)); +} + +void RecordingHttp2Visitor::OnWindowUpdate(Http2StreamId stream_id, + int window_increment) { + events_.push_back( + absl::StrFormat("OnWindowUpdate %d %d", stream_id, window_increment)); +} + +void RecordingHttp2Visitor::OnReadyToSendDataForStream(Http2StreamId stream_id, + char* destination_buffer, + size_t length, + ssize_t* written, + bool* end_stream) { + // TODO(b/181586191): Revisit this. The visitor is expected to write to the + // |destination_buffer| and set the other pointer values appropriately. + events_.push_back( + absl::StrFormat("OnReadyToSendDataForStream %d %d", stream_id, length)); +} + +void RecordingHttp2Visitor::OnReadyToSendMetadataForStream( + Http2StreamId stream_id, + char* buffer, + size_t length, + ssize_t* written) { + // TODO(b/181586191): Revisit this. The visitor is expected to write to the + // |buffer| and set *written appropriately. + events_.push_back(absl::StrFormat("OnReadyToSendMetadataForStream %d %d", + stream_id, length)); +} + +void RecordingHttp2Visitor::OnBeginMetadataForStream(Http2StreamId stream_id, + size_t payload_length) { + events_.push_back(absl::StrFormat("OnBeginMetadataForStream %d %d", stream_id, + payload_length)); +} + +void RecordingHttp2Visitor::OnMetadataForStream(Http2StreamId stream_id, + absl::string_view metadata) { + events_.push_back( + absl::StrFormat("OnMetadataForStream %d %s", stream_id, metadata)); +} + +void RecordingHttp2Visitor::OnMetadataEndForStream(Http2StreamId stream_id) { + events_.push_back(absl::StrFormat("OnMetadataEndForStream %d", stream_id)); +} + +} // namespace test +} // namespace adapter +} // namespace http2 diff --git a/chromium/net/third_party/quiche/src/http2/adapter/recording_http2_visitor.h b/chromium/net/third_party/quiche/src/http2/adapter/recording_http2_visitor.h new file mode 100644 index 00000000000..452b45185cb --- /dev/null +++ b/chromium/net/third_party/quiche/src/http2/adapter/recording_http2_visitor.h @@ -0,0 +1,80 @@ +#ifndef QUICHE_HTTP2_ADAPTER_RECORDING_HTTP2_VISITOR_H_ +#define QUICHE_HTTP2_ADAPTER_RECORDING_HTTP2_VISITOR_H_ + +#include <list> +#include <string> + +#include "http2/adapter/http2_visitor_interface.h" +#include "common/platform/api/quiche_test.h" + +namespace http2 { +namespace adapter { +namespace test { + +// A visitor implementation that records the sequence of callbacks it receives. +class RecordingHttp2Visitor : public Http2VisitorInterface { + public: + using Event = std::string; + using EventSequence = std::list<Event>; + + // From Http2VisitorInterface + void OnConnectionError() override; + void OnFrameHeader(Http2StreamId stream_id, + size_t length, + uint8_t type, + uint8_t flags) override; + void OnSettingsStart() override; + void OnSetting(Http2Setting setting) override; + void OnSettingsEnd() override; + void OnSettingsAck() override; + void OnBeginHeadersForStream(Http2StreamId stream_id) override; + void OnHeaderForStream(Http2StreamId stream_id, + absl::string_view name, + absl::string_view value) override; + void OnEndHeadersForStream(Http2StreamId stream_id) override; + void OnBeginDataForStream(Http2StreamId stream_id, + size_t payload_length) override; + void OnDataForStream(Http2StreamId stream_id, + absl::string_view data) override; + void OnEndStream(Http2StreamId stream_id) override; + void OnRstStream(Http2StreamId stream_id, Http2ErrorCode error_code) override; + void OnCloseStream(Http2StreamId stream_id, + Http2ErrorCode error_code) override; + void OnPriorityForStream(Http2StreamId stream_id, + Http2StreamId parent_stream_id, + int weight, + bool exclusive) override; + void OnPing(Http2PingId ping_id, bool is_ack) override; + void OnPushPromiseForStream(Http2StreamId stream_id, + Http2StreamId promised_stream_id) override; + void OnGoAway(Http2StreamId last_accepted_stream_id, + Http2ErrorCode error_code, + absl::string_view opaque_data) override; + void OnWindowUpdate(Http2StreamId stream_id, int window_increment) override; + void OnReadyToSendDataForStream(Http2StreamId stream_id, + char* destination_buffer, + size_t length, + ssize_t* written, + bool* end_stream) override; + void OnReadyToSendMetadataForStream(Http2StreamId stream_id, + char* buffer, + size_t length, + ssize_t* written) override; + void OnBeginMetadataForStream(Http2StreamId stream_id, + size_t payload_length) override; + void OnMetadataForStream(Http2StreamId stream_id, + absl::string_view metadata) override; + void OnMetadataEndForStream(Http2StreamId stream_id) override; + + const EventSequence& GetEventSequence() const { return events_; } + void Clear() { events_.clear(); } + + private: + EventSequence events_; +}; + +} // namespace test +} // namespace adapter +} // namespace http2 + +#endif // QUICHE_HTTP2_ADAPTER_RECORDING_HTTP2_VISITOR_H_ diff --git a/chromium/net/third_party/quiche/src/http2/adapter/recording_http2_visitor_test.cc b/chromium/net/third_party/quiche/src/http2/adapter/recording_http2_visitor_test.cc new file mode 100644 index 00000000000..8f278d75dcb --- /dev/null +++ b/chromium/net/third_party/quiche/src/http2/adapter/recording_http2_visitor_test.cc @@ -0,0 +1,135 @@ +#include "http2/adapter/recording_http2_visitor.h" + +#include <list> + +#include "http2/adapter/http2_protocol.h" +#include "http2/test_tools/http2_random.h" +#include "common/platform/api/quiche_test.h" + +namespace http2 { +namespace adapter { +namespace test { +namespace { + +using ::testing::IsEmpty; + +TEST(RecordingHttp2VisitorTest, EmptySequence) { + RecordingHttp2Visitor chocolate_visitor; + RecordingHttp2Visitor vanilla_visitor; + + EXPECT_THAT(chocolate_visitor.GetEventSequence(), IsEmpty()); + EXPECT_THAT(vanilla_visitor.GetEventSequence(), IsEmpty()); + EXPECT_EQ(chocolate_visitor.GetEventSequence(), + vanilla_visitor.GetEventSequence()); + + chocolate_visitor.OnSettingsStart(); + + EXPECT_THAT(chocolate_visitor.GetEventSequence(), testing::Not(IsEmpty())); + EXPECT_THAT(vanilla_visitor.GetEventSequence(), IsEmpty()); + EXPECT_NE(chocolate_visitor.GetEventSequence(), + vanilla_visitor.GetEventSequence()); + + chocolate_visitor.Clear(); + + EXPECT_THAT(chocolate_visitor.GetEventSequence(), IsEmpty()); + EXPECT_THAT(vanilla_visitor.GetEventSequence(), IsEmpty()); + EXPECT_EQ(chocolate_visitor.GetEventSequence(), + vanilla_visitor.GetEventSequence()); +} + +TEST(RecordingHttp2VisitorTest, SameEventsProduceSameSequence) { + RecordingHttp2Visitor chocolate_visitor; + RecordingHttp2Visitor vanilla_visitor; + + // Prepare some random values to deliver with the events. + http2::test::Http2Random random; + const Http2StreamId stream_id = random.Uniform(kMaxStreamId); + const Http2StreamId another_stream_id = random.Uniform(kMaxStreamId); + const size_t length = random.Rand16(); + const uint8_t type = random.Rand8(); + const uint8_t flags = random.Rand8(); + const Http2ErrorCode error_code = static_cast<Http2ErrorCode>( + random.Uniform(static_cast<int>(Http2ErrorCode::MAX_ERROR_CODE))); + const Http2Setting setting = {.id = random.Rand16(), + .value = random.Rand32()}; + const absl::string_view alphabet = "abcdefghijklmnopqrstuvwxyz0123456789-"; + const std::string some_string = + random.RandStringWithAlphabet(random.Rand8(), alphabet); + const std::string another_string = + random.RandStringWithAlphabet(random.Rand8(), alphabet); + const uint16_t some_int = random.Rand16(); + const bool some_bool = random.OneIn(2); + + // Send the same arbitrary sequence of events to both visitors. + std::list<RecordingHttp2Visitor*> visitors = {&chocolate_visitor, + &vanilla_visitor}; + for (RecordingHttp2Visitor* visitor : visitors) { + visitor->OnConnectionError(); + visitor->OnFrameHeader(stream_id, length, type, flags); + visitor->OnSettingsStart(); + visitor->OnSetting(setting); + visitor->OnSettingsEnd(); + visitor->OnSettingsAck(); + visitor->OnBeginHeadersForStream(stream_id); + visitor->OnHeaderForStream(stream_id, some_string, another_string); + visitor->OnEndHeadersForStream(stream_id); + visitor->OnBeginDataForStream(stream_id, length); + visitor->OnDataForStream(stream_id, some_string); + visitor->OnDataForStream(stream_id, another_string); + visitor->OnEndStream(stream_id); + visitor->OnRstStream(stream_id, error_code); + visitor->OnCloseStream(stream_id, error_code); + visitor->OnPriorityForStream(stream_id, another_stream_id, some_int, + some_bool); + visitor->OnPing(some_int, some_bool); + visitor->OnPushPromiseForStream(stream_id, another_stream_id); + visitor->OnGoAway(stream_id, error_code, some_string); + visitor->OnWindowUpdate(stream_id, some_int); + visitor->OnReadyToSendDataForStream( + stream_id, /*destination_buffer=*/nullptr, length, /*written=*/nullptr, + /*end_stream=*/nullptr); + visitor->OnReadyToSendMetadataForStream(stream_id, /*buffer=*/nullptr, + length, /*written=*/nullptr); + visitor->OnBeginMetadataForStream(stream_id, length); + visitor->OnMetadataForStream(stream_id, some_string); + visitor->OnMetadataForStream(stream_id, another_string); + visitor->OnMetadataEndForStream(stream_id); + } + + EXPECT_EQ(chocolate_visitor.GetEventSequence(), + vanilla_visitor.GetEventSequence()); +} + +TEST(RecordingHttp2VisitorTest, DifferentEventsProduceDifferentSequence) { + RecordingHttp2Visitor chocolate_visitor; + RecordingHttp2Visitor vanilla_visitor; + EXPECT_EQ(chocolate_visitor.GetEventSequence(), + vanilla_visitor.GetEventSequence()); + + const Http2StreamId stream_id = 1; + const size_t length = 42; + + // Different events with the same method arguments should produce different + // event sequences. + chocolate_visitor.OnBeginDataForStream(stream_id, length); + vanilla_visitor.OnBeginMetadataForStream(stream_id, length); + EXPECT_NE(chocolate_visitor.GetEventSequence(), + vanilla_visitor.GetEventSequence()); + + chocolate_visitor.Clear(); + vanilla_visitor.Clear(); + EXPECT_EQ(chocolate_visitor.GetEventSequence(), + vanilla_visitor.GetEventSequence()); + + // The same events with different method arguments should produce different + // event sequences. + chocolate_visitor.OnBeginHeadersForStream(stream_id); + vanilla_visitor.OnBeginHeadersForStream(stream_id + 2); + EXPECT_NE(chocolate_visitor.GetEventSequence(), + vanilla_visitor.GetEventSequence()); +} + +} // namespace +} // namespace test +} // namespace adapter +} // namespace http2 diff --git a/chromium/net/third_party/quiche/src/http2/adapter/test_frame_sequence.cc b/chromium/net/third_party/quiche/src/http2/adapter/test_frame_sequence.cc index 46d33b61798..7be368ea6a5 100644 --- a/chromium/net/third_party/quiche/src/http2/adapter/test_frame_sequence.cc +++ b/chromium/net/third_party/quiche/src/http2/adapter/test_frame_sequence.cc @@ -1,12 +1,22 @@ #include "http2/adapter/test_frame_sequence.h" #include "http2/adapter/http2_util.h" +#include "http2/adapter/oghttp2_util.h" #include "spdy/core/spdy_framer.h" namespace http2 { namespace adapter { namespace test { +std::vector<const Header> ToHeaders( + absl::Span<const std::pair<absl::string_view, absl::string_view>> headers) { + std::vector<const Header> out; + for (auto [name, value] : headers) { + out.push_back(std::make_pair(HeaderRep(name), HeaderRep(value))); + } + return out; +} + TestFrameSequence& TestFrameSequence::ClientPreface() { preface_ = spdy::kHttp2ConnectionHeaderPrefix; frames_.push_back(absl::make_unique<spdy::SpdySettingsIR>()); @@ -75,6 +85,13 @@ TestFrameSequence& TestFrameSequence::GoAway(Http2StreamId last_good_stream_id, return *this; } +TestFrameSequence& TestFrameSequence::Headers( + Http2StreamId stream_id, + absl::Span<const std::pair<absl::string_view, absl::string_view>> headers, + bool fin) { + return Headers(stream_id, ToHeaders(headers), fin); +} + TestFrameSequence& TestFrameSequence::Headers(Http2StreamId stream_id, spdy::Http2HeaderBlock block, bool fin) { @@ -88,11 +105,7 @@ TestFrameSequence& TestFrameSequence::Headers(Http2StreamId stream_id, TestFrameSequence& TestFrameSequence::Headers(Http2StreamId stream_id, absl::Span<const Header> headers, bool fin) { - spdy::SpdyHeaderBlock block; - for (const Header& header : headers) { - block[header.first] = header.second; - } - return Headers(stream_id, std::move(block), fin); + return Headers(stream_id, ToHeaderBlock(headers), fin); } TestFrameSequence& TestFrameSequence::WindowUpdate(Http2StreamId stream_id, diff --git a/chromium/net/third_party/quiche/src/http2/adapter/test_frame_sequence.h b/chromium/net/third_party/quiche/src/http2/adapter/test_frame_sequence.h index dd110c1a729..cc5e8b5ff57 100644 --- a/chromium/net/third_party/quiche/src/http2/adapter/test_frame_sequence.h +++ b/chromium/net/third_party/quiche/src/http2/adapter/test_frame_sequence.h @@ -12,6 +12,9 @@ namespace http2 { namespace adapter { namespace test { +std::vector<const Header> ToHeaders( + absl::Span<const std::pair<absl::string_view, absl::string_view>> headers); + class TestFrameSequence { public: TestFrameSequence() = default; @@ -30,6 +33,10 @@ class TestFrameSequence { TestFrameSequence& GoAway(Http2StreamId last_good_stream_id, Http2ErrorCode error, absl::string_view payload = ""); + TestFrameSequence& Headers( + Http2StreamId stream_id, + absl::Span<const std::pair<absl::string_view, absl::string_view>> headers, + bool fin = false); TestFrameSequence& Headers(Http2StreamId stream_id, spdy::Http2HeaderBlock block, bool fin = false); diff --git a/chromium/net/third_party/quiche/src/http2/adapter/test_utils.cc b/chromium/net/third_party/quiche/src/http2/adapter/test_utils.cc index 9e1db9954f2..315a28f0717 100644 --- a/chromium/net/third_party/quiche/src/http2/adapter/test_utils.cc +++ b/chromium/net/third_party/quiche/src/http2/adapter/test_utils.cc @@ -1,5 +1,7 @@ #include "http2/adapter/test_utils.h" +#include "http2/adapter/nghttp2_util.h" +#include "common/quiche_endian.h" #include "spdy/core/spdy_frame_reader.h" namespace http2 { @@ -23,17 +25,15 @@ std::vector<std::pair<const char*, std::string>> LogFriendly( return out; } -// Custom gMock matcher, used to determine if a particular type of frame -// is in a string. This is useful in tests where we want to show that a -// particular control frame type is serialized for sending to the peer. +// Custom gMock matcher, used to implement EqualsFrames(). class SpdyControlFrameMatcher - : public testing::MatcherInterface<const std::string> { + : public testing::MatcherInterface<absl::string_view> { public: explicit SpdyControlFrameMatcher( std::vector<TypeAndOptionalLength> types_and_lengths) : expected_types_and_lengths_(std::move(types_and_lengths)) {} - bool MatchAndExplain(const std::string s, + bool MatchAndExplain(absl::string_view s, testing::MatchResultListener* listener) const override { spdy::SpdyFrameReader reader(s.data(), s.size()); @@ -43,6 +43,11 @@ class SpdyControlFrameMatcher return false; } } + if (!reader.IsDoneReading()) { + size_t bytes_remaining = s.size() - reader.GetBytesConsumed(); + *listener << "; " << bytes_remaining << " bytes left to read!"; + return false; + } return true; } @@ -103,15 +108,355 @@ class SpdyControlFrameMatcher const std::vector<TypeAndOptionalLength> expected_types_and_lengths_; }; +// Custom gMock matcher, used to implement HasFrameHeader(). +class FrameHeaderMatcher + : public testing::MatcherInterface<const nghttp2_frame_hd*> { + public: + FrameHeaderMatcher(int32_t streamid, + uint8_t type, + const testing::Matcher<int> flags) + : stream_id_(streamid), type_(type), flags_(flags) {} + + bool MatchAndExplain(const nghttp2_frame_hd* frame, + testing::MatchResultListener* listener) const override { + bool matched = true; + if (stream_id_ != frame->stream_id) { + *listener << "; expected stream " << stream_id_ << ", saw " + << frame->stream_id; + matched = false; + } + if (type_ != frame->type) { + *listener << "; expected frame type " << type_ << ", saw " + << static_cast<int>(frame->type); + matched = false; + } + if (!flags_.MatchAndExplain(frame->flags, listener)) { + matched = false; + } + return matched; + } + + void DescribeTo(std::ostream* os) const override { + *os << "contains a frame header with stream " << stream_id_ << ", type " + << type_ << ", "; + flags_.DescribeTo(os); + } + + void DescribeNegationTo(std::ostream* os) const override { + *os << "does not contain a frame header with stream " << stream_id_ + << ", type " << type_ << ", "; + flags_.DescribeNegationTo(os); + } + + private: + const int32_t stream_id_; + const int type_; + const testing::Matcher<int> flags_; +}; + +class DataMatcher : public testing::MatcherInterface<const nghttp2_frame*> { + public: + DataMatcher(const testing::Matcher<uint32_t> stream_id, + const testing::Matcher<size_t> length, + const testing::Matcher<int> flags) + : stream_id_(stream_id), length_(length), flags_(flags) {} + + bool MatchAndExplain(const nghttp2_frame* frame, + testing::MatchResultListener* listener) const override { + if (frame->hd.type != NGHTTP2_DATA) { + *listener << "; expected DATA frame, saw frame of type " + << static_cast<int>(frame->hd.type); + return false; + } + bool matched = true; + if (!stream_id_.MatchAndExplain(frame->hd.stream_id, listener)) { + matched = false; + } + if (!length_.MatchAndExplain(frame->hd.length, listener)) { + matched = false; + } + if (!flags_.MatchAndExplain(frame->hd.flags, listener)) { + matched = false; + } + return matched; + } + + void DescribeTo(std::ostream* os) const override { + *os << "contains a DATA frame, "; + stream_id_.DescribeTo(os); + length_.DescribeTo(os); + flags_.DescribeTo(os); + } + + void DescribeNegationTo(std::ostream* os) const override { + *os << "does not contain a DATA frame, "; + stream_id_.DescribeNegationTo(os); + length_.DescribeNegationTo(os); + flags_.DescribeNegationTo(os); + } + + private: + const testing::Matcher<uint32_t> stream_id_; + const testing::Matcher<size_t> length_; + const testing::Matcher<int> flags_; +}; + +class HeadersMatcher : public testing::MatcherInterface<const nghttp2_frame*> { + public: + HeadersMatcher(const testing::Matcher<uint32_t> stream_id, + const testing::Matcher<int> flags, + const testing::Matcher<int> category) + : stream_id_(stream_id), flags_(flags), category_(category) {} + + bool MatchAndExplain(const nghttp2_frame* frame, + testing::MatchResultListener* listener) const override { + if (frame->hd.type != NGHTTP2_HEADERS) { + *listener << "; expected HEADERS frame, saw frame of type " + << static_cast<int>(frame->hd.type); + return false; + } + bool matched = true; + if (!stream_id_.MatchAndExplain(frame->hd.stream_id, listener)) { + matched = false; + } + if (!flags_.MatchAndExplain(frame->hd.flags, listener)) { + matched = false; + } + if (!category_.MatchAndExplain(frame->headers.cat, listener)) { + matched = false; + } + return matched; + } + + void DescribeTo(std::ostream* os) const override { + *os << "contains a HEADERS frame, "; + stream_id_.DescribeTo(os); + flags_.DescribeTo(os); + category_.DescribeTo(os); + } + + void DescribeNegationTo(std::ostream* os) const override { + *os << "does not contain a HEADERS frame, "; + stream_id_.DescribeNegationTo(os); + flags_.DescribeNegationTo(os); + category_.DescribeNegationTo(os); + } + + private: + const testing::Matcher<uint32_t> stream_id_; + const testing::Matcher<int> flags_; + const testing::Matcher<int> category_; +}; + +class RstStreamMatcher + : public testing::MatcherInterface<const nghttp2_frame*> { + public: + RstStreamMatcher(const testing::Matcher<uint32_t> stream_id, + const testing::Matcher<uint32_t> error_code) + : stream_id_(stream_id), error_code_(error_code) {} + + bool MatchAndExplain(const nghttp2_frame* frame, + testing::MatchResultListener* listener) const override { + if (frame->hd.type != NGHTTP2_RST_STREAM) { + *listener << "; expected RST_STREAM frame, saw frame of type " + << static_cast<int>(frame->hd.type); + return false; + } + bool matched = true; + if (!stream_id_.MatchAndExplain(frame->hd.stream_id, listener)) { + matched = false; + } + if (!error_code_.MatchAndExplain(frame->rst_stream.error_code, listener)) { + matched = false; + } + return matched; + } + + void DescribeTo(std::ostream* os) const override { + *os << "contains a RST_STREAM frame, "; + stream_id_.DescribeTo(os); + error_code_.DescribeTo(os); + } + + void DescribeNegationTo(std::ostream* os) const override { + *os << "does not contain a RST_STREAM frame, "; + stream_id_.DescribeNegationTo(os); + error_code_.DescribeNegationTo(os); + } + + private: + const testing::Matcher<uint32_t> stream_id_; + const testing::Matcher<uint32_t> error_code_; +}; + +class SettingsMatcher : public testing::MatcherInterface<const nghttp2_frame*> { + public: + SettingsMatcher(const testing::Matcher<std::vector<Http2Setting>> values) + : values_(values) {} + + bool MatchAndExplain(const nghttp2_frame* frame, + testing::MatchResultListener* listener) const override { + if (frame->hd.type != NGHTTP2_SETTINGS) { + *listener << "; expected SETTINGS frame, saw frame of type " + << static_cast<int>(frame->hd.type); + return false; + } + std::vector<Http2Setting> settings; + settings.reserve(frame->settings.niv); + for (int i = 0; i < frame->settings.niv; ++i) { + const auto& p = frame->settings.iv[i]; + settings.push_back({static_cast<uint16_t>(p.settings_id), p.value}); + } + return values_.MatchAndExplain(settings, listener); + } + + void DescribeTo(std::ostream* os) const override { + *os << "contains a SETTINGS frame, "; + values_.DescribeTo(os); + } + + void DescribeNegationTo(std::ostream* os) const override { + *os << "does not contain a SETTINGS frame, "; + values_.DescribeNegationTo(os); + } + + private: + const testing::Matcher<std::vector<Http2Setting>> values_; +}; + +class PingMatcher : public testing::MatcherInterface<const nghttp2_frame*> { + public: + PingMatcher(const testing::Matcher<uint64_t> id, bool is_ack) + : id_(id), is_ack_(is_ack) {} + + bool MatchAndExplain(const nghttp2_frame* frame, + testing::MatchResultListener* listener) const override { + if (frame->hd.type != NGHTTP2_PING) { + *listener << "; expected PING frame, saw frame of type " + << static_cast<int>(frame->hd.type); + return false; + } + bool matched = true; + bool frame_ack = frame->hd.flags & NGHTTP2_FLAG_ACK; + if (is_ack_ != frame_ack) { + *listener << "; expected is_ack=" << is_ack_ << ", saw " << frame_ack; + matched = false; + } + uint64_t data; + std::memcpy(&data, frame->ping.opaque_data, sizeof(data)); + data = quiche::QuicheEndian::HostToNet64(data); + if (!id_.MatchAndExplain(data, listener)) { + matched = false; + } + return matched; + } + + void DescribeTo(std::ostream* os) const override { + *os << "contains a PING frame, "; + id_.DescribeTo(os); + } + + void DescribeNegationTo(std::ostream* os) const override { + *os << "does not contain a PING frame, "; + id_.DescribeNegationTo(os); + } + + private: + const testing::Matcher<uint64_t> id_; + const bool is_ack_; +}; + +class GoAwayMatcher : public testing::MatcherInterface<const nghttp2_frame*> { + public: + GoAwayMatcher(const testing::Matcher<uint32_t> last_stream_id, + const testing::Matcher<uint32_t> error_code, + const testing::Matcher<absl::string_view> opaque_data) + : last_stream_id_(last_stream_id), + error_code_(error_code), + opaque_data_(opaque_data) {} + + bool MatchAndExplain(const nghttp2_frame* frame, + testing::MatchResultListener* listener) const override { + if (frame->hd.type != NGHTTP2_GOAWAY) { + *listener << "; expected GOAWAY frame, saw frame of type " + << static_cast<int>(frame->hd.type); + return false; + } + bool matched = true; + if (!last_stream_id_.MatchAndExplain(frame->goaway.last_stream_id, + listener)) { + matched = false; + } + if (!error_code_.MatchAndExplain(frame->goaway.error_code, listener)) { + matched = false; + } + auto opaque_data = + ToStringView(frame->goaway.opaque_data, frame->goaway.opaque_data_len); + if (!opaque_data_.MatchAndExplain(opaque_data, listener)) { + matched = false; + } + return matched; + } + + void DescribeTo(std::ostream* os) const override { + *os << "contains a GOAWAY frame, "; + last_stream_id_.DescribeTo(os); + error_code_.DescribeTo(os); + opaque_data_.DescribeTo(os); + } + + void DescribeNegationTo(std::ostream* os) const override { + *os << "does not contain a GOAWAY frame, "; + last_stream_id_.DescribeNegationTo(os); + error_code_.DescribeNegationTo(os); + opaque_data_.DescribeNegationTo(os); + } + + private: + const testing::Matcher<uint32_t> last_stream_id_; + const testing::Matcher<uint32_t> error_code_; + const testing::Matcher<absl::string_view> opaque_data_; +}; + +class WindowUpdateMatcher + : public testing::MatcherInterface<const nghttp2_frame*> { + public: + WindowUpdateMatcher(const testing::Matcher<uint32_t> delta) : delta_(delta) {} + + bool MatchAndExplain(const nghttp2_frame* frame, + testing::MatchResultListener* listener) const override { + if (frame->hd.type != NGHTTP2_WINDOW_UPDATE) { + *listener << "; expected WINDOW_UPDATE frame, saw frame of type " + << static_cast<int>(frame->hd.type); + return false; + } + return delta_.MatchAndExplain(frame->window_update.window_size_increment, + listener); + } + + void DescribeTo(std::ostream* os) const override { + *os << "contains a WINDOW_UPDATE frame, "; + delta_.DescribeTo(os); + } + + void DescribeNegationTo(std::ostream* os) const override { + *os << "does not contain a WINDOW_UPDATE frame, "; + delta_.DescribeNegationTo(os); + } + + private: + const testing::Matcher<uint32_t> delta_; +}; + } // namespace -testing::Matcher<const std::string> ContainsFrames( +testing::Matcher<absl::string_view> EqualsFrames( std::vector<std::pair<spdy::SpdyFrameType, absl::optional<size_t>>> types_and_lengths) { return MakeMatcher(new SpdyControlFrameMatcher(std::move(types_and_lengths))); } -testing::Matcher<const std::string> ContainsFrames( +testing::Matcher<absl::string_view> EqualsFrames( std::vector<spdy::SpdyFrameType> types) { std::vector<std::pair<spdy::SpdyFrameType, absl::optional<size_t>>> types_and_lengths; @@ -122,6 +467,61 @@ testing::Matcher<const std::string> ContainsFrames( return MakeMatcher(new SpdyControlFrameMatcher(std::move(types_and_lengths))); } +testing::Matcher<const nghttp2_frame_hd*> HasFrameHeader( + uint32_t streamid, + uint8_t type, + const testing::Matcher<int> flags) { + return MakeMatcher(new FrameHeaderMatcher(streamid, type, flags)); +} + +testing::Matcher<const nghttp2_frame*> IsData( + const testing::Matcher<uint32_t> stream_id, + const testing::Matcher<size_t> length, + const testing::Matcher<int> flags) { + return MakeMatcher(new DataMatcher(stream_id, length, flags)); +} + +testing::Matcher<const nghttp2_frame*> IsHeaders( + const testing::Matcher<uint32_t> stream_id, + const testing::Matcher<int> flags, + const testing::Matcher<int> category) { + return MakeMatcher(new HeadersMatcher(stream_id, flags, category)); +} + +testing::Matcher<const nghttp2_frame*> IsRstStream( + const testing::Matcher<uint32_t> stream_id, + const testing::Matcher<uint32_t> error_code) { + return MakeMatcher(new RstStreamMatcher(stream_id, error_code)); +} + +testing::Matcher<const nghttp2_frame*> IsSettings( + const testing::Matcher<std::vector<Http2Setting>> values) { + return MakeMatcher(new SettingsMatcher(values)); +} + +testing::Matcher<const nghttp2_frame*> IsPing( + const testing::Matcher<uint64_t> id) { + return MakeMatcher(new PingMatcher(id, false)); +} + +testing::Matcher<const nghttp2_frame*> IsPingAck( + const testing::Matcher<uint64_t> id) { + return MakeMatcher(new PingMatcher(id, true)); +} + +testing::Matcher<const nghttp2_frame*> IsGoAway( + const testing::Matcher<uint32_t> last_stream_id, + const testing::Matcher<uint32_t> error_code, + const testing::Matcher<absl::string_view> opaque_data) { + return MakeMatcher( + new GoAwayMatcher(last_stream_id, error_code, opaque_data)); +} + +testing::Matcher<const nghttp2_frame*> IsWindowUpdate( + const testing::Matcher<uint32_t> delta) { + return MakeMatcher(new WindowUpdateMatcher(delta)); +} + } // namespace test } // namespace adapter } // namespace http2 diff --git a/chromium/net/third_party/quiche/src/http2/adapter/test_utils.h b/chromium/net/third_party/quiche/src/http2/adapter/test_utils.h index 6276bf1fe45..ef1ae29a650 100644 --- a/chromium/net/third_party/quiche/src/http2/adapter/test_utils.h +++ b/chromium/net/third_party/quiche/src/http2/adapter/test_utils.h @@ -4,6 +4,10 @@ #include <string> #include <vector> +#include "absl/strings/string_view.h" +#include "http2/adapter/http2_protocol.h" +#include "http2/adapter/mock_http2_visitor.h" +#include "third_party/nghttp2/src/lib/includes/nghttp2/nghttp2.h" #include "common/platform/api/quiche_test.h" #include "spdy/core/spdy_protocol.h" @@ -11,17 +15,68 @@ namespace http2 { namespace adapter { namespace test { -// Matcher that checks whether a string contains HTTP/2 frames of the specified -// ordered sequence of types and lengths. -testing::Matcher<const std::string> ContainsFrames( +class DataSavingVisitor : public testing::StrictMock<MockHttp2Visitor> { + public: + void Save(absl::string_view data) { absl::StrAppend(&data_, data); } + + const std::string& data() { return data_; } + void Clear() { data_.clear(); } + + private: + std::string data_; +}; + +// These matchers check whether a string consists entirely of HTTP/2 frames of +// the specified ordered sequence. This is useful in tests where we want to show +// that one or more particular frame types are serialized for sending to the +// peer. The match will fail if there are input bytes not consumed by the +// matcher. + +// Requires that frames match both types and lengths. +testing::Matcher<absl::string_view> EqualsFrames( std::vector<std::pair<spdy::SpdyFrameType, absl::optional<size_t>>> types_and_lengths); -// Matcher that checks whether a string contains HTTP/2 frames of the specified -// ordered sequence of types. -testing::Matcher<const std::string> ContainsFrames( +// Requires that frames match the specified types. +testing::Matcher<absl::string_view> EqualsFrames( std::vector<spdy::SpdyFrameType> types); +testing::Matcher<const nghttp2_frame_hd*> HasFrameHeader( + uint32_t streamid, + uint8_t type, + const testing::Matcher<int> flags); + +testing::Matcher<const nghttp2_frame*> IsData( + const testing::Matcher<uint32_t> stream_id, + const testing::Matcher<size_t> length, + const testing::Matcher<int> flags); + +testing::Matcher<const nghttp2_frame*> IsHeaders( + const testing::Matcher<uint32_t> stream_id, + const testing::Matcher<int> flags, + const testing::Matcher<int> category); + +testing::Matcher<const nghttp2_frame*> IsRstStream( + const testing::Matcher<uint32_t> stream_id, + const testing::Matcher<uint32_t> error_code); + +testing::Matcher<const nghttp2_frame*> IsSettings( + const testing::Matcher<std::vector<Http2Setting>> values); + +testing::Matcher<const nghttp2_frame*> IsPing( + const testing::Matcher<uint64_t> id); + +testing::Matcher<const nghttp2_frame*> IsPingAck( + const testing::Matcher<uint64_t> id); + +testing::Matcher<const nghttp2_frame*> IsGoAway( + const testing::Matcher<uint32_t> last_stream_id, + const testing::Matcher<uint32_t> error_code, + const testing::Matcher<absl::string_view> opaque_data); + +testing::Matcher<const nghttp2_frame*> IsWindowUpdate( + const testing::Matcher<uint32_t> delta); + } // namespace test } // namespace adapter } // namespace http2 diff --git a/chromium/net/third_party/quiche/src/http2/adapter/test_utils_test.cc b/chromium/net/third_party/quiche/src/http2/adapter/test_utils_test.cc index e8f4ebda350..0de7b28ff6a 100644 --- a/chromium/net/third_party/quiche/src/http2/adapter/test_utils_test.cc +++ b/chromium/net/third_party/quiche/src/http2/adapter/test_utils_test.cc @@ -10,38 +10,37 @@ namespace { using spdy::SpdyFramer; -TEST(ContainsFrames, Empty) { - EXPECT_THAT("", ContainsFrames(std::vector<spdy::SpdyFrameType>{})); +TEST(EqualsFrames, Empty) { + EXPECT_THAT("", EqualsFrames(std::vector<spdy::SpdyFrameType>{})); } -TEST(ContainsFrames, SingleFrameWithLength) { +TEST(EqualsFrames, SingleFrameWithLength) { SpdyFramer framer{SpdyFramer::ENABLE_COMPRESSION}; spdy::SpdyPingIR ping{511}; EXPECT_THAT(framer.SerializeFrame(ping), - ContainsFrames({{spdy::SpdyFrameType::PING, 8}})); + EqualsFrames({{spdy::SpdyFrameType::PING, 8}})); spdy::SpdyWindowUpdateIR window_update{1, 101}; EXPECT_THAT(framer.SerializeFrame(window_update), - ContainsFrames({{spdy::SpdyFrameType::WINDOW_UPDATE, 4}})); + EqualsFrames({{spdy::SpdyFrameType::WINDOW_UPDATE, 4}})); spdy::SpdyDataIR data{3, "Some example data, ha ha!"}; EXPECT_THAT(framer.SerializeFrame(data), - ContainsFrames({{spdy::SpdyFrameType::DATA, 25}})); + EqualsFrames({{spdy::SpdyFrameType::DATA, 25}})); } -TEST(ContainsFrames, SingleFrameWithoutLength) { +TEST(EqualsFrames, SingleFrameWithoutLength) { SpdyFramer framer{SpdyFramer::ENABLE_COMPRESSION}; spdy::SpdyRstStreamIR rst_stream{7, spdy::ERROR_CODE_REFUSED_STREAM}; - EXPECT_THAT( - framer.SerializeFrame(rst_stream), - ContainsFrames({{spdy::SpdyFrameType::RST_STREAM, absl::nullopt}})); + EXPECT_THAT(framer.SerializeFrame(rst_stream), + EqualsFrames({{spdy::SpdyFrameType::RST_STREAM, absl::nullopt}})); spdy::SpdyGoAwayIR goaway{13, spdy::ERROR_CODE_ENHANCE_YOUR_CALM, "Consider taking some deep breaths."}; EXPECT_THAT(framer.SerializeFrame(goaway), - ContainsFrames({{spdy::SpdyFrameType::GOAWAY, absl::nullopt}})); + EqualsFrames({{spdy::SpdyFrameType::GOAWAY, absl::nullopt}})); spdy::Http2HeaderBlock block; block[":method"] = "GET"; @@ -49,10 +48,10 @@ TEST(ContainsFrames, SingleFrameWithoutLength) { block[":authority"] = "example.com"; spdy::SpdyHeadersIR headers{17, std::move(block)}; EXPECT_THAT(framer.SerializeFrame(headers), - ContainsFrames({{spdy::SpdyFrameType::HEADERS, absl::nullopt}})); + EqualsFrames({{spdy::SpdyFrameType::HEADERS, absl::nullopt}})); } -TEST(ContainsFrames, MultipleFrames) { +TEST(EqualsFrames, MultipleFrames) { SpdyFramer framer{SpdyFramer::ENABLE_COMPRESSION}; spdy::SpdyPingIR ping{511}; @@ -74,20 +73,48 @@ TEST(ContainsFrames, MultipleFrames) { absl::string_view(framer.SerializeFrame(rst_stream)), absl::string_view(framer.SerializeFrame(goaway)), absl::string_view(framer.SerializeFrame(headers))); + absl::string_view frame_sequence_view = frame_sequence; + EXPECT_THAT(frame_sequence, + EqualsFrames({{spdy::SpdyFrameType::PING, absl::nullopt}, + {spdy::SpdyFrameType::WINDOW_UPDATE, absl::nullopt}, + {spdy::SpdyFrameType::DATA, 25}, + {spdy::SpdyFrameType::RST_STREAM, absl::nullopt}, + {spdy::SpdyFrameType::GOAWAY, 42}, + {spdy::SpdyFrameType::HEADERS, 19}})); + EXPECT_THAT(frame_sequence_view, + EqualsFrames({{spdy::SpdyFrameType::PING, absl::nullopt}, + {spdy::SpdyFrameType::WINDOW_UPDATE, absl::nullopt}, + {spdy::SpdyFrameType::DATA, 25}, + {spdy::SpdyFrameType::RST_STREAM, absl::nullopt}, + {spdy::SpdyFrameType::GOAWAY, 42}, + {spdy::SpdyFrameType::HEADERS, 19}})); EXPECT_THAT( frame_sequence, - ContainsFrames({{spdy::SpdyFrameType::PING, absl::nullopt}, - {spdy::SpdyFrameType::WINDOW_UPDATE, absl::nullopt}, - {spdy::SpdyFrameType::DATA, 25}, - {spdy::SpdyFrameType::RST_STREAM, absl::nullopt}, - {spdy::SpdyFrameType::GOAWAY, 42}, - {spdy::SpdyFrameType::HEADERS, 19}})); + EqualsFrames( + {spdy::SpdyFrameType::PING, spdy::SpdyFrameType::WINDOW_UPDATE, + spdy::SpdyFrameType::DATA, spdy::SpdyFrameType::RST_STREAM, + spdy::SpdyFrameType::GOAWAY, spdy::SpdyFrameType::HEADERS})); EXPECT_THAT( - frame_sequence, - ContainsFrames( + frame_sequence_view, + EqualsFrames( {spdy::SpdyFrameType::PING, spdy::SpdyFrameType::WINDOW_UPDATE, spdy::SpdyFrameType::DATA, spdy::SpdyFrameType::RST_STREAM, spdy::SpdyFrameType::GOAWAY, spdy::SpdyFrameType::HEADERS})); + + // If the final frame type is removed the expectation fails, as there are + // bytes left to read. + EXPECT_THAT( + frame_sequence, + testing::Not(EqualsFrames( + {spdy::SpdyFrameType::PING, spdy::SpdyFrameType::WINDOW_UPDATE, + spdy::SpdyFrameType::DATA, spdy::SpdyFrameType::RST_STREAM, + spdy::SpdyFrameType::GOAWAY}))); + EXPECT_THAT( + frame_sequence_view, + testing::Not(EqualsFrames( + {spdy::SpdyFrameType::PING, spdy::SpdyFrameType::WINDOW_UPDATE, + spdy::SpdyFrameType::DATA, spdy::SpdyFrameType::RST_STREAM, + spdy::SpdyFrameType::GOAWAY}))); } } // namespace diff --git a/chromium/net/third_party/quiche/src/http2/adapter/window_manager.cc b/chromium/net/third_party/quiche/src/http2/adapter/window_manager.cc index a1b92d5bf2c..de45dc3497b 100644 --- a/chromium/net/third_party/quiche/src/http2/adapter/window_manager.cc +++ b/chromium/net/third_party/quiche/src/http2/adapter/window_manager.cc @@ -2,8 +2,8 @@ #include <utility> +#include "common/platform/api/quiche_bug_tracker.h" #include "common/platform/api/quiche_logging.h" -#include "spdy/platform/api/spdy_bug_tracker.h" namespace http2 { namespace adapter { @@ -20,7 +20,7 @@ void WindowManager::OnWindowSizeLimitChange(const size_t new_limit) { if (new_limit > limit_) { window_ += (new_limit - limit_); } else { - SPDY_BUG(H2 window decrease) + QUICHE_BUG(H2 window decrease) << "Window size limit decrease not currently supported."; } limit_ = new_limit; @@ -56,8 +56,8 @@ void WindowManager::MarkDataFlushed(size_t bytes) { QUICHE_VLOG(2) << "WindowManager@" << this << " buffered: " << buffered_ << " bytes: " << bytes; if (buffered_ < bytes) { - SPDY_BUG(bug_2816_1) << "WindowManager@" << this << " buffered underflow " - << "buffered_: " << buffered_ << " bytes: " << bytes; + QUICHE_BUG(bug_2816_1) << "WindowManager@" << this << " buffered underflow " + << "buffered_: " << buffered_ << " bytes: " << bytes; buffered_ = 0; } else { buffered_ -= bytes; @@ -73,7 +73,6 @@ void WindowManager::MaybeNotifyListener() { } // For the sake of efficiency, we want to send window updates if less than // half of the max quota is available to the peer at any point in time. - // http://google3/gfe/gfe2/stubby/autobahn_fd_wrapper.cc?l=1180-1183&rcl=307416556 const size_t kDesiredMinWindow = limit_ / 2; const size_t kDesiredMinDelta = limit_ / 3; const size_t delta = limit_ - (buffered_ + window_); diff --git a/chromium/net/third_party/quiche/src/http2/adapter/window_manager_test.cc b/chromium/net/third_party/quiche/src/http2/adapter/window_manager_test.cc index 549fd1c3e1a..5e0645365ec 100644 --- a/chromium/net/third_party/quiche/src/http2/adapter/window_manager_test.cc +++ b/chromium/net/third_party/quiche/src/http2/adapter/window_manager_test.cc @@ -5,7 +5,7 @@ #include "absl/functional/bind_front.h" #include "http2/test_tools/http2_random.h" #include "common/platform/api/quiche_test.h" -#include "spdy/platform/api/spdy_test_helpers.h" +#include "common/platform/api/quiche_test_helpers.h" namespace http2 { namespace adapter { @@ -97,13 +97,13 @@ TEST_F(WindowManagerTest, AvoidWindowUnderflow) { TEST_F(WindowManagerTest, AvoidBufferedUnderflow) { EXPECT_EQ(peer_.buffered(), 0); // Don't flush more than has been buffered! - EXPECT_SPDY_BUG(wm_.MarkDataFlushed(1), "buffered underflow"); + EXPECT_QUICHE_BUG(wm_.MarkDataFlushed(1), "buffered underflow"); EXPECT_EQ(peer_.buffered(), 0); wm_.MarkDataBuffered(42); EXPECT_EQ(peer_.buffered(), 42); // Don't flush more than has been buffered! - EXPECT_SPDY_BUG(wm_.MarkDataFlushed(43), "buffered underflow"); + EXPECT_QUICHE_BUG(wm_.MarkDataFlushed(43), "buffered underflow"); EXPECT_EQ(peer_.buffered(), 0); } diff --git a/chromium/net/third_party/quiche/src/spdy/core/http2_priority_write_scheduler.h b/chromium/net/third_party/quiche/src/http2/core/http2_priority_write_scheduler.h index 5820145aac4..b7046e7023a 100644 --- a/chromium/net/third_party/quiche/src/spdy/core/http2_priority_write_scheduler.h +++ b/chromium/net/third_party/quiche/src/http2/core/http2_priority_write_scheduler.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef QUICHE_SPDY_CORE_HTTP2_PRIORITY_WRITE_SCHEDULER_H_ -#define QUICHE_SPDY_CORE_HTTP2_PRIORITY_WRITE_SCHEDULER_H_ +#ifndef QUICHE_HTTP2_CORE_HTTP2_PRIORITY_WRITE_SCHEDULER_H_ +#define QUICHE_HTTP2_CORE_HTTP2_PRIORITY_WRITE_SCHEDULER_H_ #include <cstdint> #include <deque> @@ -17,16 +17,16 @@ #include <utility> #include <vector> +#include "absl/container/flat_hash_map.h" #include "absl/strings/str_cat.h" +#include "http2/core/write_scheduler.h" +#include "common/platform/api/quiche_bug_tracker.h" +#include "common/platform/api/quiche_logging.h" #include "spdy/core/spdy_intrusive_list.h" #include "spdy/core/spdy_protocol.h" -#include "spdy/core/write_scheduler.h" -#include "spdy/platform/api/spdy_bug_tracker.h" -#include "spdy/platform/api/spdy_containers.h" -#include "spdy/platform/api/spdy_logging.h" #include "spdy/platform/api/spdy_string_utils.h" -namespace spdy { +namespace http2 { namespace test { template <typename StreamIdType> @@ -84,13 +84,13 @@ class Http2PriorityWriteScheduler : public WriteScheduler<StreamIdType> { struct StreamInfo; using StreamInfoVector = absl::InlinedVector<StreamInfo*, 4>; - struct StreamInfo : public SpdyIntrusiveLink<StreamInfo> { + struct StreamInfo : public spdy::SpdyIntrusiveLink<StreamInfo> { // ID for this stream. StreamIdType id; // StreamInfo for parent stream. StreamInfo* parent = nullptr; // Weights can range between 1 and 256 (inclusive). - int weight = kHttp2DefaultStreamWeight; + int weight = spdy::kHttp2DefaultStreamWeight; // The total weight of this stream's direct descendants. int total_child_weights = 0; // Pointers to StreamInfos for children, if any. @@ -129,7 +129,7 @@ class Http2PriorityWriteScheduler : public WriteScheduler<StreamIdType> { // Returns the StreamPrecedenceType for this StreamInfo. StreamPrecedenceType ToStreamPrecedence() const { StreamIdType parent_id = - parent == nullptr ? kHttp2RootStreamId : parent->id; + parent == nullptr ? spdy::kHttp2RootStreamId : parent->id; bool exclusive = parent != nullptr && parent->children.size() == 1; return StreamPrecedenceType(parent_id, weight, exclusive); } @@ -178,7 +178,8 @@ class Http2PriorityWriteScheduler : public WriteScheduler<StreamIdType> { // Pointee owned by all_stream_infos_. StreamInfo* root_stream_info_; // Maps from stream IDs to StreamInfo objects. - SpdySmallMap<StreamIdType, std::unique_ptr<StreamInfo>, 10> all_stream_infos_; + absl::flat_hash_map<StreamIdType, std::unique_ptr<StreamInfo>> + all_stream_infos_; // Queue containing all ready streams, ordered with streams of higher // priority before streams of lower priority, and, among streams of equal // priority, streams with lower ordinal before those with higher @@ -186,7 +187,7 @@ class Http2PriorityWriteScheduler : public WriteScheduler<StreamIdType> { // picked as the next stream: some may have ancestor stream(s) that are ready // and unblocked. In these situations the occluded child streams are left in // the queue, to reduce churn. - SpdyIntrusiveList<StreamInfo> scheduling_queue_; + spdy::SpdyIntrusiveList<StreamInfo> scheduling_queue_; // Ordinal value to assign to next node inserted into scheduling_queue_ when // |add_to_front == true|. Decremented after each assignment. int64_t head_ordinal_ = -1; @@ -199,12 +200,12 @@ template <typename StreamIdType> Http2PriorityWriteScheduler<StreamIdType>::Http2PriorityWriteScheduler() { auto root_stream_info = std::make_unique<StreamInfo>(); root_stream_info_ = root_stream_info.get(); - root_stream_info->id = kHttp2RootStreamId; - root_stream_info->weight = kHttp2DefaultStreamWeight; + root_stream_info->id = spdy::kHttp2RootStreamId; + root_stream_info->weight = spdy::kHttp2DefaultStreamWeight; root_stream_info->parent = nullptr; root_stream_info->priority = 1.0; root_stream_info->ready = false; - all_stream_infos_[kHttp2RootStreamId] = std::move(root_stream_info); + all_stream_infos_[spdy::kHttp2RootStreamId] = std::move(root_stream_info); } template <typename StreamIdType> @@ -217,23 +218,23 @@ template <typename StreamIdType> void Http2PriorityWriteScheduler<StreamIdType>::RegisterStream( StreamIdType stream_id, const StreamPrecedenceType& precedence) { - // TODO(mpw): uncomment the SPDY_BUG_IF below once all tests + // TODO(mpw): uncomment the QUICHE_BUG_IF below once all tests // (e.g. SpdyClientDispatcher) modified to pass StreamPrecedence instances // appropriate for protocol version under test. // - // SPDY_BUG_IF(spdy_bug_8_1, precedence.is_spdy3_priority()) + // QUICHE_BUG_IF(spdy_bug_8_1, precedence.is_spdy3_priority()) // << "Expected HTTP/2 stream dependency"; if (StreamRegistered(stream_id)) { - SPDY_BUG(spdy_bug_8_2) << "Stream " << stream_id << " already registered"; + QUICHE_BUG(spdy_bug_8_2) << "Stream " << stream_id << " already registered"; return; } StreamInfo* parent = FindStream(precedence.parent_id()); if (parent == nullptr) { // parent_id may legitimately not be registered yet--see b/15676312. - SPDY_VLOG(1) << "Parent stream " << precedence.parent_id() - << " not registered"; + QUICHE_VLOG(1) << "Parent stream " << precedence.parent_id() + << " not registered"; parent = root_stream_info_; } @@ -271,14 +272,14 @@ void Http2PriorityWriteScheduler<StreamIdType>::RegisterStream( template <typename StreamIdType> void Http2PriorityWriteScheduler<StreamIdType>::UnregisterStream( StreamIdType stream_id) { - if (stream_id == kHttp2RootStreamId) { - SPDY_BUG(spdy_bug_8_3) << "Cannot unregister root stream"; + if (stream_id == spdy::kHttp2RootStreamId) { + QUICHE_BUG(spdy_bug_8_3) << "Cannot unregister root stream"; return; } // Remove the stream from table. auto it = all_stream_infos_.find(stream_id); if (it == all_stream_infos_.end()) { - SPDY_BUG(spdy_bug_8_4) << "Stream " << stream_id << " not registered"; + QUICHE_BUG(spdy_bug_8_4) << "Stream " << stream_id << " not registered"; return; } std::unique_ptr<StreamInfo> stream_info(std::move(it->second)); @@ -321,9 +322,9 @@ Http2PriorityWriteScheduler<StreamIdType>::GetStreamPrecedence( if (stream_info == nullptr) { // Unknown streams tolerated due to b/15676312. However, return lowest // weight. - SPDY_VLOG(1) << "Stream " << stream_id << " not registered"; - return StreamPrecedenceType(kHttp2RootStreamId, kHttp2MinStreamWeight, - false); + QUICHE_VLOG(1) << "Stream " << stream_id << " not registered"; + return StreamPrecedenceType(spdy::kHttp2RootStreamId, + spdy::kHttp2MinStreamWeight, false); } return stream_info->ToStreamPrecedence(); } @@ -335,7 +336,7 @@ Http2PriorityWriteScheduler<StreamIdType>::GetStreamChildren( std::vector<StreamIdType> child_vec; const StreamInfo* stream_info = FindStream(stream_id); if (stream_info == nullptr) { - SPDY_BUG(spdy_bug_8_5) << "Stream " << stream_id << " not registered"; + QUICHE_BUG(spdy_bug_8_5) << "Stream " << stream_id << " not registered"; } else { child_vec.reserve(stream_info->children.size()); for (StreamInfo* child : stream_info->children) { @@ -349,21 +350,21 @@ template <typename StreamIdType> void Http2PriorityWriteScheduler<StreamIdType>::UpdateStreamPrecedence( StreamIdType stream_id, const StreamPrecedenceType& precedence) { - // TODO(mpw): uncomment the SPDY_BUG_IF below once all tests + // TODO(mpw): uncomment the QUICHE_BUG_IF below once all tests // (e.g. SpdyClientDispatcher) modified to pass StreamPrecedence instances // appropriate for protocol version under test. // - // SPDY_BUG_IF(spdy_bug_8_6, precedence.is_spdy3_priority()) + // QUICHE_BUG_IF(spdy_bug_8_6, precedence.is_spdy3_priority()) // << "Expected HTTP/2 stream dependency"; - if (stream_id == kHttp2RootStreamId) { - SPDY_BUG(spdy_bug_8_7) << "Cannot set precedence of root stream"; + if (stream_id == spdy::kHttp2RootStreamId) { + QUICHE_BUG(spdy_bug_8_7) << "Cannot set precedence of root stream"; return; } StreamInfo* stream_info = FindStream(stream_id); if (stream_info == nullptr) { // TODO(mpw): add to all_stream_infos_ on demand--see b/15676312. - SPDY_VLOG(1) << "Stream " << stream_id << " not registered"; + QUICHE_VLOG(1) << "Stream " << stream_id << " not registered"; return; } UpdateStreamParent(stream_info, precedence.parent_id(), @@ -393,13 +394,13 @@ void Http2PriorityWriteScheduler<StreamIdType>::UpdateStreamParent( StreamIdType parent_id, bool exclusive) { if (stream_info->id == parent_id) { - SPDY_BUG(spdy_bug_8_8) << "Cannot set stream to be its own parent"; + QUICHE_BUG(spdy_bug_8_8) << "Cannot set stream to be its own parent"; return; } StreamInfo* new_parent = FindStream(parent_id); if (new_parent == nullptr) { // parent_id may legitimately not be registered yet--see b/15676312. - SPDY_VLOG(1) << "Parent stream " << parent_id << " not registered"; + QUICHE_VLOG(1) << "Parent stream " << parent_id << " not registered"; return; } @@ -456,13 +457,13 @@ template <typename StreamIdType> void Http2PriorityWriteScheduler<StreamIdType>::RecordStreamEventTime( StreamIdType stream_id, int64_t now_in_usec) { - if (stream_id == kHttp2RootStreamId) { - SPDY_BUG(spdy_bug_8_9) << "Cannot record event time for root stream"; + if (stream_id == spdy::kHttp2RootStreamId) { + QUICHE_BUG(spdy_bug_8_9) << "Cannot record event time for root stream"; return; } StreamInfo* stream_info = FindStream(stream_id); if (stream_info == nullptr) { - SPDY_BUG(spdy_bug_8_10) << "Stream " << stream_id << " not registered"; + QUICHE_BUG(spdy_bug_8_10) << "Stream " << stream_id << " not registered"; return; } stream_info->last_event_time_usec = now_in_usec; @@ -476,13 +477,13 @@ void Http2PriorityWriteScheduler<StreamIdType>::RecordStreamEventTime( template <typename StreamIdType> int64_t Http2PriorityWriteScheduler<StreamIdType>::GetLatestEventWithPrecedence( StreamIdType stream_id) const { - if (stream_id == kHttp2RootStreamId) { - SPDY_BUG(spdy_bug_8_11) << "Invalid argument: root stream"; + if (stream_id == spdy::kHttp2RootStreamId) { + QUICHE_BUG(spdy_bug_8_11) << "Invalid argument: root stream"; return 0; } const StreamInfo* stream_info = FindStream(stream_id); if (stream_info == nullptr) { - SPDY_BUG(spdy_bug_8_12) << "Stream " << stream_id << " not registered"; + QUICHE_BUG(spdy_bug_8_12) << "Stream " << stream_id << " not registered"; return 0; } int64_t last_event_time_usec = 0; @@ -502,13 +503,13 @@ int64_t Http2PriorityWriteScheduler<StreamIdType>::GetLatestEventWithPrecedence( template <typename StreamIdType> bool Http2PriorityWriteScheduler<StreamIdType>::ShouldYield( StreamIdType stream_id) const { - if (stream_id == kHttp2RootStreamId) { - SPDY_BUG(spdy_bug_8_13) << "Invalid argument: root stream"; + if (stream_id == spdy::kHttp2RootStreamId) { + QUICHE_BUG(spdy_bug_8_13) << "Invalid argument: root stream"; return false; } const StreamInfo* stream_info = FindStream(stream_id); if (stream_info == nullptr) { - SPDY_BUG(spdy_bug_8_14) << "Stream " << stream_id << " not registered"; + QUICHE_BUG(spdy_bug_8_14) << "Stream " << stream_id << " not registered"; return false; } if (HasReadyAncestor(*stream_info)) { @@ -533,13 +534,13 @@ template <typename StreamIdType> void Http2PriorityWriteScheduler<StreamIdType>::MarkStreamReady( StreamIdType stream_id, bool add_to_front) { - if (stream_id == kHttp2RootStreamId) { - SPDY_BUG(spdy_bug_8_15) << "Cannot mark root stream ready"; + if (stream_id == spdy::kHttp2RootStreamId) { + QUICHE_BUG(spdy_bug_8_15) << "Cannot mark root stream ready"; return; } StreamInfo* stream_info = FindStream(stream_id); if (stream_info == nullptr) { - SPDY_BUG(spdy_bug_8_16) << "Stream " << stream_id << " not registered"; + QUICHE_BUG(spdy_bug_8_16) << "Stream " << stream_id << " not registered"; return; } if (stream_info->ready) { @@ -552,13 +553,13 @@ void Http2PriorityWriteScheduler<StreamIdType>::MarkStreamReady( template <typename StreamIdType> void Http2PriorityWriteScheduler<StreamIdType>::MarkStreamNotReady( StreamIdType stream_id) { - if (stream_id == kHttp2RootStreamId) { - SPDY_BUG(spdy_bug_8_17) << "Cannot mark root stream unready"; + if (stream_id == spdy::kHttp2RootStreamId) { + QUICHE_BUG(spdy_bug_8_17) << "Cannot mark root stream unready"; return; } StreamInfo* stream_info = FindStream(stream_id); if (stream_info == nullptr) { - SPDY_BUG(spdy_bug_8_18) << "Stream " << stream_id << " not registered"; + QUICHE_BUG(spdy_bug_8_18) << "Stream " << stream_id << " not registered"; return; } if (!stream_info->ready) { @@ -680,10 +681,11 @@ Http2PriorityWriteScheduler<StreamIdType>::PopNextReadyStreamAndPrecedence() { return std::make_tuple(stream_info.id, stream_info.ToStreamPrecedence()); } } - SPDY_BUG(spdy_bug_8_19) << "No ready streams"; + QUICHE_BUG(spdy_bug_8_19) << "No ready streams"; return std::make_tuple( - kHttp2RootStreamId, - StreamPrecedenceType(kHttp2RootStreamId, kHttp2MinStreamWeight, false)); + spdy::kHttp2RootStreamId, + StreamPrecedenceType(spdy::kHttp2RootStreamId, + spdy::kHttp2MinStreamWeight, false)); } template <typename StreamIdType> @@ -694,13 +696,13 @@ size_t Http2PriorityWriteScheduler<StreamIdType>::NumReadyStreams() const { template <typename StreamIdType> bool Http2PriorityWriteScheduler<StreamIdType>::IsStreamReady( StreamIdType stream_id) const { - if (stream_id == kHttp2RootStreamId) { - SPDY_BUG(spdy_bug_8_20) << "Try to check whether root stream is ready"; + if (stream_id == spdy::kHttp2RootStreamId) { + QUICHE_BUG(spdy_bug_8_20) << "Try to check whether root stream is ready"; return false; } const StreamInfo* stream_info = FindStream(stream_id); if (stream_info == nullptr) { - SPDY_BUG(spdy_bug_8_21) << "Stream " << stream_id << " not registered"; + QUICHE_BUG(spdy_bug_8_21) << "Stream " << stream_id << " not registered"; return false; } return stream_info->ready; @@ -732,18 +734,18 @@ bool Http2PriorityWriteScheduler<StreamIdType>::ValidateInvariantsForTests() // Verify each StreamInfo mapped under the proper stream ID. if (stream_id != stream_info.id) { - SPDY_DLOG(INFO) << "Stream ID " << stream_id - << " maps to StreamInfo with ID " << stream_info.id; + QUICHE_DLOG(INFO) << "Stream ID " << stream_id + << " maps to StreamInfo with ID " << stream_info.id; return false; } // All streams except the root should have a parent, and should appear in // the children of that parent. - if (stream_info.id != kHttp2RootStreamId && + if (stream_info.id != spdy::kHttp2RootStreamId && !StreamHasChild(*stream_info.parent, &stream_info)) { - SPDY_DLOG(INFO) << "Parent stream " << stream_info.parent->id - << " is not registered, or does not list stream " - << stream_info.id << " as its child."; + QUICHE_DLOG(INFO) << "Parent stream " << stream_info.parent->id + << " is not registered, or does not list stream " + << stream_info.id << " as its child."; return false; } @@ -755,20 +757,19 @@ bool Http2PriorityWriteScheduler<StreamIdType>::ValidateInvariantsForTests() // Each stream in the list should exist and should have this stream // set as its parent. if (!StreamRegistered(child->id) || child->parent != &stream_info) { - SPDY_DLOG(INFO) << "Child stream " << child->id - << " is not registered, " - << "or does not list " << stream_info.id - << " as its parent."; + QUICHE_DLOG(INFO) + << "Child stream " << child->id << " is not registered, " + << "or does not list " << stream_info.id << " as its parent."; return false; } total_child_weights += child->weight; } // Verify that total_child_weights is correct. if (total_child_weights != stream_info.total_child_weights) { - SPDY_DLOG(INFO) << "Child weight totals do not agree. For stream " - << stream_info.id << " total_child_weights has value " - << stream_info.total_child_weights << ", expected " - << total_child_weights; + QUICHE_DLOG(INFO) << "Child weight totals do not agree. For stream " + << stream_info.id << " total_child_weights has value " + << stream_info.total_child_weights << ", expected " + << total_child_weights; return false; } } @@ -777,7 +778,7 @@ bool Http2PriorityWriteScheduler<StreamIdType>::ValidateInvariantsForTests() // Make sure NumRegisteredStreams() reflects the total number of streams the // map contains. if (total_streams != NumRegisteredStreams()) { - SPDY_DLOG(INFO) << "Map contains incorrect number of streams."; + QUICHE_DLOG(INFO) << "Map contains incorrect number of streams."; return false; } // Validate the validation function; we should have visited each stream twice @@ -786,6 +787,6 @@ bool Http2PriorityWriteScheduler<StreamIdType>::ValidateInvariantsForTests() return true; } -} // namespace spdy +} // namespace http2 -#endif // QUICHE_SPDY_CORE_HTTP2_PRIORITY_WRITE_SCHEDULER_H_ +#endif // QUICHE_HTTP2_CORE_HTTP2_PRIORITY_WRITE_SCHEDULER_H_ diff --git a/chromium/net/third_party/quiche/src/spdy/core/http2_priority_write_scheduler_test.cc b/chromium/net/third_party/quiche/src/http2/core/http2_priority_write_scheduler_test.cc index 7c9c2595811..7f086190eeb 100644 --- a/chromium/net/third_party/quiche/src/spdy/core/http2_priority_write_scheduler_test.cc +++ b/chromium/net/third_party/quiche/src/http2/core/http2_priority_write_scheduler_test.cc @@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "spdy/core/http2_priority_write_scheduler.h" +#include "http2/core/http2_priority_write_scheduler.h" #include <initializer_list> #include "common/platform/api/quiche_test.h" -#include "spdy/platform/api/spdy_test_helpers.h" +#include "common/platform/api/quiche_test_helpers.h" using ::testing::AssertionFailure; using ::testing::AssertionResult; @@ -16,10 +16,15 @@ using ::testing::ElementsAre; using ::testing::IsEmpty; using ::testing::UnorderedElementsAre; -namespace spdy { - +namespace http2 { namespace test { +using ::spdy::kHttp2MaxStreamWeight; +using ::spdy::kHttp2MinStreamWeight; +using ::spdy::kHttp2RootStreamId; +using ::spdy::kV3LowestPriority; +using ::spdy::SpdyStreamPrecedence; + template <typename StreamIdType> class Http2PriorityWriteSchedulerPeer { public: @@ -63,7 +68,7 @@ TEST_F(Http2PriorityWriteSchedulerTest, RegisterAndUnregisterStreams) { scheduler_.RegisterStream(5, SpdyStreamPrecedence(0, 50, false)); // Should not be able to add a stream with an id that already exists. - EXPECT_SPDY_BUG( + EXPECT_QUICHE_BUG( scheduler_.RegisterStream(5, SpdyStreamPrecedence(1, 50, false)), "Stream 5 already registered"); EXPECT_EQ(3u, scheduler_.NumRegisteredStreams()); @@ -82,7 +87,7 @@ TEST_F(Http2PriorityWriteSchedulerTest, RegisterAndUnregisterStreams) { scheduler_.UnregisterStream(5); // Cannot remove a stream that has already been removed. - EXPECT_SPDY_BUG(scheduler_.UnregisterStream(5), "Stream 5 not registered"); + EXPECT_QUICHE_BUG(scheduler_.UnregisterStream(5), "Stream 5 not registered"); EXPECT_EQ(3u, scheduler_.NumRegisteredStreams()); EXPECT_TRUE(scheduler_.StreamRegistered(1)); EXPECT_FALSE(scheduler_.StreamRegistered(5)); @@ -94,7 +99,7 @@ TEST_F(Http2PriorityWriteSchedulerTest, RegisterAndUnregisterStreams) { EXPECT_TRUE(scheduler_.StreamRegistered(7)); EXPECT_EQ(0u, scheduler_.GetStreamPrecedence(7).parent_id()); // Now stream 7 already exists, so this should fail: - EXPECT_SPDY_BUG( + EXPECT_QUICHE_BUG( scheduler_.RegisterStream(7, SpdyStreamPrecedence(1, 70, false)), "Stream 7 already registered"); // Try adding a second child to stream 13: @@ -116,8 +121,8 @@ TEST_F(Http2PriorityWriteSchedulerTest, RegisterStreamWithSpdy3Priority) { EXPECT_EQ(kHttp2RootStreamId, scheduler_.GetStreamPrecedence(1).parent_id()); EXPECT_THAT(scheduler_.GetStreamChildren(1), IsEmpty()); - EXPECT_SPDY_BUG(scheduler_.RegisterStream(1, SpdyStreamPrecedence(4)), - "Stream 1 already registered"); + EXPECT_QUICHE_BUG(scheduler_.RegisterStream(1, SpdyStreamPrecedence(4)), + "Stream 1 already registered"); EXPECT_EQ(3, scheduler_.GetStreamPrecedence(1).spdy3_priority()); } @@ -156,20 +161,20 @@ TEST_F(Http2PriorityWriteSchedulerTest, GetStreamParent) { } TEST_F(Http2PriorityWriteSchedulerTest, GetStreamChildren) { - EXPECT_SPDY_BUG(EXPECT_THAT(scheduler_.GetStreamChildren(7), IsEmpty()), - "Stream 7 not registered"); + EXPECT_QUICHE_BUG(EXPECT_THAT(scheduler_.GetStreamChildren(7), IsEmpty()), + "Stream 7 not registered"); scheduler_.RegisterStream(7, SpdyStreamPrecedence(0, 70, false)); EXPECT_THAT(scheduler_.GetStreamChildren(7), IsEmpty()); scheduler_.RegisterStream(9, SpdyStreamPrecedence(7, 90, false)); scheduler_.RegisterStream(15, SpdyStreamPrecedence(7, 150, false)); EXPECT_THAT(scheduler_.GetStreamChildren(7), UnorderedElementsAre(9, 15)); scheduler_.UnregisterStream(7); - EXPECT_SPDY_BUG(EXPECT_THAT(scheduler_.GetStreamChildren(7), IsEmpty()), - "Stream 7 not registered"); + EXPECT_QUICHE_BUG(EXPECT_THAT(scheduler_.GetStreamChildren(7), IsEmpty()), + "Stream 7 not registered"); } TEST_F(Http2PriorityWriteSchedulerTest, UpdateStreamWeight) { - EXPECT_SPDY_BUG( + EXPECT_QUICHE_BUG( scheduler_.UpdateStreamPrecedence(0, SpdyStreamPrecedence(0, 10, false)), "Cannot set precedence of root stream"); @@ -184,11 +189,11 @@ TEST_F(Http2PriorityWriteSchedulerTest, UpdateStreamWeight) { EXPECT_EQ(20, scheduler_.GetStreamPrecedence(3).weight()); ASSERT_TRUE(peer_.ValidateInvariants()); - EXPECT_SPDY_BUG( + EXPECT_QUICHE_BUG( scheduler_.UpdateStreamPrecedence(3, SpdyStreamPrecedence(0, 500, false)), "Invalid weight: 500"); EXPECT_EQ(kHttp2MaxStreamWeight, scheduler_.GetStreamPrecedence(3).weight()); - EXPECT_SPDY_BUG( + EXPECT_QUICHE_BUG( scheduler_.UpdateStreamPrecedence(3, SpdyStreamPrecedence(0, 0, false)), "Invalid weight: 0"); EXPECT_EQ(kHttp2MinStreamWeight, scheduler_.GetStreamPrecedence(3).weight()); @@ -569,10 +574,10 @@ TEST_F(Http2PriorityWriteSchedulerTest, UpdateStreamParentToParent) { TEST_F(Http2PriorityWriteSchedulerTest, UpdateStreamParentToSelf) { scheduler_.RegisterStream(1, SpdyStreamPrecedence(0, 100, false)); - EXPECT_SPDY_BUG( + EXPECT_QUICHE_BUG( scheduler_.UpdateStreamPrecedence(1, SpdyStreamPrecedence(1, 100, false)), "Cannot set stream to be its own parent"); - EXPECT_SPDY_BUG( + EXPECT_QUICHE_BUG( scheduler_.UpdateStreamPrecedence(1, SpdyStreamPrecedence(1, 100, true)), "Cannot set stream to be its own parent"); EXPECT_THAT(scheduler_.GetStreamChildren(0), ElementsAre(1)); @@ -661,7 +666,7 @@ TEST_F(Http2PriorityWriteSchedulerTest, HasReadyStreams) { scheduler_.UnregisterStream(1); EXPECT_FALSE(scheduler_.HasReadyStreams()); ASSERT_TRUE(peer_.ValidateInvariants()); - EXPECT_SPDY_BUG(scheduler_.IsStreamReady(1), "Stream 1 not registered"); + EXPECT_QUICHE_BUG(scheduler_.IsStreamReady(1), "Stream 1 not registered"); } TEST_F(Http2PriorityWriteSchedulerTest, CalculateRoundedWeights) { @@ -699,10 +704,10 @@ TEST_F(Http2PriorityWriteSchedulerTest, CalculateRoundedWeights) { } TEST_F(Http2PriorityWriteSchedulerTest, GetLatestEventWithPrecedence) { - EXPECT_SPDY_BUG(scheduler_.RecordStreamEventTime(3, 5), - "Stream 3 not registered"); - EXPECT_SPDY_BUG(EXPECT_EQ(0, scheduler_.GetLatestEventWithPrecedence(4)), - "Stream 4 not registered"); + EXPECT_QUICHE_BUG(scheduler_.RecordStreamEventTime(3, 5), + "Stream 3 not registered"); + EXPECT_QUICHE_BUG(EXPECT_EQ(0, scheduler_.GetLatestEventWithPrecedence(4)), + "Stream 4 not registered"); for (int i = 1; i < 5; ++i) { int weight = SpdyStreamPrecedence(i).weight(); @@ -962,4 +967,4 @@ TEST_F(PopNextReadyStreamTest, ScatteredBlocked) { } } // namespace test -} // namespace spdy +} // namespace http2 diff --git a/chromium/net/third_party/quiche/src/spdy/core/priority_write_scheduler.h b/chromium/net/third_party/quiche/src/http2/core/priority_write_scheduler.h index fde9a286ed5..b59e294e899 100644 --- a/chromium/net/third_party/quiche/src/spdy/core/priority_write_scheduler.h +++ b/chromium/net/third_party/quiche/src/http2/core/priority_write_scheduler.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef QUICHE_SPDY_CORE_PRIORITY_WRITE_SCHEDULER_H_ -#define QUICHE_SPDY_CORE_PRIORITY_WRITE_SCHEDULER_H_ +#ifndef QUICHE_HTTP2_CORE_PRIORITY_WRITE_SCHEDULER_H_ +#define QUICHE_HTTP2_CORE_PRIORITY_WRITE_SCHEDULER_H_ #include <algorithm> #include <cstddef> @@ -16,12 +16,12 @@ #include <vector> #include "absl/strings/str_cat.h" +#include "http2/core/write_scheduler.h" +#include "common/platform/api/quiche_bug_tracker.h" +#include "common/platform/api/quiche_logging.h" #include "spdy/core/spdy_protocol.h" -#include "spdy/core/write_scheduler.h" -#include "spdy/platform/api/spdy_bug_tracker.h" -#include "spdy/platform/api/spdy_logging.h" -namespace spdy { +namespace http2 { namespace test { template <typename StreamIdType> @@ -44,7 +44,7 @@ class PriorityWriteScheduler : public WriteScheduler<StreamIdType> { using typename WriteScheduler<StreamIdType>::StreamPrecedenceType; // Creates scheduler with no streams. - PriorityWriteScheduler() : PriorityWriteScheduler(kHttp2RootStreamId) {} + PriorityWriteScheduler() : PriorityWriteScheduler(spdy::kHttp2RootStreamId) {} explicit PriorityWriteScheduler(StreamIdType root_stream_id) : root_stream_id_(root_stream_id) {} @@ -56,26 +56,26 @@ class PriorityWriteScheduler : public WriteScheduler<StreamIdType> { // parent_id not used here, but may as well validate it. However, // parent_id may legitimately not be registered yet--see b/15676312. StreamIdType parent_id = precedence.parent_id(); - SPDY_DVLOG_IF(1, - parent_id != root_stream_id_ && !StreamRegistered(parent_id)) + QUICHE_DVLOG_IF( + 1, parent_id != root_stream_id_ && !StreamRegistered(parent_id)) << "Parent stream " << parent_id << " not registered"; if (stream_id == root_stream_id_) { - SPDY_BUG(spdy_bug_19_1) + QUICHE_BUG(spdy_bug_19_1) << "Stream " << root_stream_id_ << " already registered"; return; } StreamInfo stream_info = {precedence.spdy3_priority(), stream_id, false}; bool inserted = stream_infos_.insert(std::make_pair(stream_id, stream_info)).second; - SPDY_BUG_IF(spdy_bug_19_2, !inserted) + QUICHE_BUG_IF(spdy_bug_19_2, !inserted) << "Stream " << stream_id << " already registered"; } void UnregisterStream(StreamIdType stream_id) override { auto it = stream_infos_.find(stream_id); if (it == stream_infos_.end()) { - SPDY_BUG(spdy_bug_19_3) << "Stream " << stream_id << " not registered"; + QUICHE_BUG(spdy_bug_19_3) << "Stream " << stream_id << " not registered"; return; } StreamInfo& stream_info = it->second; @@ -95,8 +95,8 @@ class PriorityWriteScheduler : public WriteScheduler<StreamIdType> { StreamIdType stream_id) const override { auto it = stream_infos_.find(stream_id); if (it == stream_infos_.end()) { - SPDY_DVLOG(1) << "Stream " << stream_id << " not registered"; - return StreamPrecedenceType(kV3LowestPriority); + QUICHE_DVLOG(1) << "Stream " << stream_id << " not registered"; + return StreamPrecedenceType(spdy::kV3LowestPriority); } return StreamPrecedenceType(it->second.priority); } @@ -109,18 +109,18 @@ class PriorityWriteScheduler : public WriteScheduler<StreamIdType> { // parent_id not used here, but may as well validate it. However, // parent_id may legitimately not be registered yet--see b/15676312. StreamIdType parent_id = precedence.parent_id(); - SPDY_DVLOG_IF(1, - parent_id != root_stream_id_ && !StreamRegistered(parent_id)) + QUICHE_DVLOG_IF( + 1, parent_id != root_stream_id_ && !StreamRegistered(parent_id)) << "Parent stream " << parent_id << " not registered"; auto it = stream_infos_.find(stream_id); if (it == stream_infos_.end()) { // TODO(mpw): add to stream_infos_ on demand--see b/15676312. - SPDY_DVLOG(1) << "Stream " << stream_id << " not registered"; + QUICHE_DVLOG(1) << "Stream " << stream_id << " not registered"; return; } StreamInfo& stream_info = it->second; - SpdyPriority new_priority = precedence.spdy3_priority(); + spdy::SpdyPriority new_priority = precedence.spdy3_priority(); if (stream_info.priority == new_priority) { return; } @@ -143,7 +143,7 @@ class PriorityWriteScheduler : public WriteScheduler<StreamIdType> { int64_t now_in_usec) override { auto it = stream_infos_.find(stream_id); if (it == stream_infos_.end()) { - SPDY_BUG(spdy_bug_19_4) << "Stream " << stream_id << " not registered"; + QUICHE_BUG(spdy_bug_19_4) << "Stream " << stream_id << " not registered"; return; } PriorityInfo& priority_info = priority_infos_[it->second.priority]; @@ -154,12 +154,13 @@ class PriorityWriteScheduler : public WriteScheduler<StreamIdType> { int64_t GetLatestEventWithPrecedence(StreamIdType stream_id) const override { auto it = stream_infos_.find(stream_id); if (it == stream_infos_.end()) { - SPDY_BUG(spdy_bug_19_5) << "Stream " << stream_id << " not registered"; + QUICHE_BUG(spdy_bug_19_5) << "Stream " << stream_id << " not registered"; return 0; } int64_t last_event_time_usec = 0; const StreamInfo& stream_info = it->second; - for (SpdyPriority p = kV3HighestPriority; p < stream_info.priority; ++p) { + for (spdy::SpdyPriority p = spdy::kV3HighestPriority; + p < stream_info.priority; ++p) { last_event_time_usec = std::max(last_event_time_usec, priority_infos_[p].last_event_time_usec); } @@ -173,7 +174,8 @@ class PriorityWriteScheduler : public WriteScheduler<StreamIdType> { // Returns the next ready stream and its precedence. std::tuple<StreamIdType, StreamPrecedenceType> PopNextReadyStreamAndPrecedence() override { - for (SpdyPriority p = kV3HighestPriority; p <= kV3LowestPriority; ++p) { + for (spdy::SpdyPriority p = spdy::kV3HighestPriority; + p <= spdy::kV3LowestPriority; ++p) { ReadyList& ready_list = priority_infos_[p].ready_list; if (!ready_list.empty()) { StreamInfo* info = ready_list.front(); @@ -187,20 +189,21 @@ class PriorityWriteScheduler : public WriteScheduler<StreamIdType> { StreamPrecedenceType(info->priority)); } } - SPDY_BUG(spdy_bug_19_6) << "No ready streams available"; - return std::make_tuple(0, StreamPrecedenceType(kV3LowestPriority)); + QUICHE_BUG(spdy_bug_19_6) << "No ready streams available"; + return std::make_tuple(0, StreamPrecedenceType(spdy::kV3LowestPriority)); } bool ShouldYield(StreamIdType stream_id) const override { auto it = stream_infos_.find(stream_id); if (it == stream_infos_.end()) { - SPDY_BUG(spdy_bug_19_7) << "Stream " << stream_id << " not registered"; + QUICHE_BUG(spdy_bug_19_7) << "Stream " << stream_id << " not registered"; return false; } // If there's a higher priority stream, this stream should yield. const StreamInfo& stream_info = it->second; - for (SpdyPriority p = kV3HighestPriority; p < stream_info.priority; ++p) { + for (spdy::SpdyPriority p = spdy::kV3HighestPriority; + p < stream_info.priority; ++p) { if (!priority_infos_[p].ready_list.empty()) { return true; } @@ -221,7 +224,7 @@ class PriorityWriteScheduler : public WriteScheduler<StreamIdType> { void MarkStreamReady(StreamIdType stream_id, bool add_to_front) override { auto it = stream_infos_.find(stream_id); if (it == stream_infos_.end()) { - SPDY_BUG(spdy_bug_19_8) << "Stream " << stream_id << " not registered"; + QUICHE_BUG(spdy_bug_19_8) << "Stream " << stream_id << " not registered"; return; } StreamInfo& stream_info = it->second; @@ -241,7 +244,7 @@ class PriorityWriteScheduler : public WriteScheduler<StreamIdType> { void MarkStreamNotReady(StreamIdType stream_id) override { auto it = stream_infos_.find(stream_id); if (it == stream_infos_.end()) { - SPDY_BUG(spdy_bug_19_9) << "Stream " << stream_id << " not registered"; + QUICHE_BUG(spdy_bug_19_9) << "Stream " << stream_id << " not registered"; return; } StreamInfo& stream_info = it->second; @@ -272,7 +275,7 @@ class PriorityWriteScheduler : public WriteScheduler<StreamIdType> { bool IsStreamReady(StreamIdType stream_id) const override { auto it = stream_infos_.find(stream_id); if (it == stream_infos_.end()) { - SPDY_DLOG(INFO) << "Stream " << stream_id << " not registered"; + QUICHE_DLOG(INFO) << "Stream " << stream_id << " not registered"; return false; } return it->second.ready; @@ -284,7 +287,7 @@ class PriorityWriteScheduler : public WriteScheduler<StreamIdType> { // State kept for all registered streams. All ready streams have ready = true // and should be present in priority_infos_[priority].ready_list. struct StreamInfo { - SpdyPriority priority; + spdy::SpdyPriority priority; StreamIdType stream_id; bool ready; }; @@ -318,12 +321,12 @@ class PriorityWriteScheduler : public WriteScheduler<StreamIdType> { // Number of ready streams. size_t num_ready_streams_ = 0; // Per-priority state, including ready lists. - PriorityInfo priority_infos_[kV3LowestPriority + 1]; + PriorityInfo priority_infos_[spdy::kV3LowestPriority + 1]; // StreamInfos for all registered streams. StreamInfoMap stream_infos_; StreamIdType root_stream_id_; }; -} // namespace spdy +} // namespace http2 -#endif // QUICHE_SPDY_CORE_PRIORITY_WRITE_SCHEDULER_H_ +#endif // QUICHE_HTTP2_CORE_PRIORITY_WRITE_SCHEDULER_H_ diff --git a/chromium/net/third_party/quiche/src/spdy/core/priority_write_scheduler_test.cc b/chromium/net/third_party/quiche/src/http2/core/priority_write_scheduler_test.cc index a76e0dc5801..e4e6997118d 100644 --- a/chromium/net/third_party/quiche/src/spdy/core/priority_write_scheduler_test.cc +++ b/chromium/net/third_party/quiche/src/http2/core/priority_write_scheduler_test.cc @@ -2,16 +2,22 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "spdy/core/priority_write_scheduler.h" +#include "http2/core/priority_write_scheduler.h" #include "common/platform/api/quiche_test.h" +#include "common/platform/api/quiche_test_helpers.h" #include "spdy/core/spdy_protocol.h" #include "spdy/core/spdy_test_utils.h" -#include "spdy/platform/api/spdy_test_helpers.h" -namespace spdy { +namespace http2 { namespace test { +using ::spdy::kHttp2RootStreamId; +using ::spdy::kV3LowestPriority; +using ::spdy::SpdyPriority; +using ::spdy::SpdyStreamId; +using ::spdy::SpdyStreamPrecedence; + template <typename StreamIdType> class PriorityWriteSchedulerPeer { public: @@ -46,15 +52,15 @@ TEST_F(PriorityWriteSchedulerTest, RegisterUnregisterStreams) { EXPECT_EQ(1u, scheduler_.NumRegisteredStreams()); // Root stream counts as already registered. - EXPECT_SPDY_BUG( + EXPECT_QUICHE_BUG( scheduler_.RegisterStream(kHttp2RootStreamId, SpdyStreamPrecedence(1)), "Stream 0 already registered"); // Try redundant registrations. - EXPECT_SPDY_BUG(scheduler_.RegisterStream(1, SpdyStreamPrecedence(1)), - "Stream 1 already registered"); - EXPECT_SPDY_BUG(scheduler_.RegisterStream(1, SpdyStreamPrecedence(2)), - "Stream 1 already registered"); + EXPECT_QUICHE_BUG(scheduler_.RegisterStream(1, SpdyStreamPrecedence(1)), + "Stream 1 already registered"); + EXPECT_QUICHE_BUG(scheduler_.RegisterStream(1, SpdyStreamPrecedence(2)), + "Stream 1 already registered"); scheduler_.RegisterStream(2, SpdyStreamPrecedence(3)); EXPECT_EQ(2u, scheduler_.NumRegisteredStreams()); @@ -68,8 +74,8 @@ TEST_F(PriorityWriteSchedulerTest, RegisterUnregisterStreams) { EXPECT_EQ(0u, scheduler_.NumRegisteredStreams()); // Try redundant unregistration. - EXPECT_SPDY_BUG(scheduler_.UnregisterStream(1), "Stream 1 not registered"); - EXPECT_SPDY_BUG(scheduler_.UnregisterStream(2), "Stream 2 not registered"); + EXPECT_QUICHE_BUG(scheduler_.UnregisterStream(1), "Stream 1 not registered"); + EXPECT_QUICHE_BUG(scheduler_.UnregisterStream(2), "Stream 2 not registered"); } TEST_F(PriorityWriteSchedulerTest, RegisterStreamWithHttp2StreamDependency) { @@ -82,9 +88,10 @@ TEST_F(PriorityWriteSchedulerTest, RegisterStreamWithHttp2StreamDependency) { EXPECT_EQ(3, scheduler_.GetStreamPrecedence(1).spdy3_priority()); EXPECT_FALSE(scheduler_.HasReadyStreams()); - EXPECT_SPDY_BUG(scheduler_.RegisterStream( - 1, SpdyStreamPrecedence(kHttp2RootStreamId, 256, false)), - "Stream 1 already registered"); + EXPECT_QUICHE_BUG( + scheduler_.RegisterStream( + 1, SpdyStreamPrecedence(kHttp2RootStreamId, 256, false)), + "Stream 1 already registered"); EXPECT_TRUE(scheduler_.GetStreamPrecedence(1).is_spdy3_priority()); EXPECT_EQ(3, scheduler_.GetStreamPrecedence(1).spdy3_priority()); @@ -107,8 +114,8 @@ TEST_F(PriorityWriteSchedulerTest, GetStreamPrecedence) { EXPECT_EQ(3, scheduler_.GetStreamPrecedence(1).spdy3_priority()); // Redundant registration shouldn't change stream priority. - EXPECT_SPDY_BUG(scheduler_.RegisterStream(1, SpdyStreamPrecedence(4)), - "Stream 1 already registered"); + EXPECT_QUICHE_BUG(scheduler_.RegisterStream(1, SpdyStreamPrecedence(4)), + "Stream 1 already registered"); EXPECT_EQ(3, scheduler_.GetStreamPrecedence(1).spdy3_priority()); scheduler_.UpdateStreamPrecedence(1, SpdyStreamPrecedence(5)); @@ -204,11 +211,11 @@ TEST_F(PriorityWriteSchedulerTest, TEST_F(PriorityWriteSchedulerTest, MarkStreamReadyBack) { EXPECT_FALSE(scheduler_.HasReadyStreams()); - EXPECT_SPDY_BUG(scheduler_.MarkStreamReady(1, false), - "Stream 1 not registered"); + EXPECT_QUICHE_BUG(scheduler_.MarkStreamReady(1, false), + "Stream 1 not registered"); EXPECT_FALSE(scheduler_.HasReadyStreams()); - EXPECT_SPDY_BUG(EXPECT_EQ(0u, scheduler_.PopNextReadyStream()), - "No ready streams available"); + EXPECT_QUICHE_BUG(EXPECT_EQ(0u, scheduler_.PopNextReadyStream()), + "No ready streams available"); // Add a bunch of ready streams to tail of per-priority lists. // Expected order: (P2) 4, (P3) 1, 2, 3, (P5) 5. @@ -229,17 +236,17 @@ TEST_F(PriorityWriteSchedulerTest, MarkStreamReadyBack) { EXPECT_EQ(2u, scheduler_.PopNextReadyStream()); EXPECT_EQ(3u, scheduler_.PopNextReadyStream()); EXPECT_EQ(5u, scheduler_.PopNextReadyStream()); - EXPECT_SPDY_BUG(EXPECT_EQ(0u, scheduler_.PopNextReadyStream()), - "No ready streams available"); + EXPECT_QUICHE_BUG(EXPECT_EQ(0u, scheduler_.PopNextReadyStream()), + "No ready streams available"); } TEST_F(PriorityWriteSchedulerTest, MarkStreamReadyFront) { EXPECT_FALSE(scheduler_.HasReadyStreams()); - EXPECT_SPDY_BUG(scheduler_.MarkStreamReady(1, true), - "Stream 1 not registered"); + EXPECT_QUICHE_BUG(scheduler_.MarkStreamReady(1, true), + "Stream 1 not registered"); EXPECT_FALSE(scheduler_.HasReadyStreams()); - EXPECT_SPDY_BUG(EXPECT_EQ(0u, scheduler_.PopNextReadyStream()), - "No ready streams available"); + EXPECT_QUICHE_BUG(EXPECT_EQ(0u, scheduler_.PopNextReadyStream()), + "No ready streams available"); // Add a bunch of ready streams to head of per-priority lists. // Expected order: (P2) 4, (P3) 3, 2, 1, (P5) 5 @@ -260,8 +267,8 @@ TEST_F(PriorityWriteSchedulerTest, MarkStreamReadyFront) { EXPECT_EQ(2u, scheduler_.PopNextReadyStream()); EXPECT_EQ(1u, scheduler_.PopNextReadyStream()); EXPECT_EQ(5u, scheduler_.PopNextReadyStream()); - EXPECT_SPDY_BUG(EXPECT_EQ(0u, scheduler_.PopNextReadyStream()), - "No ready streams available"); + EXPECT_QUICHE_BUG(EXPECT_EQ(0u, scheduler_.PopNextReadyStream()), + "No ready streams available"); } TEST_F(PriorityWriteSchedulerTest, MarkStreamReadyBackAndFront) { @@ -288,8 +295,8 @@ TEST_F(PriorityWriteSchedulerTest, MarkStreamReadyBackAndFront) { EXPECT_EQ(3u, scheduler_.PopNextReadyStream()); EXPECT_EQ(1u, scheduler_.PopNextReadyStream()); EXPECT_EQ(5u, scheduler_.PopNextReadyStream()); - EXPECT_SPDY_BUG(EXPECT_EQ(0u, scheduler_.PopNextReadyStream()), - "No ready streams available"); + EXPECT_QUICHE_BUG(EXPECT_EQ(0u, scheduler_.PopNextReadyStream()), + "No ready streams available"); } TEST_F(PriorityWriteSchedulerTest, MarkStreamNotReady) { @@ -302,15 +309,16 @@ TEST_F(PriorityWriteSchedulerTest, MarkStreamNotReady) { EXPECT_EQ(0u, scheduler_.NumReadyStreams()); // Empty pop should fail. - EXPECT_SPDY_BUG(EXPECT_EQ(0u, scheduler_.PopNextReadyStream()), - "No ready streams available"); + EXPECT_QUICHE_BUG(EXPECT_EQ(0u, scheduler_.PopNextReadyStream()), + "No ready streams available"); // Tolerate redundant marking of a stream as not ready. scheduler_.MarkStreamNotReady(1); EXPECT_EQ(0u, scheduler_.NumReadyStreams()); // Should only be able to mark registered streams. - EXPECT_SPDY_BUG(scheduler_.MarkStreamNotReady(3), "Stream 3 not registered"); + EXPECT_QUICHE_BUG(scheduler_.MarkStreamNotReady(3), + "Stream 3 not registered"); } TEST_F(PriorityWriteSchedulerTest, UnregisterRemovesStream) { @@ -321,8 +329,8 @@ TEST_F(PriorityWriteSchedulerTest, UnregisterRemovesStream) { // Unregistering a stream should remove it from set of ready streams. scheduler_.UnregisterStream(3); EXPECT_EQ(0u, scheduler_.NumReadyStreams()); - EXPECT_SPDY_BUG(EXPECT_EQ(0u, scheduler_.PopNextReadyStream()), - "No ready streams available"); + EXPECT_QUICHE_BUG(EXPECT_EQ(0u, scheduler_.PopNextReadyStream()), + "No ready streams available"); } TEST_F(PriorityWriteSchedulerTest, ShouldYield) { @@ -353,10 +361,10 @@ TEST_F(PriorityWriteSchedulerTest, ShouldYield) { } TEST_F(PriorityWriteSchedulerTest, GetLatestEventWithPrecedence) { - EXPECT_SPDY_BUG(scheduler_.RecordStreamEventTime(3, 5), - "Stream 3 not registered"); - EXPECT_SPDY_BUG(EXPECT_EQ(0, scheduler_.GetLatestEventWithPrecedence(4)), - "Stream 4 not registered"); + EXPECT_QUICHE_BUG(scheduler_.RecordStreamEventTime(3, 5), + "Stream 3 not registered"); + EXPECT_QUICHE_BUG(EXPECT_EQ(0, scheduler_.GetLatestEventWithPrecedence(4)), + "Stream 4 not registered"); for (int i = 1; i < 5; ++i) { scheduler_.RegisterStream(i, SpdyStreamPrecedence(i)); @@ -374,4 +382,4 @@ TEST_F(PriorityWriteSchedulerTest, GetLatestEventWithPrecedence) { } // namespace } // namespace test -} // namespace spdy +} // namespace http2 diff --git a/chromium/net/third_party/quiche/src/spdy/core/write_scheduler.h b/chromium/net/third_party/quiche/src/http2/core/write_scheduler.h index de9264d6a47..4973a2d83ec 100644 --- a/chromium/net/third_party/quiche/src/spdy/core/write_scheduler.h +++ b/chromium/net/third_party/quiche/src/http2/core/write_scheduler.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef QUICHE_SPDY_CORE_WRITE_SCHEDULER_H_ -#define QUICHE_SPDY_CORE_WRITE_SCHEDULER_H_ +#ifndef QUICHE_HTTP2_CORE_WRITE_SCHEDULER_H_ +#define QUICHE_HTTP2_CORE_WRITE_SCHEDULER_H_ #include <cstdint> #include <string> @@ -13,7 +13,7 @@ #include "common/platform/api/quiche_export.h" #include "spdy/core/spdy_protocol.h" -namespace spdy { +namespace http2 { // Abstract superclass for classes that decide which SPDY or HTTP/2 stream to // write next. Concrete subclasses implement various scheduling policies: @@ -42,7 +42,7 @@ namespace spdy { template <typename StreamIdType> class QUICHE_EXPORT_PRIVATE WriteScheduler { public: - typedef StreamPrecedence<StreamIdType> StreamPrecedenceType; + typedef spdy::StreamPrecedence<StreamIdType> StreamPrecedenceType; virtual ~WriteScheduler() {} @@ -157,6 +157,6 @@ class QUICHE_EXPORT_PRIVATE WriteScheduler { virtual std::string DebugString() const = 0; }; -} // namespace spdy +} // namespace http2 -#endif // QUICHE_SPDY_CORE_WRITE_SCHEDULER_H_ +#endif // QUICHE_HTTP2_CORE_WRITE_SCHEDULER_H_ 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 6c6a9773c59..b7a8b39d051 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 @@ -8,6 +8,7 @@ #include <initializer_list> +#include "absl/strings/escaping.h" #include "http2/platform/api/http2_logging.h" #include "http2/platform/api/http2_string_utils.h" #include "http2/platform/api/http2_test_helpers.h" @@ -151,7 +152,7 @@ TEST_F(HpackDecoderStringBufferTest, PlainSplit) { } TEST_F(HpackDecoderStringBufferTest, HuffmanWhole) { - std::string encoded = Http2HexDecode("f1e3c2e5f23a6ba0ab90f4ff"); + std::string encoded = absl::HexStringToBytes("f1e3c2e5f23a6ba0ab90f4ff"); absl::string_view decoded("www.example.com"); EXPECT_EQ(state(), State::RESET); @@ -176,7 +177,7 @@ TEST_F(HpackDecoderStringBufferTest, HuffmanWhole) { } TEST_F(HpackDecoderStringBufferTest, HuffmanSplit) { - std::string encoded = Http2HexDecode("f1e3c2e5f23a6ba0ab90f4ff"); + std::string encoded = absl::HexStringToBytes("f1e3c2e5f23a6ba0ab90f4ff"); std::string part1 = encoded.substr(0, 5); std::string part2 = encoded.substr(5); absl::string_view decoded("www.example.com"); @@ -215,7 +216,7 @@ TEST_F(HpackDecoderStringBufferTest, HuffmanSplit) { TEST_F(HpackDecoderStringBufferTest, InvalidHuffmanOnData) { // Explicitly encode the End-of-String symbol, a no-no. - std::string encoded = Http2HexDecode("ffffffff"); + std::string encoded = absl::HexStringToBytes("ffffffff"); buf_.OnStart(/*huffman_encoded*/ true, encoded.size()); EXPECT_EQ(state(), State::COLLECTING); @@ -229,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. - std::string encoded = Http2HexDecode("00"); + std::string encoded = absl::HexStringToBytes("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.h b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_tables.h index f75916d67df..ef5b3d2d678 100644 --- a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_tables.h +++ b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_tables.h @@ -25,8 +25,8 @@ #include <vector> #include "http2/http2_constants.h" -#include "quic/core/quic_circular_deque.h" #include "common/platform/api/quiche_export.h" +#include "common/quiche_circular_deque.h" namespace http2 { namespace test { @@ -107,7 +107,7 @@ class QUICHE_EXPORT_PRIVATE HpackDecoderDynamicTable { // Removes the oldest dynamic table entry. void RemoveLastEntry(); - quic::QuicCircularDeque<HpackStringPair> table_; + quiche::QuicheCircularDeque<HpackStringPair> table_; // The last received DynamicTableSizeUpdate value, initialized to // SETTINGS_HEADER_TABLE_SIZE. 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 fa88038af2f..e7a346e7719 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 @@ -9,6 +9,7 @@ #include <iostream> #include "absl/base/macros.h" +#include "absl/strings/escaping.h" #include "http2/decoder/decode_buffer.h" #include "http2/decoder/decode_status.h" #include "http2/platform/api/http2_string_utils.h" @@ -188,13 +189,13 @@ class HpackHuffmanDecoderTest : public RandomDecoderTest { TEST_F(HpackHuffmanDecoderTest, SpecRequestExamples) { HpackHuffmanDecoder decoder; std::string test_table[] = { - Http2HexDecode("f1e3c2e5f23a6ba0ab90f4ff"), + absl::HexStringToBytes("f1e3c2e5f23a6ba0ab90f4ff"), "www.example.com", - Http2HexDecode("a8eb10649cbf"), + absl::HexStringToBytes("a8eb10649cbf"), "no-cache", - Http2HexDecode("25a849e95ba97d7f"), + absl::HexStringToBytes("25a849e95ba97d7f"), "custom-key", - Http2HexDecode("25a849e95bb8e8b4bf"), + absl::HexStringToBytes("25a849e95bb8e8b4bf"), "custom-value", }; for (size_t i = 0; i != ABSL_ARRAYSIZE(test_table); i += 2) { @@ -212,17 +213,17 @@ TEST_F(HpackHuffmanDecoderTest, SpecResponseExamples) { HpackHuffmanDecoder decoder; // clang-format off std::string test_table[] = { - Http2HexDecode("6402"), + absl::HexStringToBytes("6402"), "302", - Http2HexDecode("aec3771a4b"), + absl::HexStringToBytes("aec3771a4b"), "private", - Http2HexDecode("d07abe941054d444a8200595040b8166" + absl::HexStringToBytes("d07abe941054d444a8200595040b8166" "e082a62d1bff"), "Mon, 21 Oct 2013 20:13:21 GMT", - Http2HexDecode("9d29ad171863c78f0b97c8e9ae82ae43" + absl::HexStringToBytes("9d29ad171863c78f0b97c8e9ae82ae43" "d3"), "https://www.example.com", - Http2HexDecode("94e7821dd7f2e6c7b335dfdfcd5b3960" + absl::HexStringToBytes("94e7821dd7f2e6c7b335dfdfcd5b3960" "d5af27087f3672c1ab270fb5291f9587" "316065c003ed4ee5b1063d5007"), "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1", 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 666fe95d948..0d321876149 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 @@ -5,6 +5,7 @@ #include "http2/hpack/huffman/hpack_huffman_encoder.h" #include "absl/base/macros.h" +#include "absl/strings/escaping.h" #include "http2/platform/api/http2_string_utils.h" #include "common/platform/api/quiche_test.h" @@ -40,13 +41,13 @@ TEST_P(HuffmanEncoderTest, Empty) { TEST_P(HuffmanEncoderTest, SpecRequestExamples) { std::string test_table[] = { - Http2HexDecode("f1e3c2e5f23a6ba0ab90f4ff"), + absl::HexStringToBytes("f1e3c2e5f23a6ba0ab90f4ff"), "www.example.com", - Http2HexDecode("a8eb10649cbf"), + absl::HexStringToBytes("a8eb10649cbf"), "no-cache", - Http2HexDecode("25a849e95ba97d7f"), + absl::HexStringToBytes("25a849e95ba97d7f"), "custom-key", - Http2HexDecode("25a849e95bb8e8b4bf"), + absl::HexStringToBytes("25a849e95bb8e8b4bf"), "custom-value", }; for (size_t i = 0; i != ABSL_ARRAYSIZE(test_table); i += 2) { @@ -64,17 +65,17 @@ TEST_P(HuffmanEncoderTest, SpecRequestExamples) { TEST_P(HuffmanEncoderTest, SpecResponseExamples) { // clang-format off std::string test_table[] = { - Http2HexDecode("6402"), + absl::HexStringToBytes("6402"), "302", - Http2HexDecode("aec3771a4b"), + absl::HexStringToBytes("aec3771a4b"), "private", - Http2HexDecode("d07abe941054d444a8200595040b8166" + absl::HexStringToBytes("d07abe941054d444a8200595040b8166" "e082a62d1bff"), "Mon, 21 Oct 2013 20:13:21 GMT", - Http2HexDecode("9d29ad171863c78f0b97c8e9ae82ae43" + absl::HexStringToBytes("9d29ad171863c78f0b97c8e9ae82ae43" "d3"), "https://www.example.com", - Http2HexDecode("94e7821dd7f2e6c7b335dfdfcd5b3960" + absl::HexStringToBytes("94e7821dd7f2e6c7b335dfdfcd5b3960" "d5af27087f3672c1ab270fb5291f9587" "316065c003ed4ee5b1063d5007"), "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1", @@ -120,11 +121,11 @@ TEST_P(HuffmanEncoderTest, AppendToOutput) { size_t encoded_size = HuffmanSize("foo"); std::string buffer; Encode("foo", encoded_size, &buffer); - EXPECT_EQ(Http2HexDecode("94e7"), buffer); + EXPECT_EQ(absl::HexStringToBytes("94e7"), buffer); encoded_size = HuffmanSize("bar"); Encode("bar", encoded_size, &buffer); - EXPECT_EQ(Http2HexDecode("94e78c767f"), buffer); + EXPECT_EQ(absl::HexStringToBytes("94e78c767f"), buffer); } } // namespace 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 d4eb3d78790..3821127bd08 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 @@ -4,6 +4,7 @@ #include "http2/hpack/tools/hpack_block_builder.h" +#include "absl/strings/escaping.h" #include "http2/platform/api/http2_string_utils.h" #include "common/platform/api/quiche_test.h" @@ -97,7 +98,7 @@ TEST(HpackBlockBuilderTest, ExamplesFromSpecC3) { // 0x0010: 2e63 6f6d .com const std::string expected = - Http2HexDecode("828684410f7777772e6578616d706c652e636f6d"); + absl::HexStringToBytes("828684410f7777772e6578616d706c652e636f6d"); EXPECT_EQ(expected, b.buffer()); } } @@ -128,7 +129,7 @@ TEST(HpackBlockBuilderTest, ExamplesFromSpecC4) { // 0x0010: ff . const std::string expected = - Http2HexDecode("828684418cf1e3c2e5f23a6ba0ab90f4ff"); + absl::HexStringToBytes("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 00664b27f14..b2783e3b277 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 @@ -6,6 +6,7 @@ #include <ctype.h> +#include "absl/strings/escaping.h" #include "absl/strings/str_cat.h" #include "http2/platform/api/http2_bug_tracker.h" #include "http2/platform/api/http2_logging.h" @@ -22,7 +23,7 @@ void HpackExampleToStringOrDie(absl::string_view example, std::string* output) { QUICHE_CHECK_GT(example.size(), 1u) << "Truncated hex byte?"; const char c1 = example[1]; QUICHE_CHECK(isxdigit(c1)) << "Found half a byte?"; - *output += Http2HexDecode(example.substr(0, 2)); + *output += absl::HexStringToBytes(example.substr(0, 2)); example.remove_prefix(2); continue; } 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 3d73c5c4a86..a67cca6c729 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 @@ -9,6 +9,7 @@ #include <stddef.h> #include "absl/base/macros.h" +#include "absl/strings/escaping.h" #include "absl/strings/string_view.h" #include "http2/platform/api/http2_logging.h" #include "http2/platform/api/http2_string_utils.h" @@ -28,7 +29,7 @@ class HpackVarintDecoderTest : public RandomDecoderTest, protected: HpackVarintDecoderTest() : high_bits_(::testing::get<0>(GetParam())), - suffix_(Http2HexDecode(::testing::get<1>(GetParam()))), + suffix_(absl::HexStringToBytes(::testing::get<1>(GetParam()))), prefix_length_(0) {} void DecodeExpectSuccess(absl::string_view data, @@ -261,7 +262,7 @@ struct { TEST_P(HpackVarintDecoderTest, Success) { for (size_t i = 0; i < ABSL_ARRAYSIZE(kSuccessTestData); ++i) { - DecodeExpectSuccess(Http2HexDecode(kSuccessTestData[i].data), + DecodeExpectSuccess(absl::HexStringToBytes(kSuccessTestData[i].data), kSuccessTestData[i].prefix_length, kSuccessTestData[i].expected_value); } @@ -302,7 +303,7 @@ struct { TEST_P(HpackVarintDecoderTest, Error) { for (size_t i = 0; i < ABSL_ARRAYSIZE(kErrorTestData); ++i) { - DecodeExpectError(Http2HexDecode(kErrorTestData[i].data), + DecodeExpectError(absl::HexStringToBytes(kErrorTestData[i].data), kErrorTestData[i].prefix_length); } } 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 cd1666b8ce3..7f049e8eabf 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 @@ -5,8 +5,8 @@ #include "http2/hpack/varint/hpack_varint_encoder.h" #include "absl/base/macros.h" +#include "absl/strings/escaping.h" #include "http2/platform/api/http2_string_utils.h" - #include "common/platform/api/quiche_test.h" namespace http2 { @@ -105,7 +105,7 @@ TEST(HpackVarintEncoderTest, Long) { // a single ResumeEncoding() call. for (size_t i = 0; i < ABSL_ARRAYSIZE(kLongTestData); ++i) { std::string expected_encoding = - Http2HexDecode(kLongTestData[i].expected_encoding); + absl::HexStringToBytes(kLongTestData[i].expected_encoding); std::string output; HpackVarintEncoder::Encode(kLongTestData[i].high_bits, @@ -145,16 +145,16 @@ TEST(HpackVarintEncoderTest, LastByteIsZero) { // Test that encoder appends correctly to non-empty string. TEST(HpackVarintEncoderTest, Append) { std::string output("foo"); - EXPECT_EQ(Http2HexDecode("666f6f"), output); + EXPECT_EQ(absl::HexStringToBytes("666f6f"), output); HpackVarintEncoder::Encode(0b10011000, 3, 103, &output); - EXPECT_EQ(Http2HexDecode("666f6f9f60"), output); + EXPECT_EQ(absl::HexStringToBytes("666f6f9f60"), output); HpackVarintEncoder::Encode(0b10100000, 5, 8, &output); - EXPECT_EQ(Http2HexDecode("666f6f9f60a8"), output); + EXPECT_EQ(absl::HexStringToBytes("666f6f9f60a8"), output); HpackVarintEncoder::Encode(0b10011000, 3, 202147110, &output); - EXPECT_EQ(Http2HexDecode("666f6f9f60a89f9f8ab260"), output); + EXPECT_EQ(absl::HexStringToBytes("666f6f9f60a89f9f8ab260"), output); } } // namespace 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 a8ba99a8a31..d8152593547 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 @@ -14,6 +14,7 @@ #include <vector> #include "absl/strings/str_cat.h" +#include "absl/strings/str_format.h" #include "absl/strings/string_view.h" #include "http2/hpack/tools/hpack_block_builder.h" #include "http2/platform/api/http2_logging.h" @@ -285,7 +286,7 @@ TEST_F(HpackVarintRoundTripTest, Encode) { for (uint64_t value : values) { EncodeNoRandom(value, prefix_length); std::string dump = Http2HexDump(buffer_); - HTTP2_LOG(INFO) << Http2StringPrintf("%10llu %0#18x ", value, value) + HTTP2_LOG(INFO) << absl::StrFormat("%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 2faf2f94ebe..bebe8803652 100644 --- a/chromium/net/third_party/quiche/src/http2/http2_constants.cc +++ b/chromium/net/third_party/quiche/src/http2/http2_constants.cc @@ -5,6 +5,7 @@ #include "http2/http2_constants.h" #include "absl/strings/str_cat.h" +#include "absl/strings/str_format.h" #include "absl/strings/string_view.h" #include "http2/platform/api/http2_logging.h" #include "http2/platform/api/http2_string_utils.h" @@ -83,7 +84,7 @@ std::string Http2FrameFlagsToString(Http2FrameType type, uint8_t flags) { } } if (flags != 0) { - append_and_clear(Http2StringPrintf("0x%02x", flags), flags); + append_and_clear(absl::StrFormat("0x%02x", flags), flags); } QUICHE_DCHECK_EQ(0, flags); return s; 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 dda0dd88302..a96edccdd71 100644 --- a/chromium/net/third_party/quiche/src/http2/http2_structures.cc +++ b/chromium/net/third_party/quiche/src/http2/http2_structures.cc @@ -7,6 +7,7 @@ #include <cstring> // For std::memcmp #include <sstream> +#include "absl/strings/escaping.h" #include "absl/strings/str_cat.h" #include "http2/platform/api/http2_string_utils.h" @@ -98,7 +99,9 @@ bool operator==(const Http2PingFields& a, const Http2PingFields& b) { std::ostream& operator<<(std::ostream& out, const Http2PingFields& v) { return out << "opaque_bytes=0x" - << Http2HexEncode(v.opaque_bytes, sizeof v.opaque_bytes); + << absl::BytesToHexString(absl::string_view( + reinterpret_cast<const char*>(v.opaque_bytes), + sizeof v.opaque_bytes)); } // Http2GoAwayFields: 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 087bd254a96..cf39515ad4c 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 @@ -14,19 +14,6 @@ namespace http2 { -template <typename... Args> -inline std::string Http2StringPrintf(const Args&... args) { - return Http2StringPrintfImpl(std::forward<const Args&>(args)...); -} - -inline std::string Http2HexEncode(const void* bytes, size_t size) { - return Http2HexEncodeImpl(bytes, size); -} - -inline std::string Http2HexDecode(absl::string_view data) { - return Http2HexDecodeImpl(data); -} - inline std::string Http2HexDump(absl::string_view data) { return Http2HexDumpImpl(data); } 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 deleted file mode 100644 index 9ee7869edd3..00000000000 --- a/chromium/net/third_party/quiche/src/http2/platform/api/http2_string_utils_test.cc +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "http2/platform/api/http2_string_utils.h" - -#include "common/platform/api/quiche_test.h" - -namespace http2 { -namespace test { -namespace { - -TEST(Http2StringUtilsTest, Http2StringPrintf) { - EXPECT_EQ("", Http2StringPrintf("%s", "")); - EXPECT_EQ("foobar", Http2StringPrintf("%sbar", "foo")); - EXPECT_EQ("foobar", Http2StringPrintf("%s%s", "foo", "bar")); - EXPECT_EQ("foo: 1, bar: 2.0", - Http2StringPrintf("foo: %d, bar: %.1f", 1, 2.0)); -} - -} // namespace -} // namespace test -} // namespace http2 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 c9a071df9e0..8f9014efd17 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 @@ -1,5 +1,6 @@ #include "http2/test_tools/http2_random.h" +#include "absl/strings/escaping.h" #include "http2/platform/api/http2_logging.h" #include "http2/platform/api/http2_string_utils.h" #include "third_party/boringssl/src/include/openssl/chacha.h" @@ -17,13 +18,14 @@ Http2Random::Http2Random() { } Http2Random::Http2Random(absl::string_view key) { - std::string decoded_key = Http2HexDecode(key); + std::string decoded_key = absl::HexStringToBytes(key); QUICHE_CHECK_EQ(sizeof(key_), decoded_key.size()); memcpy(key_, decoded_key.data(), sizeof(key_)); } std::string Http2Random::Key() const { - return Http2HexEncode(key_, sizeof(key_)); + return absl::BytesToHexString( + absl::string_view(reinterpret_cast<const char*>(key_), sizeof(key_))); } void Http2Random::FillRandom(void* buffer, size_t buffer_size) { diff --git a/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_base.cc b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_base.cc index 8b4a27f0866..173c8d30488 100644 --- a/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_base.cc +++ b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_base.cc @@ -23,8 +23,20 @@ WriteResult QuicBatchWriterBase::WritePacket( PerPacketOptions* options) { const WriteResult result = InternalWritePacket(buffer, buf_len, self_address, peer_address, options); - if (result.status == WRITE_STATUS_BLOCKED) { - write_blocked_ = true; + + if (GetQuicReloadableFlag(quic_batch_writer_fix_write_blocked)) { + if (IsWriteBlockedStatus(result.status)) { + if (result.status == WRITE_STATUS_BLOCKED_DATA_BUFFERED) { + QUIC_CODE_COUNT(quic_batch_writer_fix_write_blocked_data_buffered); + } else { + QUIC_CODE_COUNT(quic_batch_writer_fix_write_blocked_data_not_buffered); + } + write_blocked_ = true; + } + } else { + if (result.status == WRITE_STATUS_BLOCKED) { + write_blocked_ = true; + } } return result; } diff --git a/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_base.h b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_base.h index ff924d0481c..e7d1f129684 100644 --- a/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_base.h +++ b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_base.h @@ -60,7 +60,7 @@ class QUIC_EXPORT_PRIVATE QuicBatchWriterBase : public QuicPacketWriter { const QuicBatchWriterBuffer& batch_buffer() const { return *batch_buffer_; } QuicBatchWriterBuffer& batch_buffer() { return *batch_buffer_; } - const QuicCircularDeque<BufferedWrite>& buffered_writes() const { + const quiche::QuicheCircularDeque<BufferedWrite>& buffered_writes() const { return batch_buffer_->buffered_writes(); } diff --git a/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_buffer.h b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_buffer.h index 007c2834cc5..4faa3cba4e7 100644 --- a/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_buffer.h +++ b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_buffer.h @@ -6,11 +6,11 @@ #define QUICHE_QUIC_PLATFORM_IMPL_BATCH_WRITER_QUIC_BATCH_WRITER_BUFFER_H_ #include "absl/base/optimization.h" -#include "quic/core/quic_circular_deque.h" #include "quic/core/quic_linux_socket_utils.h" #include "quic/core/quic_packet_writer.h" #include "quic/platform/api/quic_ip_address.h" #include "quic/platform/api/quic_socket_address.h" +#include "common/quiche_circular_deque.h" namespace quic { @@ -61,7 +61,7 @@ class QUIC_EXPORT_PRIVATE QuicBatchWriterBuffer { }; PopResult PopBufferedWrite(int32_t num_buffered_writes); - const QuicCircularDeque<BufferedWrite>& buffered_writes() const { + const quiche::QuicheCircularDeque<BufferedWrite>& buffered_writes() const { return buffered_writes_; } @@ -87,7 +87,7 @@ class QUIC_EXPORT_PRIVATE QuicBatchWriterBuffer { bool Invariants() const; const char* buffer_end() const { return buffer_ + sizeof(buffer_); } ABSL_CACHELINE_ALIGNED char buffer_[kBufferSize]; - QuicCircularDeque<BufferedWrite> buffered_writes_; + quiche::QuicheCircularDeque<BufferedWrite> buffered_writes_; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_gso_batch_writer_test.cc b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_gso_batch_writer_test.cc index ec08164e529..8a1b93fc723 100644 --- a/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_gso_batch_writer_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_gso_batch_writer_test.cc @@ -322,6 +322,11 @@ TEST_F(QuicGsoBatchWriterTest, WriteBlockDataBuffered) { })); ASSERT_EQ(WriteResult(WRITE_STATUS_BLOCKED_DATA_BUFFERED, EWOULDBLOCK), WritePacket(&writer, 50)); + if (GetQuicReloadableFlag(quic_batch_writer_fix_write_blocked)) { + EXPECT_TRUE(writer.IsWriteBlocked()); + } else { + EXPECT_FALSE(writer.IsWriteBlocked()); + } ASSERT_EQ(250u, writer.batch_buffer().SizeInUse()); ASSERT_EQ(3u, writer.buffered_writes().size()); } 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 48fe9a82c05..29a43a605e0 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 @@ -17,7 +17,6 @@ #include "quic/core/quic_framer.h" #include "quic/core/quic_types.h" #include "quic/core/quic_utils.h" -#include "common/platform/api/quiche_text_utils.h" namespace quic { 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 7a34097fd54..6738f49ab05 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.h +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.h @@ -9,13 +9,13 @@ #include "quic/core/congestion_control/windowed_filter.h" #include "quic/core/packet_number_indexed_queue.h" #include "quic/core/quic_bandwidth.h" -#include "quic/core/quic_circular_deque.h" #include "quic/core/quic_packets.h" #include "quic/core/quic_time.h" #include "quic/core/quic_types.h" #include "quic/core/quic_unacked_packet_map.h" #include "quic/platform/api/quic_export.h" #include "quic/platform/api/quic_flags.h" +#include "common/quiche_circular_deque.h" namespace quic { @@ -540,7 +540,7 @@ class QUIC_EXPORT_PRIVATE BandwidthSampler : public BandwidthSamplerInterface { PacketNumberIndexedQueue<ConnectionStateOnSentPacket> connection_state_map_; RecentAckPoints recent_ack_points_; - QuicCircularDeque<AckPoint> a0_candidates_; + quiche::QuicheCircularDeque<AckPoint> a0_candidates_; // Maximum number of tracked packets. const QuicPacketCount max_tracked_packets_; 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 d24e50efdbc..8d4a49350b5 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 @@ -116,9 +116,9 @@ void Bbr2NetworkModel::OnCongestionEventStart( << total_bytes_acked() - prior_bytes_acked << " bytes from " << acked_packets.size() << " packets have been acked, but sample_max_bandwidth is zero."; + congestion_event->sample_max_bandwidth = sample.sample_max_bandwidth; if (!sample.sample_is_app_limited || sample.sample_max_bandwidth > MaxBandwidth()) { - congestion_event->sample_max_bandwidth = sample.sample_max_bandwidth; max_bandwidth_filter_.Update(congestion_event->sample_max_bandwidth); } } @@ -188,99 +188,112 @@ void Bbr2NetworkModel::OnCongestionEventStart( void Bbr2NetworkModel::AdaptLowerBounds( const Bbr2CongestionEvent& congestion_event) { - if (Params().bw_lo_mode_ != Bbr2Params::DEFAULT) { - if (congestion_event.bytes_lost == 0) { + if (Params().bw_lo_mode_ == Bbr2Params::DEFAULT) { + if (!congestion_event.end_of_round_trip || + congestion_event.is_probing_for_bandwidth) { return; } - // Ignore losses from packets sent when probing for more bandwidth in - // STARTUP or PROBE_UP when they're lost in DRAIN or PROBE_DOWN. - if (pacing_gain_ < 1) { - return; - } - // Decrease bandwidth_lo whenever there is loss. - // Set bandwidth_lo_ if it is not yet set. - if (bandwidth_lo_.IsInfinite()) { - bandwidth_lo_ = MaxBandwidth(); - } - // Save bandwidth_lo_ if it hasn't already been saved. - if (prior_bandwidth_lo_.IsZero()) { - prior_bandwidth_lo_ = bandwidth_lo_; - } - switch (Params().bw_lo_mode_) { - case Bbr2Params::MIN_RTT_REDUCTION: - bandwidth_lo_ = - bandwidth_lo_ - QuicBandwidth::FromBytesAndTimeDelta( - congestion_event.bytes_lost, MinRtt()); - break; - case Bbr2Params::INFLIGHT_REDUCTION: { - // Use a max of BDP and inflight to avoid starving app-limited flows. - const QuicByteCount effective_inflight = - std::max(BDP(), congestion_event.prior_bytes_in_flight); - // This could use bytes_lost_in_round if the bandwidth_lo_ was saved - // when entering 'recovery', but this BBRv2 implementation doesn't have - // recovery defined. - bandwidth_lo_ = bandwidth_lo_ * - ((effective_inflight - congestion_event.bytes_lost) / - static_cast<double>(effective_inflight)); - break; + + if (bytes_lost_in_round_ > 0) { + if (bandwidth_lo_.IsInfinite()) { + bandwidth_lo_ = MaxBandwidth(); } - case Bbr2Params::CWND_REDUCTION: - bandwidth_lo_ = - bandwidth_lo_ * - ((congestion_event.prior_cwnd - congestion_event.bytes_lost) / - static_cast<double>(congestion_event.prior_cwnd)); - break; - case Bbr2Params::DEFAULT: - QUIC_BUG(quic_bug_10466_1) << "Unreachable case DEFAULT."; - } - if (pacing_gain_ > Params().startup_full_bw_threshold) { - // In STARTUP, pacing_gain_ is applied to bandwidth_lo_ in - // UpdatePacingRate, so this backs that multiplication out to allow the - // pacing rate to decrease, but not below - // bandwidth_latest_ * startup_full_bw_threshold. - bandwidth_lo_ = - std::max(bandwidth_lo_, - bandwidth_latest_ * - (Params().startup_full_bw_threshold / pacing_gain_)); - } else { - // Ensure bandwidth_lo isn't lower than bandwidth_latest_. - bandwidth_lo_ = std::max(bandwidth_lo_, bandwidth_latest_); - } - // If it's the end of the round, ensure bandwidth_lo doesn't decrease more - // than beta. - if (GetQuicReloadableFlag(quic_bbr2_fix_bw_lo_mode) && - congestion_event.end_of_round_trip) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr2_fix_bw_lo_mode, 2, 2); bandwidth_lo_ = - std::max(bandwidth_lo_, prior_bandwidth_lo_ * (1.0 - Params().beta)); - prior_bandwidth_lo_ = QuicBandwidth::Zero(); + std::max(bandwidth_latest_, bandwidth_lo_ * (1.0 - Params().beta)); + QUIC_DVLOG(3) << "bandwidth_lo_ updated to " << bandwidth_lo_ + << ", bandwidth_latest_ is " << bandwidth_latest_; + + if (Params().ignore_inflight_lo) { + return; + } + if (inflight_lo_ == inflight_lo_default()) { + inflight_lo_ = congestion_event.prior_cwnd; + } + inflight_lo_ = std::max<QuicByteCount>( + inflight_latest_, inflight_lo_ * (1.0 - Params().beta)); } - // This early return ignores inflight_lo as well. return; } - if (!congestion_event.end_of_round_trip || - congestion_event.is_probing_for_bandwidth) { + + // Params().bw_lo_mode_ != Bbr2Params::DEFAULT + if (congestion_event.bytes_lost == 0) { return; } - - if (bytes_lost_in_round_ > 0) { - if (bandwidth_lo_.IsInfinite()) { - bandwidth_lo_ = MaxBandwidth(); + // Ignore losses from packets sent when probing for more bandwidth in + // STARTUP or PROBE_UP when they're lost in DRAIN or PROBE_DOWN. + if (pacing_gain_ < 1) { + return; + } + // Decrease bandwidth_lo whenever there is loss. + // Set bandwidth_lo_ if it is not yet set. + if (bandwidth_lo_.IsInfinite()) { + bandwidth_lo_ = MaxBandwidth(); + } + // Save bandwidth_lo_ if it hasn't already been saved. + if (prior_bandwidth_lo_.IsZero()) { + prior_bandwidth_lo_ = bandwidth_lo_; + } + switch (Params().bw_lo_mode_) { + case Bbr2Params::MIN_RTT_REDUCTION: + bandwidth_lo_ = + bandwidth_lo_ - QuicBandwidth::FromBytesAndTimeDelta( + congestion_event.bytes_lost, MinRtt()); + break; + case Bbr2Params::INFLIGHT_REDUCTION: { + // Use a max of BDP and inflight to avoid starving app-limited flows. + const QuicByteCount effective_inflight = + std::max(BDP(), congestion_event.prior_bytes_in_flight); + // This could use bytes_lost_in_round if the bandwidth_lo_ was saved + // when entering 'recovery', but this BBRv2 implementation doesn't have + // recovery defined. + bandwidth_lo_ = + bandwidth_lo_ * ((effective_inflight - congestion_event.bytes_lost) / + static_cast<double>(effective_inflight)); + break; } + case Bbr2Params::CWND_REDUCTION: + bandwidth_lo_ = + bandwidth_lo_ * + ((congestion_event.prior_cwnd - congestion_event.bytes_lost) / + static_cast<double>(congestion_event.prior_cwnd)); + break; + case Bbr2Params::DEFAULT: + QUIC_BUG(quic_bug_10466_1) << "Unreachable case DEFAULT."; + } + QuicBandwidth last_bandwidth = bandwidth_latest_; + // sample_max_bandwidth will be Zero() if the loss is triggered by a timer + // expiring. Ideally we'd use the most recent bandwidth sample, + // but bandwidth_latest is safer than Zero(). + if (GetQuicReloadableFlag(quic_bbr2_fix_bw_lo_mode2) && + !congestion_event.sample_max_bandwidth.IsZero()) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr2_fix_bw_lo_mode2, 1, 2); + // bandwidth_latest_ is the max bandwidth for the round, but to allow + // fast, conservation style response to loss, use the last sample. + last_bandwidth = congestion_event.sample_max_bandwidth; + } + if (pacing_gain_ > Params().startup_full_bw_threshold) { + // In STARTUP, pacing_gain_ is applied to bandwidth_lo_ in + // UpdatePacingRate, so this backs that multiplication out to allow the + // pacing rate to decrease, but not below + // last_bandwidth * startup_full_bw_threshold. + // TODO(ianswett): Consider altering pacing_gain_ when in STARTUP instead. + bandwidth_lo_ = std::max( + bandwidth_lo_, + last_bandwidth * (Params().startup_full_bw_threshold / pacing_gain_)); + } else { + // Ensure bandwidth_lo isn't lower than last_bandwidth. + bandwidth_lo_ = std::max(bandwidth_lo_, last_bandwidth); + } + // If it's the end of the round, ensure bandwidth_lo doesn't decrease more + // than beta. + if (GetQuicReloadableFlag(quic_bbr2_fix_bw_lo_mode) && + congestion_event.end_of_round_trip) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr2_fix_bw_lo_mode, 2, 2); bandwidth_lo_ = - std::max(bandwidth_latest_, bandwidth_lo_ * (1.0 - Params().beta)); - QUIC_DVLOG(3) << "bandwidth_lo_ updated to " << bandwidth_lo_ - << ", bandwidth_latest_ is " << bandwidth_latest_; - - if (Params().ignore_inflight_lo) { - return; - } - if (inflight_lo_ == inflight_lo_default()) { - inflight_lo_ = congestion_event.prior_cwnd; - } - inflight_lo_ = std::max<QuicByteCount>( - inflight_latest_, inflight_lo_ * (1.0 - Params().beta)); + std::max(bandwidth_lo_, prior_bandwidth_lo_ * (1.0 - Params().beta)); + prior_bandwidth_lo_ = QuicBandwidth::Zero(); } + // These modes ignore inflight_lo as well. } void Bbr2NetworkModel::OnCongestionEventFinish( 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 8f5d4185dfc..b7007f55705 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 @@ -92,7 +92,7 @@ struct QUIC_EXPORT_PRIVATE Bbr2Params { // If true, always exit STARTUP on loss, even if bandwidth exceeds threshold. // If false, exit STARTUP on loss only if bandwidth is below threshold. - bool always_exit_startup_on_excess_loss = true; + bool always_exit_startup_on_excess_loss = false; /* * DRAIN parameters. @@ -313,6 +313,8 @@ struct QUIC_EXPORT_PRIVATE Bbr2CongestionEvent { QuicTime::Delta sample_min_rtt = QuicTime::Delta::Infinite(); // Maximum bandwidth of all bandwidth samples from acked_packets. + // This sample may be app-limited, and will be Zero() if there are no newly + // acknowledged inflight packets. QuicBandwidth sample_max_bandwidth = QuicBandwidth::Zero(); // The send state of the largest packet in acked_packets, unless it is empty. diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_bw.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_bw.cc index 9045d7e034b..af0f00fee80 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_bw.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_bw.cc @@ -500,6 +500,15 @@ void Bbr2ProbeBwMode::EnterProbeDown(bool probed_too_high, cycle_.rounds_in_phase = 0; cycle_.phase_start_time = now; ++sender_->connection_stats_->bbr_num_cycles; + if (GetQuicReloadableFlag(quic_bbr2_fix_bw_lo_mode2) && + Params().bw_lo_mode_ != Bbr2Params::QuicBandwidthLoMode::DEFAULT) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr2_fix_bw_lo_mode2, 2, 2); + // Clear bandwidth lo if it was set in PROBE_UP, because losses in PROBE_UP + // should not permanently change bandwidth_lo. + // It's possible for bandwidth_lo to be set during REFILL, but if that was + // a valid value, it'll quickly be rediscovered. + model_->clear_bandwidth_lo(); + } // Pick probe wait time. cycle_.rounds_since_probe = 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 d0f61277283..b69a7952afa 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 @@ -132,7 +132,7 @@ void Bbr2Sender::ApplyConnectionOptions( params_.ignore_inflight_lo = true; } if (ContainsQuicTag(connection_options, kB2NE)) { - params_.always_exit_startup_on_excess_loss = false; + params_.always_exit_startup_on_excess_loss = true; } if (ContainsQuicTag(connection_options, kB2SL)) { params_.startup_loss_exit_use_max_delivered_for_inflight_hi = false; 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 e26760e0bf9..99acf2c3e21 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 @@ -417,25 +417,6 @@ TEST_F(Bbr2DefaultTopologyTest, SimpleTransfer) { EXPECT_APPROX_EQ(params.RTT(), rtt_stats()->smoothed_rtt(), 1.0f); } -TEST_F(Bbr2DefaultTopologyTest, SimpleTransferB2NE) { - SetConnectionOption(kB2NE); - DefaultTopologyParams params; - CreateNetwork(params); - - // Transfer 12MB. - DoSimpleTransfer(12 * 1024 * 1024, QuicTime::Delta::FromSeconds(35)); - EXPECT_TRUE(Bbr2ModeIsOneOf({Bbr2Mode::PROBE_BW, Bbr2Mode::PROBE_RTT})); - - EXPECT_APPROX_EQ(params.BottleneckBandwidth(), - sender_->ExportDebugState().bandwidth_hi, 0.01f); - - EXPECT_LE(sender_loss_rate_in_packets(), 0.05); - // The margin here is high, because the aggregation greatly increases - // smoothed rtt. - EXPECT_GE(params.RTT() * 4, rtt_stats()->smoothed_rtt()); - EXPECT_APPROX_EQ(params.RTT(), rtt_stats()->min_rtt(), 0.2f); -} - TEST_F(Bbr2DefaultTopologyTest, SimpleTransferB2RC) { SetConnectionOption(kB2RC); DefaultTopologyParams params; @@ -859,6 +840,42 @@ TEST_F(Bbr2DefaultTopologyTest, ExitStartupDueToLossB2SL) { EXPECT_APPROX_EQ(sender_->ExportDebugState().inflight_hi, params.BDP(), 0.1f); } +// Verifies that in STARTUP, if we exceed loss threshold in a round, we exit +// STARTUP at the end of the round even if there's enough bandwidth growth. +TEST_F(Bbr2DefaultTopologyTest, ExitStartupDueToLossB2NE) { + // Set up flags such that any loss will be considered "too high". + SetQuicFlag(FLAGS_quic_bbr2_default_startup_full_loss_count, 0); + SetQuicFlag(FLAGS_quic_bbr2_default_loss_threshold, 0.0); + + sender_ = SetupBbr2Sender(&sender_endpoint_, /*old_sender=*/nullptr); + + SetConnectionOption(kB2NE); + DefaultTopologyParams params; + params.switch_queue_capacity_in_bdp = 0.5; + CreateNetwork(params); + + // Run until the full bandwidth is reached and check how many rounds it was. + sender_endpoint_.AddBytesToTransfer(12 * 1024 * 1024); + QuicRoundTripCount max_bw_round = 0; + QuicBandwidth max_bw(QuicBandwidth::Zero()); + bool simulator_result = simulator_.RunUntilOrTimeout( + [this, &max_bw, &max_bw_round]() { + if (max_bw < sender_->ExportDebugState().bandwidth_hi) { + max_bw = sender_->ExportDebugState().bandwidth_hi; + max_bw_round = sender_->ExportDebugState().round_trip_count; + } + return sender_->ExportDebugState().startup.full_bandwidth_reached; + }, + QuicTime::Delta::FromSeconds(5)); + ASSERT_TRUE(simulator_result); + EXPECT_EQ(Bbr2Mode::DRAIN, sender_->ExportDebugState().mode); + EXPECT_EQ(sender_->ExportDebugState().round_trip_count, max_bw_round); + EXPECT_EQ( + 0u, + sender_->ExportDebugState().startup.round_trips_without_bandwidth_growth); + EXPECT_NE(0u, sender_connection_stats().packets_lost); +} + TEST_F(Bbr2DefaultTopologyTest, SenderPoliced) { DefaultTopologyParams params; params.sender_policer_params = TrafficPolicerParams(); diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_startup.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_startup.cc index 5a9a532e688..1bd89c6024f 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_startup.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_startup.cc @@ -112,8 +112,9 @@ void Bbr2StartupMode::CheckExcessiveLosses( new_inflight_hi = model_->max_bytes_delivered_in_round(); } } - QUIC_DVLOG(3) << sender_ << " Exiting STARTUP due to loss. inflight_hi:" - << new_inflight_hi; + QUIC_DVLOG(3) << sender_ << " Exiting STARTUP due to loss at round " + << model_->RoundTripCount() + << ". inflight_hi:" << new_inflight_hi; // TODO(ianswett): Add a shared method to set inflight_hi in the model. model_->set_inflight_hi(new_inflight_hi); model_->set_full_bandwidth_reached(); diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_12_decrypter_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_12_decrypter_test.cc index c16668b2fdd..dccd7dfa48d 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_12_decrypter_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_12_decrypter_test.cc @@ -13,7 +13,6 @@ #include "quic/core/quic_utils.h" #include "quic/platform/api/quic_test.h" #include "quic/test_tools/quic_test_utils.h" -#include "common/platform/api/quiche_text_utils.h" #include "common/test_tools/quiche_test_utils.h" namespace { diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_12_encrypter_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_12_encrypter_test.cc index 5c093ad4ee0..67e35ed8934 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_12_encrypter_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_12_encrypter_test.cc @@ -13,7 +13,6 @@ #include "quic/core/quic_utils.h" #include "quic/platform/api/quic_test.h" #include "quic/test_tools/quic_test_utils.h" -#include "common/platform/api/quiche_text_utils.h" #include "common/test_tools/quiche_test_utils.h" namespace { diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_decrypter_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_decrypter_test.cc index 6877d9de48f..25abd716576 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_decrypter_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_decrypter_test.cc @@ -12,7 +12,6 @@ #include "quic/core/quic_utils.h" #include "quic/platform/api/quic_test.h" #include "quic/test_tools/quic_test_utils.h" -#include "common/platform/api/quiche_text_utils.h" #include "common/test_tools/quiche_test_utils.h" namespace { diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_encrypter_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_encrypter_test.cc index d51c5deb0ea..7e5fb25a937 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_encrypter_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_encrypter_test.cc @@ -12,7 +12,6 @@ #include "quic/core/quic_utils.h" #include "quic/platform/api/quic_test.h" #include "quic/test_tools/quic_test_utils.h" -#include "common/platform/api/quiche_text_utils.h" #include "common/test_tools/quiche_test_utils.h" namespace { diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/aes_256_gcm_decrypter_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/aes_256_gcm_decrypter_test.cc index bfafd2cb513..c63a589a3d8 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/aes_256_gcm_decrypter_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/aes_256_gcm_decrypter_test.cc @@ -13,7 +13,6 @@ #include "quic/core/quic_utils.h" #include "quic/platform/api/quic_test.h" #include "quic/test_tools/quic_test_utils.h" -#include "common/platform/api/quiche_text_utils.h" #include "common/test_tools/quiche_test_utils.h" namespace { diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/aes_256_gcm_encrypter_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/aes_256_gcm_encrypter_test.cc index 8d4c1de8e16..a2f8066717c 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/aes_256_gcm_encrypter_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/aes_256_gcm_encrypter_test.cc @@ -13,7 +13,6 @@ #include "quic/core/quic_utils.h" #include "quic/platform/api/quic_test.h" #include "quic/test_tools/quic_test_utils.h" -#include "common/platform/api/quiche_text_utils.h" #include "common/test_tools/quiche_test_utils.h" namespace { diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/cert_compressor_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/cert_compressor_test.cc index b76ee7bf8d4..a024d131c2a 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/cert_compressor_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/cert_compressor_test.cc @@ -12,7 +12,6 @@ #include "quic/core/quic_utils.h" #include "quic/platform/api/quic_test.h" #include "quic/test_tools/crypto_test_utils.h" -#include "common/platform/api/quiche_text_utils.h" namespace quic { namespace test { diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view.cc index c21dd202b2d..4024a78e952 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view.cc @@ -30,9 +30,9 @@ #include "quic/platform/api/quic_bug_tracker.h" #include "quic/platform/api/quic_ip_address.h" #include "quic/platform/api/quic_logging.h" -#include "common/platform/api/quiche_text_utils.h" #include "common/platform/api/quiche_time_utils.h" #include "common/quiche_data_reader.h" +#include "common/quiche_text_utils.h" namespace quic { namespace { diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_decrypter_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_decrypter_test.cc index 42d8899a781..93e48d257d0 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_decrypter_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_decrypter_test.cc @@ -12,7 +12,6 @@ #include "quic/core/quic_utils.h" #include "quic/platform/api/quic_test.h" #include "quic/test_tools/quic_test_utils.h" -#include "common/platform/api/quiche_text_utils.h" #include "common/test_tools/quiche_test_utils.h" namespace { diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_encrypter_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_encrypter_test.cc index 8c403fede35..7fc32822f7e 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_encrypter_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_encrypter_test.cc @@ -8,12 +8,12 @@ #include <string> #include "absl/base/macros.h" +#include "absl/strings/escaping.h" #include "absl/strings/string_view.h" #include "quic/core/crypto/chacha20_poly1305_decrypter.h" #include "quic/core/quic_utils.h" #include "quic/platform/api/quic_test.h" #include "quic/test_tools/quic_test_utils.h" -#include "common/platform/api/quiche_text_utils.h" #include "common/test_tools/quiche_test_utils.h" namespace { diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_tls_decrypter_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_tls_decrypter_test.cc index 4b0f10bcd0d..b71bcf127f8 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_tls_decrypter_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_tls_decrypter_test.cc @@ -12,7 +12,6 @@ #include "quic/core/quic_utils.h" #include "quic/platform/api/quic_test.h" #include "quic/test_tools/quic_test_utils.h" -#include "common/platform/api/quiche_text_utils.h" #include "common/test_tools/quiche_test_utils.h" namespace { diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_tls_encrypter_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_tls_encrypter_test.cc index 7bca425a708..61aaac73d17 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_tls_encrypter_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_tls_encrypter_test.cc @@ -14,7 +14,6 @@ #include "quic/core/quic_utils.h" #include "quic/platform/api/quic_test.h" #include "quic/test_tools/quic_test_utils.h" -#include "common/platform/api/quiche_text_utils.h" #include "common/test_tools/quiche_test_utils.h" namespace { diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_message_printer_bin.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_message_printer_bin.cc index 3109924d59e..68e3d9cbe19 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_message_printer_bin.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_message_printer_bin.cc @@ -13,7 +13,6 @@ #include "absl/strings/escaping.h" #include "quic/core/crypto/crypto_framer.h" #include "quic/core/quic_utils.h" -#include "common/platform/api/quiche_text_utils.h" using std::cerr; using std::cout; 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 e08d90b1c08..af62865b653 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h @@ -28,7 +28,7 @@ using ServerConfigID = std::string; // The following tags have been deprecated and should not be reused: // "1CON", "BBQ4", "NCON", "RCID", "SREJ", "TBKP", "TB10", "SCLS", "SMHL", -// "QNZR", "B2HI", "H2PR", "FIFO", "LIFO", "RRWS" +// "QNZR", "B2HI", "H2PR", "FIFO", "LIFO", "RRWS", "QNSP" // clang-format off const QuicTag kCHLO = TAG('C', 'H', 'L', 'O'); // Client hello @@ -127,9 +127,10 @@ const QuicTag kIW50 = TAG('I', 'W', '5', '0'); // Force ICWND to 50 const QuicTag kB2ON = TAG('B', '2', 'O', 'N'); // Enable BBRv2 const QuicTag kB2NA = TAG('B', '2', 'N', 'A'); // For BBRv2, do not add ack // height to queueing threshold -const QuicTag kB2NE = TAG('B', '2', 'N', 'E'); // For BBRv2, do not exit - // STARTUP if there's enough - // bandwidth growth +const QuicTag kB2NE = TAG('B', '2', 'N', 'E'); // For BBRv2, always exit + // STARTUP on loss, even if + // bandwidth growth exceeds + // threshold. const QuicTag kB2RP = TAG('B', '2', 'R', 'P'); // For BBRv2, run PROBE_RTT on // the regular schedule const QuicTag kB2CL = TAG('B', '2', 'C', 'L'); // For BBRv2, allow PROBE_BW @@ -342,6 +343,7 @@ const QuicTag kMTUL = TAG('M', 'T', 'U', 'L'); // Low-target MTU discovery. const QuicTag kNSLC = TAG('N', 'S', 'L', 'C'); // Always send connection close // for idle timeout. +const QuicTag kCHSP = TAG('C', 'H', 'S', 'P'); // Chaos protection. // Proof types (i.e. certificate types) // NOTE: although it would be silly to do so, specifying both kX509 and kX59R @@ -401,9 +403,6 @@ const QuicTag kPDP5 = TAG('P', 'D', 'P', '5'); // Path degrading triggered const QuicTag kQNZ2 = TAG('Q', 'N', 'Z', '2'); // Turn off QUIC crypto 0-RTT. -const QuicTag kQNSP = TAG('Q', 'N', 'S', 'P'); // Turn off server push in - // gQUIC. - const QuicTag kMAD = TAG('M', 'A', 'D', 0); // Max Ack Delay (IETF QUIC) const QuicTag kIGNP = TAG('I', 'G', 'N', 'P'); // Do not use PING only packet 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 7414eda8692..7fadbbdcef7 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 @@ -33,7 +33,6 @@ #include "quic/test_tools/mock_random.h" #include "quic/test_tools/quic_crypto_server_config_peer.h" #include "quic/test_tools/quic_test_utils.h" -#include "common/platform/api/quiche_text_utils.h" #include "common/quiche_endian.h" namespace quic { 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 2c8435035c9..67527d45826 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 @@ -762,4 +762,21 @@ std::string CryptoUtils::HashHandshakeMessage( } #undef RETURN_STRING_LITERAL // undef for jumbo builds + +// static +bool CryptoUtils::GetSSLCapabilities(const SSL* ssl, + bssl::UniquePtr<uint8_t>* capabilities, + size_t* capabilities_len) { + uint8_t* buffer; + CBB cbb; + + if (!CBB_init(&cbb, 128) || !SSL_serialize_capabilities(ssl, &cbb) || + !CBB_finish(&cbb, &buffer, capabilities_len)) { + return false; + } + + *capabilities = bssl::UniquePtr<uint8_t>(buffer); + return true; +} + } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils.h b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils.h index ec68c6580f4..7aa32e1445a 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils.h +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils.h @@ -237,6 +237,11 @@ class QUIC_EXPORT_PRIVATE CryptoUtils { // Returns a hash of the serialized |message|. static std::string HashHandshakeMessage(const CryptoHandshakeMessage& message, Perspective perspective); + + // Wraps SSL_serialize_capabilities. Return nullptr if failed. + static bool GetSSLCapabilities(const SSL* ssl, + bssl::UniquePtr<uint8_t>* capabilities, + size_t* capabilities_len); }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils_test.cc index 4586b9bbb4a..0f2df3a7f90 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils_test.cc @@ -11,7 +11,6 @@ #include "quic/core/quic_utils.h" #include "quic/platform/api/quic_test.h" #include "quic/test_tools/quic_test_utils.h" -#include "common/platform/api/quiche_text_utils.h" #include "common/test_tools/quiche_test_utils.h" namespace quic { diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source.h b/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source.h index cee94f2e4af..31cbfd66114 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source.h +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source.h @@ -229,12 +229,15 @@ class QUIC_EXPORT_PRIVATE ProofSourceHandleCallback { // whether it is completed before ProofSourceHandle::SelectCertificate // returned. // |chain| the certificate chain in leaf-first order. + // |handshake_hints| (optional) handshake hints that can be used by + // SSL_set_handshake_hints. // // When called asynchronously(is_sync=false), this method will be responsible // to continue the handshake from where it left off. virtual void OnSelectCertificateDone(bool ok, bool is_sync, - const ProofSource::Chain* chain) = 0; + const ProofSource::Chain* chain, + absl::string_view handshake_hints) = 0; // Called when a ProofSourceHandle::ComputeSignature operation completes. virtual void OnComputeSignatureDone( @@ -280,9 +283,11 @@ class QUIC_EXPORT_PRIVATE ProofSourceHandle { virtual QuicAsyncStatus SelectCertificate( const QuicSocketAddress& server_address, const QuicSocketAddress& client_address, + absl::string_view ssl_capabilities, const std::string& hostname, absl::string_view client_hello, const std::string& alpn, + absl::optional<std::string> alps, const std::vector<uint8_t>& quic_transport_params, const absl::optional<std::vector<uint8_t>>& early_data_context) = 0; diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.cc index c886cbe989e..3f94e7cda60 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.cc @@ -34,7 +34,6 @@ #include "quic/platform/api/quic_hostname_utils.h" #include "quic/platform/api/quic_logging.h" #include "quic/platform/api/quic_map_util.h" -#include "common/platform/api/quiche_text_utils.h" namespace quic { diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.cc index 4f19533b008..f2a88095aac 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 @@ -51,7 +51,6 @@ #include "quic/platform/api/quic_reference_counted.h" #include "quic/platform/api/quic_socket_address.h" #include "quic/platform/api/quic_testvalue.h" -#include "common/platform/api/quiche_text_utils.h" namespace quic { @@ -745,9 +744,7 @@ void QuicCryptoServerConfig::ProcessClientHelloAfterGetProof( << context->connection_id() << " which is invalid with version " << context->version(); - if (context->validate_chlo_result()->postpone_cert_validate_for_server && - context->info().reject_reasons.empty()) { - QUIC_RELOADABLE_FLAG_COUNT(quic_crypto_postpone_cert_validate_for_server); + if (context->info().reject_reasons.empty()) { if (!context->signed_config() || !context->signed_config()->chain) { // No chain. context->validate_chlo_result()->info.reject_reasons.push_back( @@ -1224,8 +1221,8 @@ void QuicCryptoServerConfig::SelectNewPrimaryConfig( } void QuicCryptoServerConfig::EvaluateClientHello( - const QuicSocketAddress& server_address, - const QuicSocketAddress& client_address, + const QuicSocketAddress& /*server_address*/, + const QuicSocketAddress& /*client_address*/, QuicTransportVersion /*version*/, const Configs& configs, QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result> @@ -1294,17 +1291,6 @@ void QuicCryptoServerConfig::EvaluateClientHello( // No valid source address token. } - if (!client_hello_state->postpone_cert_validate_for_server) { - QuicReferenceCountedPointer<ProofSource::Chain> chain = - proof_source_->GetCertChain(server_address, client_address, - std::string(info->sni)); - if (!chain) { - info->reject_reasons.push_back(SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE); - } else if (!ValidateExpectedLeafCertificate(client_hello, chain->certs)) { - info->reject_reasons.push_back(INVALID_EXPECTED_LEAF_CERTIFICATE); - } - } - if (info->client_nonce.size() != kNonceSize) { info->reject_reasons.push_back(CLIENT_NONCE_INVALID_FAILURE); // Invalid client nonce. 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 464f2bbfc36..4f3ad0819e4 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 @@ -98,9 +98,6 @@ class QUIC_EXPORT_PRIVATE ValidateClientHelloResultCallback { // Populated if the CHLO STK contained a CachedNetworkParameters proto. CachedNetworkParameters cached_network_params; - const bool postpone_cert_validate_for_server = - GetQuicReloadableFlag(quic_crypto_postpone_cert_validate_for_server); - protected: ~Result() override; }; diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config_test.cc index 9f70c355237..484e46eee6a 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config_test.cc @@ -25,7 +25,6 @@ #include "quic/test_tools/mock_clock.h" #include "quic/test_tools/quic_crypto_server_config_peer.h" #include "quic/test_tools/quic_test_utils.h" -#include "common/platform/api/quiche_text_utils.h" namespace quic { namespace test { diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_hkdf_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_hkdf_test.cc index 73f850ed68a..e23d3f2a1e9 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_hkdf_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_hkdf_test.cc @@ -9,7 +9,6 @@ #include "absl/base/macros.h" #include "absl/strings/escaping.h" #include "quic/platform/api/quic_test.h" -#include "common/platform/api/quiche_text_utils.h" namespace quic { namespace test { diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/tls_server_connection.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/tls_server_connection.cc index 8926909cd78..6e9901b995e 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/tls_server_connection.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/tls_server_connection.cc @@ -30,16 +30,12 @@ bssl::UniquePtr<SSL_CTX> TlsServerConnection::CreateSslCtx( QUIC_CODE_COUNT(quic_session_tickets_enabled); SSL_CTX_set_ticket_aead_method(ssl_ctx.get(), &TlsServerConnection::kSessionTicketMethod); - } else if (!GetQuicRestartFlag(quic_session_tickets_always_enabled)) { - QUIC_CODE_COUNT(quic_session_tickets_disabled_by_flag); - SSL_CTX_set_options(ssl_ctx.get(), SSL_OP_NO_TICKET); } else { QUIC_CODE_COUNT(quic_session_tickets_disabled); } - if (proof_source->GetTicketCrypter() || - GetQuicRestartFlag(quic_session_tickets_always_enabled)) { - SSL_CTX_set_early_data_enabled(ssl_ctx.get(), 1); - } + + SSL_CTX_set_early_data_enabled(ssl_ctx.get(), 1); + SSL_CTX_set_select_certificate_cb( ssl_ctx.get(), &TlsServerConnection::EarlySelectCertCallback); SSL_CTX_set_options(ssl_ctx.get(), SSL_OP_CIPHER_SERVER_PREFERENCE); diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_new_token_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_new_token_frame.cc index 8ad442fc694..8642fd93265 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_new_token_frame.cc +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_new_token_frame.cc @@ -6,7 +6,6 @@ #include "absl/strings/escaping.h" #include "quic/platform/api/quic_logging.h" -#include "common/platform/api/quiche_text_utils.h" namespace quic { diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_path_challenge_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_path_challenge_frame.cc index 857ca19291f..0f88bb83160 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_path_challenge_frame.cc +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_path_challenge_frame.cc @@ -6,7 +6,6 @@ #include "absl/strings/escaping.h" #include "quic/platform/api/quic_bug_tracker.h" -#include "common/platform/api/quiche_text_utils.h" namespace quic { diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_path_response_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_path_response_frame.cc index ade4156b8ab..f802b131b30 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_path_response_frame.cc +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_path_response_frame.cc @@ -6,7 +6,6 @@ #include "absl/strings/escaping.h" #include "quic/platform/api/quic_bug_tracker.h" -#include "common/platform/api/quiche_text_utils.h" namespace quic { diff --git a/chromium/net/third_party/quiche/src/quic/core/handshaker_delegate_interface.h b/chromium/net/third_party/quiche/src/quic/core/handshaker_delegate_interface.h index ae291b7826f..1e47d16a5f1 100644 --- a/chromium/net/third_party/quiche/src/quic/core/handshaker_delegate_interface.h +++ b/chromium/net/third_party/quiche/src/quic/core/handshaker_delegate_interface.h @@ -74,6 +74,9 @@ class QUIC_EXPORT_PRIVATE HandshakerDelegateInterface { // Called at the end of an handshake operation callback. virtual void OnHandshakeCallbackDone() = 0; + + // Whether a packet flusher is currently attached. + virtual bool PacketFlusherAttached() const = 0; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/http/end_to_end_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/end_to_end_test.cc index aceebe1b33b..8efba8869bf 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 @@ -17,6 +17,7 @@ #include "quic/core/http/http_constants.h" #include "quic/core/http/quic_spdy_client_stream.h" #include "quic/core/http/web_transport_http3.h" +#include "quic/core/quic_connection.h" #include "quic/core/quic_data_writer.h" #include "quic/core/quic_epoll_connection_helper.h" #include "quic/core/quic_error_codes.h" @@ -43,7 +44,6 @@ #include "quic/test_tools/packet_reordering_writer.h" #include "quic/test_tools/qpack/qpack_encoder_peer.h" #include "quic/test_tools/qpack/qpack_encoder_test_utils.h" -#include "quic/test_tools/qpack/qpack_header_table_peer.h" #include "quic/test_tools/qpack/qpack_test_utils.h" #include "quic/test_tools/quic_client_peer.h" #include "quic/test_tools/quic_config_peer.h" @@ -80,6 +80,7 @@ using ::testing::_; using ::testing::Assign; using ::testing::Invoke; using ::testing::NiceMock; +using testing::NotNull; namespace quic { namespace test { @@ -750,6 +751,18 @@ class EndToEndTest : public QuicTestWithParam<TestParams> { } } + void WaitForNewConnectionIds() { + // Wait until a new server CID is available for another migration. + const auto* client_connection = GetClientConnection(); + while (!QuicConnectionPeer::HasUnusedPeerIssuedConnectionId( + client_connection) || + (!client_connection->client_connection_id().IsEmpty() && + !QuicConnectionPeer::HasSelfIssuedConnectionIdToConsume( + client_connection))) { + client_->client()->WaitForEvents(); + } + } + ScopedEnvironmentForThreads environment_; bool initialized_; // If true, the Initialize() function will create |client_| and starts to @@ -1552,17 +1565,11 @@ TEST_P(EndToEndTest, AddressToken) { server_thread_->Pause(); QuicConnection* server_connection = GetServerConnection(); if (server_connection != nullptr) { - if (GetQuicReloadableFlag(quic_enable_token_based_address_validation)) { - // Verify address is validated via validating token received in INITIAL - // packet. - EXPECT_FALSE(server_connection->GetStats() - .address_validated_via_decrypting_packet); - EXPECT_TRUE(server_connection->GetStats().address_validated_via_token); - } else { - EXPECT_TRUE(server_connection->GetStats() - .address_validated_via_decrypting_packet); - EXPECT_FALSE(server_connection->GetStats().address_validated_via_token); - } + // Verify address is validated via validating token received in INITIAL + // packet. + EXPECT_FALSE( + server_connection->GetStats().address_validated_via_decrypting_packet); + EXPECT_TRUE(server_connection->GetStats().address_validated_via_token); } else { ADD_FAILURE() << "Missing server connection"; } @@ -2477,10 +2484,7 @@ TEST_P( HalfRttResponseBlocksShloRetransmissionWithoutTokenBasedAddressValidation) { // Turn off token based address validation to make the server get constrained // by amplification factor during handshake. - // TODO(fayang): Keep this test while deprecating - // quic_enable_token_based_address_validation. For example, consider always - // rejecting the received address token. - SetQuicReloadableFlag(quic_enable_token_based_address_validation, false); + SetQuicFlag(FLAGS_quic_reject_retry_token_in_initial_packet, true); ASSERT_TRUE(Initialize()); if (!version_.SupportsAntiAmplificationLimit()) { return; @@ -2502,17 +2506,8 @@ TEST_P( // Large response (100KB) for 0-RTT request. std::string large_body(102400, 'a'); AddToCache("/large_response", 200, large_body); - if (GetQuicReloadableFlag(quic_preempt_stream_data_with_handshake_packet)) { - SendSynchronousRequestAndCheckResponse(client_.get(), "/large_response", - large_body); - } else { - // Server consistently gets constrained by amplification factor, hence PTO - // never gets armed. The CHLO retransmission would trigger the - // retransmission of SHLO, however, the ENCRYPTION_HANDSHAKE packet NEVER - // gets retransmitted since half RTT data consumes the remaining space in - // the coalescer. - EXPECT_EQ("", client_->SendSynchronousRequest("/large_response")); - } + SendSynchronousRequestAndCheckResponse(client_.get(), "/large_response", + large_body); } TEST_P(EndToEndTest, MaxStreamsUberTest) { @@ -2620,6 +2615,253 @@ TEST_P(EndToEndTest, ConnectionMigrationClientIPChanged) { server_thread_->Resume(); } +TEST_P(EndToEndTest, IetfConnectionMigrationClientIPChangedMultipleTimes) { + ASSERT_TRUE(Initialize()); + if (!GetClientConnection()->connection_migration_use_new_cid()) { + return; + } + SendSynchronousFooRequestAndCheckResponse(); + + // Store the client IP address which was used to send the first request. + QuicIpAddress host0 = + client_->client()->network_helper()->GetLatestClientAddress().host(); + QuicConnection* client_connection = GetClientConnection(); + ASSERT_TRUE(client_connection != nullptr); + + // Migrate socket to a new IP address. + QuicIpAddress host1 = TestLoopback(2); + EXPECT_NE(host0, host1); + ASSERT_TRUE( + QuicConnectionPeer::HasUnusedPeerIssuedConnectionId(client_connection)); + QuicConnectionId server_cid0 = client_connection->connection_id(); + EXPECT_TRUE(QuicConnectionPeer::GetServerConnectionIdOnAlternativePath( + client_connection) + .IsEmpty()); + EXPECT_TRUE(client_->client()->MigrateSocket(host1)); + QuicConnectionId server_cid1 = client_connection->connection_id(); + EXPECT_FALSE(server_cid1.IsEmpty()); + EXPECT_NE(server_cid0, server_cid1); + EXPECT_TRUE(QuicConnectionPeer::GetServerConnectionIdOnAlternativePath( + client_connection) + .IsEmpty()); + + // Send a request using the new socket. + SendSynchronousBarRequestAndCheckResponse(); + EXPECT_EQ(1u, + client_connection->GetStats().num_connectivity_probing_received); + + // Send another request and wait for response making sure path response is + // received at server. + SendSynchronousBarRequestAndCheckResponse(); + + // Migrate socket to a new IP address. + WaitForNewConnectionIds(); + EXPECT_EQ(1u, client_connection->GetStats().num_retire_connection_id_sent); + QuicIpAddress host2 = TestLoopback(3); + EXPECT_NE(host0, host2); + EXPECT_NE(host1, host2); + EXPECT_TRUE(QuicConnectionPeer::GetServerConnectionIdOnAlternativePath( + client_connection) + .IsEmpty()); + EXPECT_TRUE(client_->client()->MigrateSocket(host2)); + QuicConnectionId server_cid2 = client_connection->connection_id(); + EXPECT_FALSE(server_cid2.IsEmpty()); + EXPECT_NE(server_cid0, server_cid2); + EXPECT_NE(server_cid1, server_cid2); + EXPECT_TRUE(QuicConnectionPeer::GetServerConnectionIdOnAlternativePath( + client_connection) + .IsEmpty()); + + // Send another request using the new socket and wait for response making sure + // path response is received at server. + SendSynchronousBarRequestAndCheckResponse(); + EXPECT_EQ(2u, + client_connection->GetStats().num_connectivity_probing_received); + + // Migrate socket back to an old IP address. + WaitForNewConnectionIds(); + EXPECT_EQ(2u, client_connection->GetStats().num_retire_connection_id_sent); + EXPECT_TRUE(QuicConnectionPeer::GetServerConnectionIdOnAlternativePath( + client_connection) + .IsEmpty()); + EXPECT_TRUE(client_->client()->MigrateSocket(host1)); + QuicConnectionId server_cid3 = client_connection->connection_id(); + EXPECT_FALSE(server_cid3.IsEmpty()); + EXPECT_NE(server_cid0, server_cid3); + EXPECT_NE(server_cid1, server_cid3); + EXPECT_NE(server_cid2, server_cid3); + EXPECT_TRUE(QuicConnectionPeer::GetServerConnectionIdOnAlternativePath( + client_connection) + .IsEmpty()); + const auto* client_packet_creator = + QuicConnectionPeer::GetPacketCreator(client_connection); + EXPECT_TRUE(client_packet_creator->GetClientConnectionId().IsEmpty()); + EXPECT_EQ(server_cid3, client_packet_creator->GetServerConnectionId()); + + // Send another request using the new socket and wait for response making sure + // path response is received at server. + SendSynchronousBarRequestAndCheckResponse(); + // Even this is an old path, server has forgotten about it and thus needs to + // validate the path again. + EXPECT_EQ(3u, + client_connection->GetStats().num_connectivity_probing_received); + + WaitForNewConnectionIds(); + EXPECT_EQ(3u, client_connection->GetStats().num_retire_connection_id_sent); + + server_thread_->Pause(); + QuicConnection* server_connection = GetServerConnection(); + // By the time the 2nd request is completed, the PATH_RESPONSE must have been + // received by the server. + EXPECT_FALSE(server_connection->HasPendingPathValidation()); + EXPECT_EQ(3u, server_connection->GetStats().num_validated_peer_migration); + EXPECT_EQ(server_cid3, server_connection->connection_id()); + const auto* server_packet_creator = + QuicConnectionPeer::GetPacketCreator(server_connection); + EXPECT_EQ(server_cid3, server_packet_creator->GetServerConnectionId()); + EXPECT_TRUE(QuicConnectionPeer::GetServerConnectionIdOnAlternativePath( + server_connection) + .IsEmpty()); + EXPECT_EQ(4u, server_connection->GetStats().num_new_connection_id_sent); + server_thread_->Resume(); +} + +TEST_P(EndToEndTest, + ConnectionMigrationWithNonZeroConnectionIDClientIPChangedMultipleTimes) { + if (!version_.SupportsClientConnectionIds()) { + ASSERT_TRUE(Initialize()); + return; + } + override_client_connection_id_length_ = kQuicDefaultConnectionIdLength; + ASSERT_TRUE(Initialize()); + if (!GetClientConnection()->connection_migration_use_new_cid()) { + return; + } + SendSynchronousFooRequestAndCheckResponse(); + + // Store the client IP address which was used to send the first request. + QuicIpAddress host0 = + client_->client()->network_helper()->GetLatestClientAddress().host(); + QuicConnection* client_connection = GetClientConnection(); + ASSERT_TRUE(client_connection != nullptr); + + // Migrate socket to a new IP address. + QuicIpAddress host1 = TestLoopback(2); + EXPECT_NE(host0, host1); + ASSERT_TRUE( + QuicConnectionPeer::HasUnusedPeerIssuedConnectionId(client_connection)); + QuicConnectionId server_cid0 = client_connection->connection_id(); + QuicConnectionId client_cid0 = client_connection->client_connection_id(); + EXPECT_TRUE(QuicConnectionPeer::GetServerConnectionIdOnAlternativePath( + client_connection) + .IsEmpty()); + EXPECT_TRUE(QuicConnectionPeer::GetClientConnectionIdOnAlternativePath( + client_connection) + .IsEmpty()); + EXPECT_TRUE(client_->client()->MigrateSocket(host1)); + QuicConnectionId server_cid1 = client_connection->connection_id(); + QuicConnectionId client_cid1 = client_connection->client_connection_id(); + EXPECT_FALSE(server_cid1.IsEmpty()); + EXPECT_FALSE(client_cid1.IsEmpty()); + EXPECT_NE(server_cid0, server_cid1); + EXPECT_NE(client_cid0, client_cid1); + EXPECT_TRUE(QuicConnectionPeer::GetServerConnectionIdOnAlternativePath( + client_connection) + .IsEmpty()); + EXPECT_TRUE(QuicConnectionPeer::GetClientConnectionIdOnAlternativePath( + client_connection) + .IsEmpty()); + + // Send another request to ensure that the server will have time to finish the + // reverse path validation and send address token. + SendSynchronousBarRequestAndCheckResponse(); + EXPECT_EQ(1u, + client_connection->GetStats().num_connectivity_probing_received); + + // Migrate socket to a new IP address. + WaitForNewConnectionIds(); + EXPECT_EQ(1u, client_connection->GetStats().num_retire_connection_id_sent); + EXPECT_EQ(2u, client_connection->GetStats().num_new_connection_id_sent); + QuicIpAddress host2 = TestLoopback(3); + EXPECT_NE(host0, host2); + EXPECT_NE(host1, host2); + EXPECT_TRUE(client_->client()->MigrateSocket(host2)); + QuicConnectionId server_cid2 = client_connection->connection_id(); + QuicConnectionId client_cid2 = client_connection->client_connection_id(); + EXPECT_FALSE(server_cid2.IsEmpty()); + EXPECT_NE(server_cid0, server_cid2); + EXPECT_NE(server_cid1, server_cid2); + EXPECT_FALSE(client_cid2.IsEmpty()); + EXPECT_NE(client_cid0, client_cid2); + EXPECT_NE(client_cid1, client_cid2); + EXPECT_TRUE(QuicConnectionPeer::GetServerConnectionIdOnAlternativePath( + client_connection) + .IsEmpty()); + EXPECT_TRUE(QuicConnectionPeer::GetClientConnectionIdOnAlternativePath( + client_connection) + .IsEmpty()); + + // Send another request to ensure that the server will have time to finish the + // reverse path validation and send address token. + SendSynchronousBarRequestAndCheckResponse(); + EXPECT_EQ(2u, + client_connection->GetStats().num_connectivity_probing_received); + + // Migrate socket back to an old IP address. + WaitForNewConnectionIds(); + EXPECT_EQ(2u, client_connection->GetStats().num_retire_connection_id_sent); + EXPECT_EQ(3u, client_connection->GetStats().num_new_connection_id_sent); + EXPECT_TRUE(client_->client()->MigrateSocket(host1)); + QuicConnectionId server_cid3 = client_connection->connection_id(); + QuicConnectionId client_cid3 = client_connection->client_connection_id(); + EXPECT_FALSE(server_cid3.IsEmpty()); + EXPECT_NE(server_cid0, server_cid3); + EXPECT_NE(server_cid1, server_cid3); + EXPECT_NE(server_cid2, server_cid3); + EXPECT_FALSE(client_cid3.IsEmpty()); + EXPECT_NE(client_cid0, client_cid3); + EXPECT_NE(client_cid1, client_cid3); + EXPECT_NE(client_cid2, client_cid3); + const auto* client_packet_creator = + QuicConnectionPeer::GetPacketCreator(client_connection); + EXPECT_EQ(client_cid3, client_packet_creator->GetClientConnectionId()); + EXPECT_EQ(server_cid3, client_packet_creator->GetServerConnectionId()); + EXPECT_TRUE(QuicConnectionPeer::GetServerConnectionIdOnAlternativePath( + client_connection) + .IsEmpty()); + + // Send another request to ensure that the server will have time to finish the + // reverse path validation and send address token. + SendSynchronousBarRequestAndCheckResponse(); + // Even this is an old path, server has forgotten about it and thus needs to + // validate the path again. + EXPECT_EQ(3u, + client_connection->GetStats().num_connectivity_probing_received); + + WaitForNewConnectionIds(); + EXPECT_EQ(3u, client_connection->GetStats().num_retire_connection_id_sent); + EXPECT_EQ(4u, client_connection->GetStats().num_new_connection_id_sent); + + server_thread_->Pause(); + // By the time the 2nd request is completed, the PATH_RESPONSE must have been + // received by the server. + QuicConnection* server_connection = GetServerConnection(); + EXPECT_FALSE(server_connection->HasPendingPathValidation()); + EXPECT_EQ(3u, server_connection->GetStats().num_validated_peer_migration); + EXPECT_EQ(server_cid3, server_connection->connection_id()); + EXPECT_EQ(client_cid3, server_connection->client_connection_id()); + EXPECT_TRUE(QuicConnectionPeer::GetServerConnectionIdOnAlternativePath( + server_connection) + .IsEmpty()); + const auto* server_packet_creator = + QuicConnectionPeer::GetPacketCreator(server_connection); + EXPECT_EQ(client_cid3, server_packet_creator->GetClientConnectionId()); + EXPECT_EQ(server_cid3, server_packet_creator->GetServerConnectionId()); + EXPECT_EQ(3u, server_connection->GetStats().num_retire_connection_id_sent); + EXPECT_EQ(4u, server_connection->GetStats().num_new_connection_id_sent); + server_thread_->Resume(); +} + TEST_P(EndToEndTest, ConnectionMigrationNewTokenForNewIp) { ASSERT_TRUE(Initialize()); if (!version_.HasIetfQuicFrames() || @@ -2644,7 +2886,7 @@ TEST_P(EndToEndTest, ConnectionMigrationNewTokenForNewIp) { EXPECT_EQ(1u, client_connection->GetStats().num_connectivity_probing_received); - // Send another request to ensure that the server will time to finish the + // Send another request to ensure that the server will have time to finish the // reverse path validation and send address token. SendSynchronousBarRequestAndCheckResponse(); @@ -2661,17 +2903,11 @@ TEST_P(EndToEndTest, ConnectionMigrationNewTokenForNewIp) { server_thread_->Pause(); QuicConnection* server_connection = GetServerConnection(); if (server_connection != nullptr) { - if (GetQuicReloadableFlag(quic_enable_token_based_address_validation)) { - // Verify address is validated via validating token received in INITIAL - // packet. - EXPECT_FALSE(server_connection->GetStats() - .address_validated_via_decrypting_packet); - EXPECT_TRUE(server_connection->GetStats().address_validated_via_token); - } else { - EXPECT_TRUE(server_connection->GetStats() - .address_validated_via_decrypting_packet); - EXPECT_FALSE(server_connection->GetStats().address_validated_via_token); - } + // Verify address is validated via validating token received in INITIAL + // packet. + EXPECT_FALSE( + server_connection->GetStats().address_validated_via_decrypting_packet); + EXPECT_TRUE(server_connection->GetStats().address_validated_via_token); } else { ADD_FAILURE() << "Missing server connection"; } @@ -2709,14 +2945,19 @@ class DuplicatePacketWithSpoofedSelfAddressWriter TEST_P(EndToEndTest, ClientAddressSpoofedForSomePeriod) { ASSERT_TRUE(Initialize()); - if (!version_.HasIetfQuicFrames() || - !client_->client()->session()->connection()->validate_client_address()) { + if (!GetClientConnection()->connection_migration_use_new_cid()) { return; } auto writer = new DuplicatePacketWithSpoofedSelfAddressWriter(); client_.reset(CreateQuicClient(writer)); + + // Make sure client has unused peer connection ID before migration. + SendSynchronousFooRequestAndCheckResponse(); + ASSERT_TRUE(QuicConnectionPeer::HasUnusedPeerIssuedConnectionId( + GetClientConnection())); + QuicIpAddress real_host = TestLoopback(1); - client_->MigrateSocket(real_host); + ASSERT_TRUE(client_->MigrateSocket(real_host)); SendSynchronousFooRequestAndCheckResponse(); EXPECT_EQ( 0u, GetClientConnection()->GetStats().num_connectivity_probing_received); @@ -2755,10 +2996,107 @@ TEST_P(EndToEndTest, ClientAddressSpoofedForSomePeriod) { EXPECT_EQ(large_body, client_->response_body()); } -TEST_P(EndToEndTest, AsynchronousConnectionMigrationClientIPChanged) { +TEST_P(EndToEndTest, + AsynchronousConnectionMigrationClientIPChangedMultipleTimes) { ASSERT_TRUE(Initialize()); - if (!version_.HasIetfQuicFrames() || - !client_->client()->session()->connection()->use_path_validator()) { + if (!GetClientConnection()->connection_migration_use_new_cid()) { + return; + } + client_.reset(CreateQuicClient(nullptr)); + + SendSynchronousFooRequestAndCheckResponse(); + + // Store the client IP address which was used to send the first request. + QuicIpAddress host0 = + client_->client()->network_helper()->GetLatestClientAddress().host(); + QuicConnection* client_connection = GetClientConnection(); + QuicConnectionId server_cid0 = client_connection->connection_id(); + // Server should have one new connection ID upon handshake completion. + ASSERT_TRUE( + QuicConnectionPeer::HasUnusedPeerIssuedConnectionId(client_connection)); + + // Migrate socket to new IP address #1. + QuicIpAddress host1 = TestLoopback(2); + EXPECT_NE(host0, host1); + ASSERT_TRUE(client_->client()->ValidateAndMigrateSocket(host1)); + while (client_->client()->HasPendingPathValidation()) { + client_->client()->WaitForEvents(); + } + EXPECT_EQ(host1, client_->client()->session()->self_address().host()); + EXPECT_EQ(1u, + client_connection->GetStats().num_connectivity_probing_received); + QuicConnectionId server_cid1 = client_connection->connection_id(); + EXPECT_NE(server_cid0, server_cid1); + EXPECT_TRUE(QuicConnectionPeer::GetServerConnectionIdOnAlternativePath( + client_connection) + .IsEmpty()); + + // Send a request using the new socket. + SendSynchronousBarRequestAndCheckResponse(); + + // Migrate socket to new IP address #2. + WaitForNewConnectionIds(); + QuicIpAddress host2 = TestLoopback(3); + EXPECT_NE(host0, host1); + ASSERT_TRUE(client_->client()->ValidateAndMigrateSocket(host2)); + + while (client_->client()->HasPendingPathValidation()) { + client_->client()->WaitForEvents(); + } + EXPECT_EQ(host2, client_->client()->session()->self_address().host()); + EXPECT_EQ(2u, + client_connection->GetStats().num_connectivity_probing_received); + QuicConnectionId server_cid2 = client_connection->connection_id(); + EXPECT_NE(server_cid0, server_cid2); + EXPECT_NE(server_cid1, server_cid2); + EXPECT_TRUE(QuicConnectionPeer::GetServerConnectionIdOnAlternativePath( + client_connection) + .IsEmpty()); + + // Send a request using the new socket. + SendSynchronousBarRequestAndCheckResponse(); + + // Migrate socket back to IP address #1. + WaitForNewConnectionIds(); + ASSERT_TRUE(client_->client()->ValidateAndMigrateSocket(host1)); + + while (client_->client()->HasPendingPathValidation()) { + client_->client()->WaitForEvents(); + } + EXPECT_EQ(host1, client_->client()->session()->self_address().host()); + EXPECT_EQ(3u, + client_connection->GetStats().num_connectivity_probing_received); + QuicConnectionId server_cid3 = client_connection->connection_id(); + EXPECT_NE(server_cid0, server_cid3); + EXPECT_NE(server_cid1, server_cid3); + EXPECT_NE(server_cid2, server_cid3); + EXPECT_TRUE(QuicConnectionPeer::GetServerConnectionIdOnAlternativePath( + client_connection) + .IsEmpty()); + + // Send a request using the new socket. + SendSynchronousBarRequestAndCheckResponse(); + server_thread_->Pause(); + const QuicConnection* server_connection = GetServerConnection(); + EXPECT_EQ(server_connection->connection_id(), server_cid3); + EXPECT_TRUE(QuicConnectionPeer::GetServerConnectionIdOnAlternativePath( + server_connection) + .IsEmpty()); + server_thread_->Resume(); + + // There should be 1 new connection ID issued by the server. + WaitForNewConnectionIds(); +} + +TEST_P(EndToEndTest, + AsynchronousConnectionMigrationClientIPChangedWithNonEmptyClientCID) { + if (!version_.SupportsClientConnectionIds()) { + ASSERT_TRUE(Initialize()); + return; + } + override_client_connection_id_length_ = kQuicDefaultConnectionIdLength; + ASSERT_TRUE(Initialize()); + if (!GetClientConnection()->connection_migration_use_new_cid()) { return; } client_.reset(CreateQuicClient(nullptr)); @@ -2768,6 +3106,9 @@ TEST_P(EndToEndTest, AsynchronousConnectionMigrationClientIPChanged) { // Store the client IP address which was used to send the first request. QuicIpAddress old_host = client_->client()->network_helper()->GetLatestClientAddress().host(); + auto* client_connection = GetClientConnection(); + QuicConnectionId client_cid0 = client_connection->client_connection_id(); + QuicConnectionId server_cid0 = client_connection->connection_id(); // Migrate socket to the new IP address. QuicIpAddress new_host = TestLoopback(2); @@ -2778,12 +3119,26 @@ TEST_P(EndToEndTest, AsynchronousConnectionMigrationClientIPChanged) { client_->client()->WaitForEvents(); } EXPECT_EQ(new_host, client_->client()->session()->self_address().host()); - QuicConnection* client_connection = GetClientConnection(); - ASSERT_TRUE(client_connection); - EXPECT_EQ(client_connection->validate_client_address() ? 1u : 0, + EXPECT_EQ(1u, client_connection->GetStats().num_connectivity_probing_received); + QuicConnectionId client_cid1 = client_connection->client_connection_id(); + QuicConnectionId server_cid1 = client_connection->connection_id(); + const auto* client_packet_creator = + QuicConnectionPeer::GetPacketCreator(client_connection); + EXPECT_EQ(client_cid1, client_packet_creator->GetClientConnectionId()); + EXPECT_EQ(server_cid1, client_packet_creator->GetServerConnectionId()); // Send a request using the new socket. SendSynchronousBarRequestAndCheckResponse(); + + server_thread_->Pause(); + QuicConnection* server_connection = GetServerConnection(); + EXPECT_EQ(client_cid1, server_connection->client_connection_id()); + EXPECT_EQ(server_cid1, server_connection->connection_id()); + const auto* server_packet_creator = + QuicConnectionPeer::GetPacketCreator(server_connection); + EXPECT_EQ(client_cid1, server_packet_creator->GetClientConnectionId()); + EXPECT_EQ(server_cid1, server_packet_creator->GetServerConnectionId()); + server_thread_->Resume(); } TEST_P(EndToEndTest, ConnectionMigrationClientPortChanged) { @@ -3257,13 +3612,13 @@ TEST_P(EndToEndTest, AckNotifierWithPacketLossAndBlockedSocket) { ADD_FAILURE() << "Missing QPACK encoder"; return; } - QpackHeaderTable* header_table = + QpackEncoderHeaderTable* header_table = QpackEncoderPeer::header_table(qpack_encoder); if (header_table == nullptr) { ADD_FAILURE() << "Missing header table"; return; } - if (QpackHeaderTablePeer::dynamic_table_capacity(header_table) > 0) { + if (header_table->dynamic_table_capacity() > 0) { break; } } @@ -3880,312 +4235,6 @@ TEST_P(EndToEndTest, Trailers) { EXPECT_EQ(trailers, client_->response_trailers()); } -class EndToEndTestServerPush : public EndToEndTest { - protected: - const size_t kNumMaxStreams = 10; - - EndToEndTestServerPush() : EndToEndTest() { - client_config_.SetMaxBidirectionalStreamsToSend(kNumMaxStreams); - server_config_.SetMaxBidirectionalStreamsToSend(kNumMaxStreams); - client_config_.SetMaxUnidirectionalStreamsToSend(kNumMaxStreams); - server_config_.SetMaxUnidirectionalStreamsToSend(kNumMaxStreams); - } - - // Add a request with its response and |num_resources| push resources into - // cache. - // If |resource_size| == 0, response body of push resources use default string - // concatenating with resource url. Otherwise, generate a string of - // |resource_size| as body. - void AddRequestAndResponseWithServerPush(std::string host, - std::string path, - std::string response_body, - std::string* push_urls, - const size_t num_resources, - const size_t resource_size) { - bool use_large_response = resource_size != 0; - std::string large_resource; - if (use_large_response) { - // Generate a response common body larger than flow control window for - // push response. - large_resource = std::string(resource_size, 'a'); - } - std::list<QuicBackendResponse::ServerPushInfo> push_resources; - for (size_t i = 0; i < num_resources; ++i) { - std::string url = push_urls[i]; - QuicUrl resource_url(url); - std::string body = - use_large_response - ? large_resource - : absl::StrCat("This is server push response body for ", url); - SpdyHeaderBlock response_headers; - response_headers[":status"] = "200"; - response_headers["content-length"] = absl::StrCat(body.size()); - push_resources.push_back(QuicBackendResponse::ServerPushInfo( - resource_url, std::move(response_headers), kV3LowestPriority, body)); - } - - memory_cache_backend_.AddSimpleResponseWithServerPushResources( - host, path, 200, response_body, push_resources); - } -}; - -// Run all server push end to end tests with all supported versions. -INSTANTIATE_TEST_SUITE_P(EndToEndTestsServerPush, - EndToEndTestServerPush, - ::testing::ValuesIn(GetTestParams()), - ::testing::PrintToStringParamName()); - -TEST_P(EndToEndTestServerPush, ServerPush) { - ASSERT_TRUE(Initialize()); - EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); - - // Set reordering to ensure that body arriving before PUSH_PROMISE is ok. - SetPacketSendDelay(QuicTime::Delta::FromMilliseconds(2)); - SetReorderPercentage(30); - - // Add a response with headers, body, and push resources. - const std::string kBody = "body content"; - size_t kNumResources = 4; - std::string push_urls[] = {"https://example.com/font.woff", - "https://example.com/script.js", - "https://fonts.example.com/font.woff", - "https://example.com/logo-hires.jpg"}; - AddRequestAndResponseWithServerPush("example.com", "/push_example", kBody, - push_urls, kNumResources, 0); - - client_->client()->set_response_listener( - std::unique_ptr<QuicSpdyClientBase::ResponseListener>( - new TestResponseListener)); - - QUIC_DVLOG(1) << "send request for /push_example"; - EXPECT_EQ(kBody, client_->SendSynchronousRequest( - "https://example.com/push_example")); - QuicStreamSequencer* sequencer = nullptr; - if (!version_.UsesHttp3()) { - QuicSpdyClientSession* client_session = GetClientSession(); - ASSERT_TRUE(client_session); - QuicHeadersStream* headers_stream = - QuicSpdySessionPeer::GetHeadersStream(client_session); - ASSERT_TRUE(headers_stream); - sequencer = QuicStreamPeer::sequencer(headers_stream); - ASSERT_TRUE(sequencer); - // 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; - std::string expected_body = - absl::StrCat("This is server push response body for ", url); - std::string response_body = client_->SendSynchronousRequest(url); - QUIC_DVLOG(1) << "response body " << response_body; - EXPECT_EQ(expected_body, response_body); - } - if (!version_.UsesHttp3()) { - ASSERT_TRUE(sequencer); - EXPECT_FALSE( - QuicStreamSequencerPeer::IsUnderlyingBufferAllocated(sequencer)); - } -} - -TEST_P(EndToEndTestServerPush, ServerPushUnderLimit) { - // Tests that sending a request which has 4 push resources will trigger server - // to push those 4 resources and client can handle pushed resources and match - // them with requests later. - ASSERT_TRUE(Initialize()); - - if (version_.UsesHttp3()) { - return; - } - - EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); - // Set reordering to ensure that body arriving before PUSH_PROMISE is ok. - SetPacketSendDelay(QuicTime::Delta::FromMilliseconds(2)); - SetReorderPercentage(30); - - // Add a response with headers, body, and push resources. - const std::string kBody = "body content"; - size_t const kNumResources = 4; - std::string push_urls[] = { - "https://example.com/font.woff", - "https://example.com/script.js", - "https://fonts.example.com/font.woff", - "https://example.com/logo-hires.jpg", - }; - AddRequestAndResponseWithServerPush("example.com", "/push_example", kBody, - push_urls, kNumResources, 0); - client_->client()->set_response_listener( - std::unique_ptr<QuicSpdyClientBase::ResponseListener>( - new TestResponseListener)); - - // Send the first request: this will trigger the server to send all the push - // resources associated with this request, and these will be cached by the - // client. - EXPECT_EQ(kBody, client_->SendSynchronousRequest( - "https://example.com/push_example")); - - for (const std::string& url : push_urls) { - // Sending subsequent requesets will not actually send anything on the wire, - // as the responses are already in the client's cache. - QUIC_DVLOG(1) << "send request for pushed stream on url " << url; - std::string expected_body = - absl::StrCat("This is server push response body for ", url); - std::string response_body = client_->SendSynchronousRequest(url); - QUIC_DVLOG(1) << "response body " << response_body; - EXPECT_EQ(expected_body, response_body); - } - // Expect only original request has been sent and push responses have been - // received as normal response. - EXPECT_EQ(1u, client_->num_requests()); - EXPECT_EQ(1u + kNumResources, client_->num_responses()); -} - -TEST_P(EndToEndTestServerPush, ServerPushOverLimitNonBlocking) { - if (version_.UsesHttp3()) { - ASSERT_TRUE(Initialize()); - return; - } - // Tests that when streams are not blocked by flow control or congestion - // control, pushing even more resources than max number of open outgoing - // streams should still work because all response streams get closed - // immediately after pushing resources. - ASSERT_TRUE(Initialize()); - EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); - - // Set reordering to ensure that body arriving before PUSH_PROMISE is ok. - SetPacketSendDelay(QuicTime::Delta::FromMilliseconds(2)); - SetReorderPercentage(30); - - // Add a response with headers, body, and push resources. - const std::string kBody = "body content"; - - // One more resource than max number of outgoing stream of this session. - const size_t kNumResources = 1 + kNumMaxStreams; // 11. - std::string push_urls[11]; - for (size_t i = 0; i < kNumResources; ++i) { - push_urls[i] = absl::StrCat("https://example.com/push_resources", i); - } - AddRequestAndResponseWithServerPush("example.com", "/push_example", kBody, - push_urls, kNumResources, 0); - client_->client()->set_response_listener( - std::unique_ptr<QuicSpdyClientBase::ResponseListener>( - new TestResponseListener)); - - // Send the first request: this will trigger the server to send all the push - // resources associated with this request, and these will be cached by the - // client. - EXPECT_EQ(kBody, client_->SendSynchronousRequest( - "https://example.com/push_example")); - - for (const std::string& url : push_urls) { - // Sending subsequent requesets will not actually send anything on the wire, - // as the responses are already in the client's cache. - EXPECT_EQ(absl::StrCat("This is server push response body for ", url), - client_->SendSynchronousRequest(url)); - } - - // Only 1 request should have been sent. - EXPECT_EQ(1u, client_->num_requests()); - // The responses to the original request and all the promised resources - // should have been received. - EXPECT_EQ(12u, client_->num_responses()); -} - -TEST_P(EndToEndTestServerPush, ServerPushOverLimitWithBlocking) { - if (version_.UsesHttp3()) { - ASSERT_TRUE(Initialize()); - return; - } - - // Tests that when server tries to send more large resources(large enough to - // be blocked by flow control window or congestion control window) than max - // open outgoing streams , server can open upto max number of outgoing - // streams for them, and the rest will be queued up. - - // Reset flow control windows. - size_t kFlowControlWnd = 20 * 1024; // 20KB. - // Response body is larger than 1 flow controlblock window. - size_t kBodySize = kFlowControlWnd * 2; - set_client_initial_stream_flow_control_receive_window(kFlowControlWnd); - // Make sure conntection level flow control window is large enough not to - // block data being sent out though they will be blocked by stream level one. - set_client_initial_session_flow_control_receive_window( - kBodySize * kNumMaxStreams + 1024); - - ASSERT_TRUE(Initialize()); - EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); - - // Set reordering to ensure that body arriving before PUSH_PROMISE is ok. - SetPacketSendDelay(QuicTime::Delta::FromMilliseconds(2)); - SetReorderPercentage(30); - - // Add a response with headers, body, and push resources. - const std::string kBody = "body content"; - - const size_t kNumResources = kNumMaxStreams + 1; - std::string push_urls[11]; - for (size_t i = 0; i < kNumResources; ++i) { - push_urls[i] = absl::StrCat("http://example.com/push_resources", i); - } - AddRequestAndResponseWithServerPush("example.com", "/push_example", kBody, - push_urls, kNumResources, kBodySize); - - client_->client()->set_response_listener( - std::unique_ptr<QuicSpdyClientBase::ResponseListener>( - new TestResponseListener)); - - client_->SendRequest("https://example.com/push_example"); - - // Pause after the first response arrives. - while (!client_->response_complete()) { - // Because of priority, the first response arrived should be to original - // request. - client_->WaitForResponse(); - ASSERT_TRUE(client_->connected()); - } - - // Check server session to see if it has max number of outgoing streams opened - // though more resources need to be pushed. - if (!version_.HasIetfQuicFrames()) { - server_thread_->Pause(); - QuicSession* server_session = GetServerSession(); - if (server_session != nullptr) { - EXPECT_EQ(kNumMaxStreams, - QuicSessionPeer::GetStreamIdManager(server_session) - ->num_open_outgoing_streams()); - } else { - ADD_FAILURE() << "Missing server session"; - } - server_thread_->Resume(); - } - - EXPECT_EQ(1u, client_->num_requests()); - EXPECT_EQ(1u, client_->num_responses()); - EXPECT_EQ(kBody, client_->response_body()); - - // "Send" request for a promised resources will not really send out it because - // its response is being pushed(but blocked). And the following ack and - // flow control behavior of SendSynchronousRequests() - // will unblock the stream to finish receiving response. - client_->SendSynchronousRequest(push_urls[0]); - EXPECT_EQ(1u, client_->num_requests()); - EXPECT_EQ(2u, client_->num_responses()); - - // Do same thing for the rest 10 resources. - for (size_t i = 1; i < kNumResources; ++i) { - client_->SendSynchronousRequest(push_urls[i]); - } - - // Because of server push, client gets all pushed resources without actually - // sending requests for them. - EXPECT_EQ(1u, client_->num_requests()); - // Including response to original request, 12 responses in total were - // received. - EXPECT_EQ(12u, client_->num_responses()); -} - // TODO(fayang): this test seems to cause net_unittests timeouts :| TEST_P(EndToEndTest, DISABLED_TestHugePostWithPacketLoss) { // This test tests a huge post with introduced packet loss from client to @@ -4440,11 +4489,7 @@ TEST_P(EndToEndTest, client_.reset(CreateQuicClient(client_writer_)); EXPECT_EQ("", client_->SendSynchronousRequest("/foo")); - if (GetQuicReloadableFlag(quic_fix_dispatcher_sent_error_code)) { - EXPECT_THAT(client_->connection_error(), IsError(QUIC_PACKET_WRITE_ERROR)); - } else { - EXPECT_THAT(client_->connection_error(), IsError(QUIC_HANDSHAKE_FAILED)); - } + EXPECT_THAT(client_->connection_error(), IsError(QUIC_HANDSHAKE_FAILED)); } // Regression test for b/116200989. @@ -5007,6 +5052,207 @@ TEST_P(EndToEndPacketReorderingTest, PathValidationFailure) { server_thread_->Resume(); } +TEST_P(EndToEndPacketReorderingTest, MigrateAgainAfterPathValidationFailure) { + ASSERT_TRUE(Initialize()); + if (!GetClientConnection()->connection_migration_use_new_cid()) { + return; + } + + client_.reset(CreateQuicClient(nullptr)); + // Finish one request to make sure handshake established. + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + + // Wait for the connection to become idle, to make sure the packet gets + // delayed is the connectivity probing packet. + client_->WaitForDelayedAcks(); + + QuicSocketAddress addr1 = client_->client()->session()->self_address(); + QuicConnection* client_connection = GetClientConnection(); + QuicConnectionId server_cid1 = client_connection->connection_id(); + + // Migrate socket to the new IP address. + QuicIpAddress host2 = TestLoopback(2); + EXPECT_NE(addr1.host(), host2); + + // Drop PATH_RESPONSE packets to timeout the path validation. + server_writer_->set_fake_packet_loss_percentage(100); + ASSERT_TRUE( + QuicConnectionPeer::HasUnusedPeerIssuedConnectionId(client_connection)); + + ASSERT_TRUE(client_->client()->ValidateAndMigrateSocket(host2)); + + QuicConnectionId server_cid2 = + QuicConnectionPeer::GetServerConnectionIdOnAlternativePath( + client_connection); + EXPECT_FALSE(server_cid2.IsEmpty()); + EXPECT_NE(server_cid2, server_cid1); + // Wait until path validation fails at the client. + while (client_->client()->HasPendingPathValidation()) { + EXPECT_EQ(server_cid2, + QuicConnectionPeer::GetServerConnectionIdOnAlternativePath( + client_connection)); + client_->client()->WaitForEvents(); + } + EXPECT_EQ(addr1, client_->client()->session()->self_address()); + EXPECT_EQ(server_cid1, GetClientConnection()->connection_id()); + + server_writer_->set_fake_packet_loss_percentage(0); + EXPECT_EQ(kBarResponseBody, client_->SendSynchronousRequest("/bar")); + + WaitForNewConnectionIds(); + EXPECT_EQ(1u, client_connection->GetStats().num_retire_connection_id_sent); + EXPECT_EQ(0u, client_connection->GetStats().num_new_connection_id_sent); + + server_thread_->Pause(); + QuicConnection* server_connection = GetServerConnection(); + // Server has received 3 path challenges. + EXPECT_EQ(3u, + server_connection->GetStats().num_connectivity_probing_received); + EXPECT_EQ(server_cid1, server_connection->connection_id()); + EXPECT_EQ(0u, server_connection->GetStats().num_retire_connection_id_sent); + EXPECT_EQ(2u, server_connection->GetStats().num_new_connection_id_sent); + server_thread_->Resume(); + + // Migrate socket to a new IP address again. + QuicIpAddress host3 = TestLoopback(3); + EXPECT_NE(addr1.host(), host3); + EXPECT_NE(host2, host3); + + WaitForNewConnectionIds(); + EXPECT_EQ(1u, client_connection->GetStats().num_retire_connection_id_sent); + EXPECT_EQ(0u, client_connection->GetStats().num_new_connection_id_sent); + + ASSERT_TRUE(client_->client()->ValidateAndMigrateSocket(host3)); + QuicConnectionId server_cid3 = + QuicConnectionPeer::GetServerConnectionIdOnAlternativePath( + client_connection); + EXPECT_FALSE(server_cid3.IsEmpty()); + EXPECT_NE(server_cid1, server_cid3); + EXPECT_NE(server_cid2, server_cid3); + while (client_->client()->HasPendingPathValidation()) { + client_->client()->WaitForEvents(); + } + EXPECT_EQ(host3, client_->client()->session()->self_address().host()); + EXPECT_EQ(server_cid3, GetClientConnection()->connection_id()); + EXPECT_TRUE(QuicConnectionPeer::GetServerConnectionIdOnAlternativePath( + client_connection) + .IsEmpty()); + EXPECT_EQ(kBarResponseBody, client_->SendSynchronousRequest("/bar")); + + // Server should send a new connection ID to client. + WaitForNewConnectionIds(); + EXPECT_EQ(2u, client_connection->GetStats().num_retire_connection_id_sent); + EXPECT_EQ(0u, client_connection->GetStats().num_new_connection_id_sent); +} + +TEST_P(EndToEndPacketReorderingTest, + MigrateAgainAfterPathValidationFailureWithNonZeroClientConnectionId) { + if (!version_.SupportsClientConnectionIds()) { + ASSERT_TRUE(Initialize()); + return; + } + override_client_connection_id_length_ = kQuicDefaultConnectionIdLength; + ASSERT_TRUE(Initialize()); + if (!GetClientConnection()->connection_migration_use_new_cid()) { + return; + } + + client_.reset(CreateQuicClient(nullptr)); + // Finish one request to make sure handshake established. + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + + // Wait for the connection to become idle, to make sure the packet gets + // delayed is the connectivity probing packet. + client_->WaitForDelayedAcks(); + + QuicSocketAddress addr1 = client_->client()->session()->self_address(); + QuicConnection* client_connection = GetClientConnection(); + QuicConnectionId server_cid1 = client_connection->connection_id(); + QuicConnectionId client_cid1 = client_connection->client_connection_id(); + + // Migrate socket to the new IP address. + QuicIpAddress host2 = TestLoopback(2); + EXPECT_NE(addr1.host(), host2); + + // Drop PATH_RESPONSE packets to timeout the path validation. + server_writer_->set_fake_packet_loss_percentage(100); + ASSERT_TRUE( + QuicConnectionPeer::HasUnusedPeerIssuedConnectionId(client_connection)); + ASSERT_TRUE(client_->client()->ValidateAndMigrateSocket(host2)); + QuicConnectionId server_cid2 = + QuicConnectionPeer::GetServerConnectionIdOnAlternativePath( + client_connection); + EXPECT_FALSE(server_cid2.IsEmpty()); + EXPECT_NE(server_cid2, server_cid1); + QuicConnectionId client_cid2 = + QuicConnectionPeer::GetClientConnectionIdOnAlternativePath( + client_connection); + EXPECT_FALSE(client_cid2.IsEmpty()); + EXPECT_NE(client_cid2, client_cid1); + while (client_->client()->HasPendingPathValidation()) { + EXPECT_EQ(server_cid2, + QuicConnectionPeer::GetServerConnectionIdOnAlternativePath( + client_connection)); + client_->client()->WaitForEvents(); + } + EXPECT_EQ(addr1, client_->client()->session()->self_address()); + EXPECT_EQ(server_cid1, GetClientConnection()->connection_id()); + EXPECT_TRUE(QuicConnectionPeer::GetServerConnectionIdOnAlternativePath( + client_connection) + .IsEmpty()); + server_writer_->set_fake_packet_loss_percentage(0); + EXPECT_EQ(kBarResponseBody, client_->SendSynchronousRequest("/bar")); + WaitForNewConnectionIds(); + EXPECT_EQ(1u, client_connection->GetStats().num_retire_connection_id_sent); + EXPECT_EQ(2u, client_connection->GetStats().num_new_connection_id_sent); + + server_thread_->Pause(); + QuicConnection* server_connection = GetServerConnection(); + if (server_connection != nullptr) { + EXPECT_EQ(3u, + server_connection->GetStats().num_connectivity_probing_received); + EXPECT_EQ(server_cid1, server_connection->connection_id()); + } else { + ADD_FAILURE() << "Missing server connection"; + } + EXPECT_EQ(1u, server_connection->GetStats().num_retire_connection_id_sent); + EXPECT_EQ(2u, server_connection->GetStats().num_new_connection_id_sent); + server_thread_->Resume(); + + // Migrate socket to a new IP address again. + QuicIpAddress host3 = TestLoopback(3); + EXPECT_NE(addr1.host(), host3); + EXPECT_NE(host2, host3); + ASSERT_TRUE(client_->client()->ValidateAndMigrateSocket(host3)); + + QuicConnectionId server_cid3 = + QuicConnectionPeer::GetServerConnectionIdOnAlternativePath( + client_connection); + EXPECT_FALSE(server_cid3.IsEmpty()); + EXPECT_NE(server_cid1, server_cid3); + EXPECT_NE(server_cid2, server_cid3); + QuicConnectionId client_cid3 = + QuicConnectionPeer::GetClientConnectionIdOnAlternativePath( + client_connection); + EXPECT_NE(client_cid1, client_cid3); + EXPECT_NE(client_cid2, client_cid3); + while (client_->client()->HasPendingPathValidation()) { + client_->client()->WaitForEvents(); + } + EXPECT_EQ(host3, client_->client()->session()->self_address().host()); + EXPECT_EQ(server_cid3, GetClientConnection()->connection_id()); + EXPECT_TRUE(QuicConnectionPeer::GetServerConnectionIdOnAlternativePath( + client_connection) + .IsEmpty()); + EXPECT_EQ(kBarResponseBody, client_->SendSynchronousRequest("/bar")); + + // Server should send new server connection ID to client and retires old + // client connection ID. + WaitForNewConnectionIds(); + EXPECT_EQ(2u, client_connection->GetStats().num_retire_connection_id_sent); + EXPECT_EQ(3u, client_connection->GetStats().num_new_connection_id_sent); +} + TEST_P(EndToEndPacketReorderingTest, Buffer0RttRequest) { ASSERT_TRUE(Initialize()); // Finish one request to make sure handshake established. @@ -5384,6 +5630,74 @@ TEST_P(EndToEndTest, LegacyVersionEncapsulationWithLoss) { 0u); } +// Testing packet writer that makes a copy of the first sent packets before +// sending them. Useful for tests that need access to sent packets. +class CopyingPacketWriter : public PacketDroppingTestWriter { + public: + explicit CopyingPacketWriter(int num_packets_to_copy) + : num_packets_to_copy_(num_packets_to_copy) {} + WriteResult WritePacket(const char* buffer, + size_t buf_len, + const QuicIpAddress& self_address, + const QuicSocketAddress& peer_address, + PerPacketOptions* options) override { + if (num_packets_to_copy_ > 0) { + num_packets_to_copy_--; + packets_.push_back( + QuicEncryptedPacket(buffer, buf_len, /*owns_buffer=*/false).Clone()); + } + return PacketDroppingTestWriter::WritePacket(buffer, buf_len, self_address, + peer_address, options); + } + + std::vector<std::unique_ptr<QuicEncryptedPacket>>& packets() { + return packets_; + } + + private: + int num_packets_to_copy_; + std::vector<std::unique_ptr<QuicEncryptedPacket>> packets_; +}; + +TEST_P(EndToEndTest, ChaosProtection) { + if (!version_.UsesCryptoFrames()) { + ASSERT_TRUE(Initialize()); + return; + } + // Replace the client's writer with one that'll save the first packet. + auto copying_writer = new CopyingPacketWriter(1); + delete client_writer_; + client_writer_ = copying_writer; + // Enable chaos protection and perform an HTTP request. + client_config_.SetClientConnectionOptions(QuicTagVector{kCHSP}); + ASSERT_TRUE(Initialize()); + SendSynchronousFooRequestAndCheckResponse(); + // Parse the saved packet to make sure it's valid. + SimpleQuicFramer validation_framer({version_}); + validation_framer.framer()->SetInitialObfuscators( + GetClientConnection()->connection_id()); + ASSERT_GT(copying_writer->packets().size(), 0u); + EXPECT_TRUE(validation_framer.ProcessPacket(*copying_writer->packets()[0])); + // TODO(dschinazi) figure out a way to use a MockRandom in this test so we + // can inspect the contents of this packet. +} + +TEST_P(EndToEndTest, ChaosProtectionWithMultiPacketChlo) { + if (!version_.UsesCryptoFrames()) { + ASSERT_TRUE(Initialize()); + return; + } + // Enable chaos protection. + client_config_.SetClientConnectionOptions(QuicTagVector{kCHSP}); + // Add a transport parameter to make the client hello span multiple packets. + constexpr auto kCustomParameter = + static_cast<TransportParameters::TransportParameterId>(0xff34); + client_config_.custom_transport_parameters_to_send()[kCustomParameter] = + std::string(2000, '?'); + ASSERT_TRUE(Initialize()); + SendSynchronousFooRequestAndCheckResponse(); +} + TEST_P(EndToEndTest, KeyUpdateInitiatedByClient) { if (!version_.UsesTls()) { // Key Update is only supported in TLS handshake. 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 3544cfddf9a..6d9290a12c1 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 @@ -36,8 +36,17 @@ HttpDecoder::HttpDecoder(Visitor* visitor, Options options) current_push_id_length_(0), remaining_push_id_length_(0), error_(QUIC_NO_ERROR), - error_detail_("") { + error_detail_(""), + ignore_old_priority_update_( + GetQuicReloadableFlag(quic_ignore_old_priority_update_frame)), + error_on_http3_push_(GetQuicReloadableFlag(quic_error_on_http3_push)) { QUICHE_DCHECK(visitor_); + if (ignore_old_priority_update_) { + QUIC_RELOADABLE_FLAG_COUNT(quic_ignore_old_priority_update_frame); + } + if (error_on_http3_push_) { + QUIC_RELOADABLE_FLAG_COUNT(quic_error_on_http3_push); + } } HttpDecoder::~HttpDecoder() {} @@ -172,6 +181,20 @@ bool HttpDecoder::ReadFrameType(QuicDataReader* reader) { current_frame_type_)); return false; } + + if (error_on_http3_push_) { + if (current_frame_type_ == + static_cast<uint64_t>(HttpFrameType::CANCEL_PUSH)) { + RaiseError(QUIC_HTTP_FRAME_ERROR, "CANCEL_PUSH frame received."); + return false; + } + if (current_frame_type_ == + static_cast<uint64_t>(HttpFrameType::PUSH_PROMISE)) { + RaiseError(QUIC_HTTP_FRAME_ERROR, "PUSH_PROMISE frame received."); + return false; + } + } + state_ = STATE_READING_FRAME_LENGTH; return true; } @@ -238,11 +261,19 @@ bool HttpDecoder::ReadFrameLength(QuicDataReader* reader) { visitor_->OnHeadersFrameStart(header_length, current_frame_length_); break; case static_cast<uint64_t>(HttpFrameType::CANCEL_PUSH): + if (error_on_http3_push_) { + QUICHE_NOTREACHED(); + break; + } break; case static_cast<uint64_t>(HttpFrameType::SETTINGS): continue_processing = visitor_->OnSettingsFrameStart(header_length); break; case static_cast<uint64_t>(HttpFrameType::PUSH_PROMISE): + if (error_on_http3_push_) { + QUICHE_NOTREACHED(); + break; + } // This edge case needs to be handled here, because ReadFramePayload() // does not get called if |current_frame_length_| is zero. if (current_frame_length_ == 0) { @@ -257,7 +288,13 @@ bool HttpDecoder::ReadFrameLength(QuicDataReader* reader) { case static_cast<uint64_t>(HttpFrameType::MAX_PUSH_ID): break; case static_cast<uint64_t>(HttpFrameType::PRIORITY_UPDATE): - continue_processing = visitor_->OnPriorityUpdateFrameStart(header_length); + if (ignore_old_priority_update_) { + continue_processing = visitor_->OnUnknownFrameStart( + current_frame_type_, header_length, current_frame_length_); + } else { + continue_processing = + visitor_->OnPriorityUpdateFrameStart(header_length); + } break; case static_cast<uint64_t>(HttpFrameType::PRIORITY_UPDATE_REQUEST_STREAM): continue_processing = visitor_->OnPriorityUpdateFrameStart(header_length); @@ -307,7 +344,11 @@ bool HttpDecoder::ReadFramePayload(QuicDataReader* reader) { break; } case static_cast<uint64_t>(HttpFrameType::CANCEL_PUSH): { - continue_processing = BufferOrParsePayload(reader); + if (error_on_http3_push_) { + QUICHE_NOTREACHED(); + } else { + continue_processing = BufferOrParsePayload(reader); + } break; } case static_cast<uint64_t>(HttpFrameType::SETTINGS): { @@ -315,6 +356,10 @@ bool HttpDecoder::ReadFramePayload(QuicDataReader* reader) { break; } case static_cast<uint64_t>(HttpFrameType::PUSH_PROMISE): { + if (error_on_http3_push_) { + QUICHE_NOTREACHED(); + break; + } PushId push_id; if (current_frame_length_ == remaining_frame_length_) { // A new Push Promise frame just arrived. @@ -388,7 +433,11 @@ bool HttpDecoder::ReadFramePayload(QuicDataReader* reader) { break; } case static_cast<uint64_t>(HttpFrameType::PRIORITY_UPDATE): { - continue_processing = BufferOrParsePayload(reader); + if (ignore_old_priority_update_) { + continue_processing = HandleUnknownFramePayload(reader); + } else { + continue_processing = BufferOrParsePayload(reader); + } break; } case static_cast<uint64_t>(HttpFrameType::PRIORITY_UPDATE_REQUEST_STREAM): { @@ -428,9 +477,13 @@ bool HttpDecoder::FinishParsing(QuicDataReader* reader) { break; } case static_cast<uint64_t>(HttpFrameType::CANCEL_PUSH): { - // If frame payload is not empty, FinishParsing() is skipped. - QUICHE_DCHECK_EQ(0u, current_frame_length_); - continue_processing = BufferOrParsePayload(reader); + if (error_on_http3_push_) { + QUICHE_NOTREACHED(); + } else { + // If frame payload is not empty, FinishParsing() is skipped. + QUICHE_DCHECK_EQ(0u, current_frame_length_); + continue_processing = BufferOrParsePayload(reader); + } break; } case static_cast<uint64_t>(HttpFrameType::SETTINGS): { @@ -440,7 +493,11 @@ bool HttpDecoder::FinishParsing(QuicDataReader* reader) { break; } case static_cast<uint64_t>(HttpFrameType::PUSH_PROMISE): { - continue_processing = visitor_->OnPushPromiseFrameEnd(); + if (error_on_http3_push_) { + QUICHE_NOTREACHED(); + } else { + continue_processing = visitor_->OnPushPromiseFrameEnd(); + } break; } case static_cast<uint64_t>(HttpFrameType::GOAWAY): { @@ -456,9 +513,13 @@ bool HttpDecoder::FinishParsing(QuicDataReader* reader) { break; } case static_cast<uint64_t>(HttpFrameType::PRIORITY_UPDATE): { - // If frame payload is not empty, FinishParsing() is skipped. - QUICHE_DCHECK_EQ(0u, current_frame_length_); - continue_processing = BufferOrParsePayload(reader); + if (ignore_old_priority_update_) { + continue_processing = visitor_->OnUnknownFrameEnd(); + } else { + // If frame payload is not empty, FinishParsing() is skipped. + QUICHE_DCHECK_EQ(0u, current_frame_length_); + continue_processing = BufferOrParsePayload(reader); + } break; } case static_cast<uint64_t>(HttpFrameType::PRIORITY_UPDATE_REQUEST_STREAM): { @@ -559,6 +620,10 @@ bool HttpDecoder::ParseEntirePayload(QuicDataReader* reader) { switch (current_frame_type_) { case static_cast<uint64_t>(HttpFrameType::CANCEL_PUSH): { + if (error_on_http3_push_) { + QUICHE_NOTREACHED(); + return false; + } CancelPushFrame frame; if (!reader->ReadVarInt62(&frame.push_id)) { RaiseError(QUIC_HTTP_FRAME_ERROR, @@ -606,11 +671,16 @@ bool HttpDecoder::ParseEntirePayload(QuicDataReader* reader) { return visitor_->OnMaxPushIdFrame(frame); } case static_cast<uint64_t>(HttpFrameType::PRIORITY_UPDATE): { - PriorityUpdateFrame frame; - if (!ParsePriorityUpdateFrame(reader, &frame)) { + if (ignore_old_priority_update_) { + QUICHE_NOTREACHED(); return false; + } else { + PriorityUpdateFrame frame; + if (!ParsePriorityUpdateFrame(reader, &frame)) { + return false; + } + return visitor_->OnPriorityUpdateFrame(frame); } - return visitor_->OnPriorityUpdateFrame(frame); } case static_cast<uint64_t>(HttpFrameType::PRIORITY_UPDATE_REQUEST_STREAM): { PriorityUpdateFrame frame; @@ -767,6 +837,7 @@ bool HttpDecoder::ParseAcceptChFrame(QuicDataReader* reader, QuicByteCount HttpDecoder::MaxFrameLength(uint64_t frame_type) { switch (frame_type) { case static_cast<uint64_t>(HttpFrameType::CANCEL_PUSH): + // TODO(b/171463363): Remove. return sizeof(PushId); case static_cast<uint64_t>(HttpFrameType::SETTINGS): // This limit is arbitrary. @@ -774,6 +845,7 @@ QuicByteCount HttpDecoder::MaxFrameLength(uint64_t frame_type) { case static_cast<uint64_t>(HttpFrameType::GOAWAY): return VARIABLE_LENGTH_INTEGER_LENGTH_8; case static_cast<uint64_t>(HttpFrameType::MAX_PUSH_ID): + // TODO(b/171463363): Remove. return sizeof(PushId); case static_cast<uint64_t>(HttpFrameType::PRIORITY_UPDATE): // This limit is arbitrary. 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 a351415e964..3a970fb63b1 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 @@ -45,6 +45,7 @@ class QUIC_EXPORT_PRIVATE HttpDecoder { // processed. At that point it is safe to consume |header_length| bytes. // Called when a CANCEL_PUSH frame has been successfully parsed. + // TODO(b/171463363): Remove. virtual bool OnCancelPushFrame(const CancelPushFrame& frame) = 0; // Called when a MAX_PUSH_ID frame has been successfully parsed. @@ -83,6 +84,7 @@ class QUIC_EXPORT_PRIVATE HttpDecoder { // Called when a HEADERS frame has been completely processed. virtual bool OnHeadersFrameEnd() = 0; + // TODO(b/171463363): Remove all. // Called when a PUSH_PROMISE frame has been received. virtual bool OnPushPromiseFrameStart(QuicByteCount header_length) = 0; // Called when the Push ID field of a PUSH_PROMISE frame has been parsed. @@ -230,7 +232,7 @@ class QUIC_EXPORT_PRIVATE HttpDecoder { void BufferFrameType(QuicDataReader* reader); // Buffers at most |remaining_push_id_length_| from |reader| to - // |push_id_buffer_|. + // |push_id_buffer_|. TODO(b/171463363): Remove. void BufferPushId(QuicDataReader* reader); // Sets |error_| and |error_detail_| accordingly. @@ -241,11 +243,13 @@ class QUIC_EXPORT_PRIVATE HttpDecoder { // Parses the payload of a PRIORITY_UPDATE frame (draft-01, type 0x0f) // from |reader| into |frame|. + // TODO(b/147306124): Remove. bool ParsePriorityUpdateFrame(QuicDataReader* reader, PriorityUpdateFrame* frame); // Parses the payload of a PRIORITY_UPDATE frame (draft-02, type 0xf0700) // from |reader| into |frame|. + // TODO(b/147306124): Rename to ParsePriorityUpdateFrame(). bool ParseNewPriorityUpdateFrame(QuicDataReader* reader, PriorityUpdateFrame* frame); @@ -276,8 +280,10 @@ class QUIC_EXPORT_PRIVATE HttpDecoder { // Remaining length that's needed for the frame's type field. QuicByteCount remaining_type_field_length_; // Length of PUSH_PROMISE frame's push id. + // TODO(b/171463363): Remove. QuicByteCount current_push_id_length_; // Remaining length that's needed for PUSH_PROMISE frame's push id field. + // TODO(b/171463363): Remove. QuicByteCount remaining_push_id_length_; // Last error. QuicErrorCode error_; @@ -290,7 +296,16 @@ class QUIC_EXPORT_PRIVATE HttpDecoder { // Remaining unparsed type field data. std::array<char, sizeof(uint64_t)> type_buffer_; // Remaining unparsed push id data. + // TODO(b/171463363): Remove. std::array<char, sizeof(uint64_t)> push_id_buffer_; + + // Latched value of + // gfe2_reloadable_flag_quic_ignore_old_priority_update_frame. + const bool ignore_old_priority_update_; + + // Latched value of + // gfe2_reloadable_flag_quic_error_on_http3_push. + const bool error_on_http3_push_; }; } // 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 aac020a97a7..05d580e20e1 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 @@ -19,7 +19,6 @@ #include "quic/platform/api/quic_flags.h" #include "quic/platform/api/quic_test.h" #include "quic/test_tools/quic_test_utils.h" -#include "common/platform/api/quiche_text_utils.h" using ::testing::_; using ::testing::AnyNumber; @@ -249,6 +248,14 @@ TEST_F(HttpDecoderTest, CancelPush) { "01" // length "01"); // Push Id + if (GetQuicReloadableFlag(quic_error_on_http3_push)) { + EXPECT_CALL(visitor_, OnError(&decoder_)); + EXPECT_EQ(1u, ProcessInput(input)); + EXPECT_THAT(decoder_.error(), IsError(QUIC_HTTP_FRAME_ERROR)); + EXPECT_EQ("CANCEL_PUSH frame received.", decoder_.error_detail()); + return; + } + // Visitor pauses processing. EXPECT_CALL(visitor_, OnCancelPushFrame(CancelPushFrame({1}))) .WillOnce(Return(false)); @@ -277,6 +284,14 @@ TEST_F(HttpDecoderTest, PushPromiseFrame) { "C000000000000101"), // push id 257 "Headers"); // headers + if (GetQuicReloadableFlag(quic_error_on_http3_push)) { + EXPECT_CALL(visitor_, OnError(&decoder_)); + EXPECT_EQ(1u, ProcessInput(input)); + EXPECT_THAT(decoder_.error(), IsError(QUIC_HTTP_FRAME_ERROR)); + EXPECT_EQ("PUSH_PROMISE frame received.", decoder_.error_detail()); + return; + } + // Visitor pauses processing. EXPECT_CALL(visitor_, OnPushPromiseFrameStart(2)).WillOnce(Return(false)); EXPECT_CALL(visitor_, OnPushPromiseFramePushId(257, 8, 7)) @@ -338,6 +353,10 @@ TEST_F(HttpDecoderTest, PushPromiseFrame) { } TEST_F(HttpDecoderTest, CorruptPushPromiseFrame) { + if (GetQuicReloadableFlag(quic_error_on_http3_push)) { + return; + } + InSequence s; std::string input = absl::HexStringToBytes( @@ -733,6 +752,10 @@ TEST_F(HttpDecoderTest, EmptyHeadersFrame) { } TEST_F(HttpDecoderTest, PushPromiseFrameNoHeaders) { + if (GetQuicReloadableFlag(quic_error_on_http3_push)) { + return; + } + InSequence s; std::string input = absl::HexStringToBytes( "05" // type (PUSH_PROMISE) @@ -768,6 +791,10 @@ TEST_F(HttpDecoderTest, PushPromiseFrameNoHeaders) { } TEST_F(HttpDecoderTest, MalformedFrameWithOverlyLargePayload) { + if (GetQuicReloadableFlag(quic_error_on_http3_push)) { + return; + } + std::string input = absl::HexStringToBytes( "03" // type (CANCEL_PUSH) "10" // length @@ -841,97 +868,183 @@ TEST_F(HttpDecoderTest, HeadersPausedThenData) { } 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 CANCEL_PUSH push_id."}, - {"\x03" // type (CANCEL_PUSH) - "\x04" // length - "\x05" // valid push id - "foo", // superfluous data - "Superfluous data in CANCEL_PUSH frame."}, - {"\x0D" // type (MAX_PUSH_ID) - "\x01" // length - "\x40", // first byte of two-byte varint push id - "Unable to read MAX_PUSH_ID push_id."}, - {"\x0D" // type (MAX_PUSH_ID) - "\x04" // length - "\x05" // valid push id - "foo", // superfluous data - "Superfluous data in MAX_PUSH_ID frame."}, - {"\x07" // type (GOAWAY) - "\x01" // length - "\x40", // first byte of two-byte varint stream id - "Unable to read GOAWAY ID."}, - {"\x07" // type (GOAWAY) - "\x04" // length - "\x05" // valid stream id - "foo", // superfluous data - "Superfluous data in GOAWAY frame."}, - {"\x40\x89" // type (ACCEPT_CH) - "\x01" // length - "\x40", // first byte of two-byte varint origin length - "Unable to read ACCEPT_CH origin."}, - {"\x40\x89" // type (ACCEPT_CH) - "\x01" // length - "\x05", // valid origin length but no origin string - "Unable to read ACCEPT_CH origin."}, - {"\x40\x89" // type (ACCEPT_CH) - "\x04" // length - "\x05" // valid origin length - "foo", // payload ends before origin ends - "Unable to read ACCEPT_CH origin."}, - {"\x40\x89" // type (ACCEPT_CH) - "\x04" // length - "\x03" // valid origin length - "foo", // payload ends at end of origin: no value - "Unable to read ACCEPT_CH value."}, - {"\x40\x89" // type (ACCEPT_CH) - "\x05" // length - "\x03" // valid origin length - "foo" // payload ends at end of origin: no value - "\x40", // first byte of two-byte varint value length - "Unable to read ACCEPT_CH value."}, - {"\x40\x89" // type (ACCEPT_CH) - "\x08" // length - "\x03" // valid origin length - "foo" // origin - "\x05" // valid value length - "bar", // payload ends before value ends - "Unable to read ACCEPT_CH value."}}; - - for (const auto& test_data : kTestData) { - { - HttpDecoder decoder(&visitor_); - EXPECT_CALL(visitor_, OnAcceptChFrameStart(_)).Times(AnyNumber()); - EXPECT_CALL(visitor_, OnError(&decoder)); - - absl::string_view input(test_data.input); - decoder.ProcessInput(input.data(), input.size()); - EXPECT_THAT(decoder.error(), IsError(QUIC_HTTP_FRAME_ERROR)); - EXPECT_EQ(test_data.error_message, decoder.error_detail()); + if (GetQuicReloadableFlag(quic_error_on_http3_push)) { + InSequence s; + + struct { + const char* const input; + const char* const error_message; + } kTestData[] = {{"\x0D" // type (MAX_PUSH_ID) + "\x01" // length + "\x40", // first byte of two-byte varint push id + "Unable to read MAX_PUSH_ID push_id."}, + {"\x0D" // type (MAX_PUSH_ID) + "\x04" // length + "\x05" // valid push id + "foo", // superfluous data + "Superfluous data in MAX_PUSH_ID frame."}, + {"\x07" // type (GOAWAY) + "\x01" // length + "\x40", // first byte of two-byte varint stream id + "Unable to read GOAWAY ID."}, + {"\x07" // type (GOAWAY) + "\x04" // length + "\x05" // valid stream id + "foo", // superfluous data + "Superfluous data in GOAWAY frame."}, + {"\x40\x89" // type (ACCEPT_CH) + "\x01" // length + "\x40", // first byte of two-byte varint origin length + "Unable to read ACCEPT_CH origin."}, + {"\x40\x89" // type (ACCEPT_CH) + "\x01" // length + "\x05", // valid origin length but no origin string + "Unable to read ACCEPT_CH origin."}, + {"\x40\x89" // type (ACCEPT_CH) + "\x04" // length + "\x05" // valid origin length + "foo", // payload ends before origin ends + "Unable to read ACCEPT_CH origin."}, + {"\x40\x89" // type (ACCEPT_CH) + "\x04" // length + "\x03" // valid origin length + "foo", // payload ends at end of origin: no value + "Unable to read ACCEPT_CH value."}, + {"\x40\x89" // type (ACCEPT_CH) + "\x05" // length + "\x03" // valid origin length + "foo" // payload ends at end of origin: no value + "\x40", // first byte of two-byte varint value length + "Unable to read ACCEPT_CH value."}, + {"\x40\x89" // type (ACCEPT_CH) + "\x08" // length + "\x03" // valid origin length + "foo" // origin + "\x05" // valid value length + "bar", // payload ends before value ends + "Unable to read ACCEPT_CH value."}}; + + for (const auto& test_data : kTestData) { + { + HttpDecoder decoder(&visitor_); + EXPECT_CALL(visitor_, OnAcceptChFrameStart(_)).Times(AnyNumber()); + EXPECT_CALL(visitor_, OnError(&decoder)); + + absl::string_view input(test_data.input); + decoder.ProcessInput(input.data(), input.size()); + EXPECT_THAT(decoder.error(), IsError(QUIC_HTTP_FRAME_ERROR)); + EXPECT_EQ(test_data.error_message, decoder.error_detail()); + } + { + HttpDecoder decoder(&visitor_); + EXPECT_CALL(visitor_, OnAcceptChFrameStart(_)).Times(AnyNumber()); + EXPECT_CALL(visitor_, OnError(&decoder)); + + absl::string_view input(test_data.input); + for (auto c : input) { + decoder.ProcessInput(&c, 1); + } + EXPECT_THAT(decoder.error(), IsError(QUIC_HTTP_FRAME_ERROR)); + EXPECT_EQ(test_data.error_message, decoder.error_detail()); + } } - { - HttpDecoder decoder(&visitor_); - EXPECT_CALL(visitor_, OnAcceptChFrameStart(_)).Times(AnyNumber()); - EXPECT_CALL(visitor_, OnError(&decoder)); - - absl::string_view input(test_data.input); - for (auto c : input) { - decoder.ProcessInput(&c, 1); + } else { + 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 CANCEL_PUSH push_id."}, + {"\x03" // type (CANCEL_PUSH) + "\x04" // length + "\x05" // valid push id + "foo", // superfluous data + "Superfluous data in CANCEL_PUSH frame."}, + {"\x0D" // type (MAX_PUSH_ID) + "\x01" // length + "\x40", // first byte of two-byte varint push id + "Unable to read MAX_PUSH_ID push_id."}, + {"\x0D" // type (MAX_PUSH_ID) + "\x04" // length + "\x05" // valid push id + "foo", // superfluous data + "Superfluous data in MAX_PUSH_ID frame."}, + {"\x07" // type (GOAWAY) + "\x01" // length + "\x40", // first byte of two-byte varint stream id + "Unable to read GOAWAY ID."}, + {"\x07" // type (GOAWAY) + "\x04" // length + "\x05" // valid stream id + "foo", // superfluous data + "Superfluous data in GOAWAY frame."}, + {"\x40\x89" // type (ACCEPT_CH) + "\x01" // length + "\x40", // first byte of two-byte varint origin length + "Unable to read ACCEPT_CH origin."}, + {"\x40\x89" // type (ACCEPT_CH) + "\x01" // length + "\x05", // valid origin length but no origin string + "Unable to read ACCEPT_CH origin."}, + {"\x40\x89" // type (ACCEPT_CH) + "\x04" // length + "\x05" // valid origin length + "foo", // payload ends before origin ends + "Unable to read ACCEPT_CH origin."}, + {"\x40\x89" // type (ACCEPT_CH) + "\x04" // length + "\x03" // valid origin length + "foo", // payload ends at end of origin: no value + "Unable to read ACCEPT_CH value."}, + {"\x40\x89" // type (ACCEPT_CH) + "\x05" // length + "\x03" // valid origin length + "foo" // payload ends at end of origin: no value + "\x40", // first byte of two-byte varint value length + "Unable to read ACCEPT_CH value."}, + {"\x40\x89" // type (ACCEPT_CH) + "\x08" // length + "\x03" // valid origin length + "foo" // origin + "\x05" // valid value length + "bar", // payload ends before value ends + "Unable to read ACCEPT_CH value."}}; + + for (const auto& test_data : kTestData) { + { + HttpDecoder decoder(&visitor_); + EXPECT_CALL(visitor_, OnAcceptChFrameStart(_)).Times(AnyNumber()); + EXPECT_CALL(visitor_, OnError(&decoder)); + + absl::string_view input(test_data.input); + decoder.ProcessInput(input.data(), input.size()); + EXPECT_THAT(decoder.error(), IsError(QUIC_HTTP_FRAME_ERROR)); + EXPECT_EQ(test_data.error_message, decoder.error_detail()); + } + { + HttpDecoder decoder(&visitor_); + EXPECT_CALL(visitor_, OnAcceptChFrameStart(_)).Times(AnyNumber()); + EXPECT_CALL(visitor_, OnError(&decoder)); + + absl::string_view input(test_data.input); + for (auto c : input) { + decoder.ProcessInput(&c, 1); + } + EXPECT_THAT(decoder.error(), IsError(QUIC_HTTP_FRAME_ERROR)); + EXPECT_EQ(test_data.error_message, decoder.error_detail()); } - EXPECT_THAT(decoder.error(), IsError(QUIC_HTTP_FRAME_ERROR)); - EXPECT_EQ(test_data.error_message, decoder.error_detail()); } } } TEST_F(HttpDecoderTest, EmptyCancelPushFrame) { + if (GetQuicReloadableFlag(quic_error_on_http3_push)) { + return; + } + std::string input = absl::HexStringToBytes( "03" // type (CANCEL_PUSH) "00"); // frame length @@ -959,6 +1072,10 @@ TEST_F(HttpDecoderTest, EmptySettingsFrame) { // Regression test for https://crbug.com/1001823. TEST_F(HttpDecoderTest, EmptyPushPromiseFrame) { + if (GetQuicReloadableFlag(quic_error_on_http3_push)) { + return; + } + std::string input = absl::HexStringToBytes( "05" // type (PUSH_PROMISE) "00"); // frame length @@ -1003,7 +1120,11 @@ TEST_F(HttpDecoderTest, LargeStreamIdInGoAway) { EXPECT_EQ("", decoder_.error_detail()); } -TEST_F(HttpDecoderTest, PriorityUpdateFrame) { +TEST_F(HttpDecoderTest, OldPriorityUpdateFrame) { + if (GetQuicReloadableFlag(quic_ignore_old_priority_update_frame)) { + return; + } + InSequence s; std::string input1 = absl::HexStringToBytes( "0f" // type (PRIORITY_UPDATE) @@ -1085,7 +1206,44 @@ TEST_F(HttpDecoderTest, PriorityUpdateFrame) { EXPECT_EQ("", decoder_.error_detail()); } -TEST_F(HttpDecoderTest, NewPriorityUpdateFrame) { +TEST_F(HttpDecoderTest, ObsoletePriorityUpdateFrame) { + if (!GetQuicReloadableFlag(quic_ignore_old_priority_update_frame)) { + return; + } + + const QuicByteCount header_length = 2; + const QuicByteCount payload_length = 3; + InSequence s; + std::string input = absl::HexStringToBytes( + "0f" // type (obsolete PRIORITY_UPDATE) + "03" // length + "666f6f"); // payload "foo" + + // Process frame as a whole. + EXPECT_CALL(visitor_, + OnUnknownFrameStart(0x0f, header_length, payload_length)); + EXPECT_CALL(visitor_, OnUnknownFramePayload(Eq("foo"))); + EXPECT_CALL(visitor_, OnUnknownFrameEnd()).WillOnce(Return(false)); + + EXPECT_EQ(header_length + payload_length, + ProcessInputWithGarbageAppended(input)); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); + EXPECT_EQ("", decoder_.error_detail()); + + // Process frame byte by byte. + EXPECT_CALL(visitor_, + OnUnknownFrameStart(0x0f, header_length, payload_length)); + EXPECT_CALL(visitor_, OnUnknownFramePayload(Eq("f"))); + EXPECT_CALL(visitor_, OnUnknownFramePayload(Eq("o"))); + EXPECT_CALL(visitor_, OnUnknownFramePayload(Eq("o"))); + EXPECT_CALL(visitor_, OnUnknownFrameEnd()); + + ProcessInputCharByChar(input); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); + EXPECT_EQ("", decoder_.error_detail()); +} + +TEST_F(HttpDecoderTest, PriorityUpdateFrame) { InSequence s; std::string input1 = absl::HexStringToBytes( "800f0700" // type (PRIORITY_UPDATE) @@ -1166,6 +1324,10 @@ TEST_F(HttpDecoderTest, NewPriorityUpdateFrame) { } TEST_F(HttpDecoderTest, CorruptPriorityUpdateFrame) { + if (GetQuicReloadableFlag(quic_ignore_old_priority_update_frame)) { + return; + } + std::string payload1 = absl::HexStringToBytes( "80" // prioritized element type: PUSH_STREAM "4005"); // prioritized element id diff --git a/chromium/net/third_party/quiche/src/quic/core/http/http_frames.h b/chromium/net/third_party/quiche/src/quic/core/http/http_frames.h index 56e53487b24..b14ebe5a91b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/http_frames.h +++ b/chromium/net/third_party/quiche/src/quic/core/http/http_frames.h @@ -29,6 +29,7 @@ enum class HttpFrameType { GOAWAY = 0x7, MAX_PUSH_ID = 0xD, // https://tools.ietf.org/html/draft-ietf-httpbis-priority-01 + // TODO(b/147306124): Remove. PRIORITY_UPDATE = 0XF, // https://tools.ietf.org/html/draft-davidben-http-client-hint-reliability-02 ACCEPT_CH = 0x89, diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_header_list.h b/chromium/net/third_party/quiche/src/quic/core/http/quic_header_list.h index 9ddf6de8a84..01c861d5905 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_header_list.h +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_header_list.h @@ -11,9 +11,9 @@ #include <utility> #include "absl/strings/string_view.h" -#include "quic/core/quic_circular_deque.h" #include "quic/platform/api/quic_bug_tracker.h" #include "quic/platform/api/quic_export.h" +#include "common/quiche_circular_deque.h" #include "spdy/core/spdy_header_block.h" #include "spdy/core/spdy_headers_handler_interface.h" @@ -23,7 +23,8 @@ namespace quic { class QUIC_EXPORT_PRIVATE QuicHeaderList : public spdy::SpdyHeadersHandlerInterface { public: - using ListType = QuicCircularDeque<std::pair<std::string, std::string>>; + using ListType = + quiche::QuicheCircularDeque<std::pair<std::string, std::string>>; using value_type = ListType::value_type; using const_iterator = ListType::const_iterator; @@ -59,7 +60,7 @@ class QUIC_EXPORT_PRIVATE QuicHeaderList std::string DebugString() const; private: - QuicCircularDeque<std::pair<std::string, std::string>> header_list_; + quiche::QuicheCircularDeque<std::pair<std::string, std::string>> header_list_; // The limit on the size of the header list (defined by spec as name + value + // overhead for each header field). Headers over this limit will not be diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_headers_stream.h b/chromium/net/third_party/quiche/src/quic/core/http/quic_headers_stream.h index ae9e2afe0d1..153575be1de 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_headers_stream.h +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_headers_stream.h @@ -91,7 +91,7 @@ class QUIC_EXPORT_PRIVATE QuicHeadersStream : public QuicStream { QuicSpdySession* spdy_session_; // Headers that have not been fully acked. - QuicCircularDeque<CompressedHeaderInfo> unacked_headers_; + quiche::QuicheCircularDeque<CompressedHeaderInfo> unacked_headers_; }; } // 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 55dafac3756..42fef63c978 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 @@ -563,6 +563,10 @@ TEST_P(QuicHeadersStreamTest, ProcessPriorityFrame) { } TEST_P(QuicHeadersStreamTest, ProcessPushPromiseDisabledSetting) { + if (perspective() != Perspective::IS_CLIENT) { + return; + } + session_.OnConfigNegotiated(); SpdySettingsIR data; // Respect supported settings frames SETTINGS_ENABLE_PUSH. @@ -570,15 +574,11 @@ TEST_P(QuicHeadersStreamTest, ProcessPushPromiseDisabledSetting) { SpdySerializedFrame frame(framer_->SerializeFrame(data)); stream_frame_.data_buffer = frame.data(); stream_frame_.data_length = frame.size(); - if (perspective() == Perspective::IS_CLIENT) { - EXPECT_CALL( - *connection_, - CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA, - "Unsupported field of HTTP/2 SETTINGS frame: 2", _)); - } + EXPECT_CALL( + *connection_, + CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA, + "Unsupported field of HTTP/2 SETTINGS frame: 2", _)); headers_stream_->OnStreamFrame(stream_frame_); - EXPECT_EQ(session_.server_push_enabled(), - perspective() == Perspective::IS_CLIENT); } TEST_P(QuicHeadersStreamTest, ProcessLargeRawData) { 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 fbd7b2eb18e..39d8b42a5a2 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 @@ -15,7 +15,7 @@ #include "quic/core/quic_types.h" #include "quic/platform/api/quic_flag_utils.h" #include "quic/platform/api/quic_flags.h" -#include "common/platform/api/quiche_text_utils.h" +#include "common/quiche_text_utils.h" namespace quic { @@ -70,7 +70,6 @@ bool QuicReceiveControlStream::OnCancelPushFrame(const CancelPushFrame& frame) { spdy_session()->debug_visitor()->OnCancelPushFrameReceived(frame); } - // TODO(b/151841240): Handle CANCEL_PUSH frames instead of ignoring them. return ValidateFrameType(HttpFrameType::CANCEL_PUSH); } 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 c9133436e9f..03f21d8a70f 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 @@ -15,7 +15,6 @@ #include "quic/test_tools/quic_spdy_session_peer.h" #include "quic/test_tools/quic_stream_peer.h" #include "quic/test_tools/quic_test_utils.h" -#include "common/platform/api/quiche_text_utils.h" namespace quic { @@ -165,7 +164,7 @@ TEST_P(QuicReceiveControlStreamTest, ReceiveSettings) { QuicStreamFrame frame(receive_control_stream_->id(), false, 1, data); QpackEncoder* qpack_encoder = session_.qpack_encoder(); - QpackHeaderTable* header_table = + QpackEncoderHeaderTable* header_table = QpackEncoderPeer::header_table(qpack_encoder); EXPECT_EQ(std::numeric_limits<size_t>::max(), session_.max_outbound_header_list_size()); @@ -311,7 +310,10 @@ TEST_P(QuicReceiveControlStreamTest, PushPromiseOnControlStreamShouldClose) { push_promise_frame); EXPECT_CALL( *connection_, - CloseConnection(QUIC_HTTP_FRAME_UNEXPECTED_ON_CONTROL_STREAM, _, _)) + CloseConnection(GetQuicReloadableFlag(quic_error_on_http3_push) + ? QUIC_HTTP_FRAME_ERROR + : QUIC_HTTP_FRAME_UNEXPECTED_ON_CONTROL_STREAM, + _, _)) .WillOnce( Invoke(connection_, &MockQuicConnection::ReallyCloseConnection)); EXPECT_CALL(*connection_, SendConnectionClosePacket(_, _, _)); @@ -382,13 +384,21 @@ TEST_P(QuicReceiveControlStreamTest, CancelPushFrameBeforeSettings) { "01" // payload length "01"); // push ID - EXPECT_CALL(*connection_, - CloseConnection(QUIC_HTTP_MISSING_SETTINGS_FRAME, - "First frame received on control stream is type " - "3, but it must be SETTINGS.", - _)) - .WillOnce( - Invoke(connection_, &MockQuicConnection::ReallyCloseConnection)); + if (GetQuicReloadableFlag(quic_error_on_http3_push)) { + EXPECT_CALL(*connection_, CloseConnection(QUIC_HTTP_FRAME_ERROR, + "CANCEL_PUSH frame received.", _)) + .WillOnce( + Invoke(connection_, &MockQuicConnection::ReallyCloseConnection)); + } else { + EXPECT_CALL( + *connection_, + CloseConnection(QUIC_HTTP_MISSING_SETTINGS_FRAME, + "First frame received on control stream is type " + "3, but it must be SETTINGS.", + _)) + .WillOnce( + Invoke(connection_, &MockQuicConnection::ReallyCloseConnection)); + } EXPECT_CALL(*connection_, SendConnectionClosePacket(_, _, _)); EXPECT_CALL(session_, OnConnectionClosed(_, _)); 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 d1be0df27ca..c5af1dc4a90 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 @@ -13,7 +13,6 @@ #include "quic/test_tools/quic_config_peer.h" #include "quic/test_tools/quic_spdy_session_peer.h" #include "quic/test_tools/quic_test_utils.h" -#include "common/platform/api/quiche_text_utils.h" #include "common/test_tools/quiche_test_utils.h" namespace quic { diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base.cc index b955835e2b8..c78df58e18a 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base.cc @@ -50,12 +50,6 @@ void QuicServerSessionBase::OnConfigNegotiated() { return; } - // Disable server push if peer sends the corresponding connection option. - if (!version().UsesHttp3() && - ContainsQuicTag(config()->ReceivedConnectionOptions(), kQNSP)) { - OnSetting(spdy::SETTINGS_ENABLE_PUSH, 0); - } - // Enable bandwidth resumption if peer sent correct connection options. const bool last_bandwidth_resumption = ContainsQuicTag(config()->ReceivedConnectionOptions(), kBWRE); 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 29750f2e3cf..ac7fc1e59c8 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 @@ -10,7 +10,6 @@ #include <utility> #include "absl/memory/memory.h" -#include "absl/strings/string_view.h" #include "quic/core/crypto/null_encrypter.h" #include "quic/core/crypto/quic_crypto_server_config.h" #include "quic/core/crypto/quic_random.h" @@ -51,6 +50,12 @@ namespace quic { namespace test { namespace { +// Data to be sent on a request stream. In Google QUIC, this is interpreted as +// DATA payload (there is no framing on request streams). In IETF QUIC, this is +// interpreted as HEADERS frame (type 0x1) with payload length 122 ('z'). Since +// no payload is included, QPACK decoder will not be invoked. +const char* const kStreamData = "\1z"; + class TestServerSession : public QuicServerSessionBase { public: TestServerSession(const QuicConfig& config, @@ -148,7 +153,7 @@ class QuicServerSessionBaseTest : public QuicTestWithParam<ParsedQuicVersion> { config_.SetInitialSessionFlowControlWindowToSend( kInitialSessionFlowControlWindowForTest); - ParsedQuicVersionVector supported_versions = SupportedVersions(GetParam()); + ParsedQuicVersionVector supported_versions = SupportedVersions(version()); connection_ = new StrictMock<MockQuicConnection>( &helper_, &alarm_factory_, Perspective::IS_SERVER, supported_versions); connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1)); @@ -166,23 +171,24 @@ class QuicServerSessionBaseTest : public QuicTestWithParam<ParsedQuicVersion> { QuicConfigPeer::SetReceivedInitialSessionFlowControlWindow( session_->config(), kMinimumFlowControlSendWindow); session_->OnConfigNegotiated(); - if (connection_->version().SupportsAntiAmplificationLimit()) { + if (version().SupportsAntiAmplificationLimit()) { QuicConnectionPeer::SetAddressValidated(connection_); } } QuicStreamId GetNthClientInitiatedBidirectionalId(int n) { - return GetNthClientInitiatedBidirectionalStreamId( - connection_->transport_version(), n); + return GetNthClientInitiatedBidirectionalStreamId(transport_version(), n); } QuicStreamId GetNthServerInitiatedUnidirectionalId(int n) { return quic::test::GetNthServerInitiatedUnidirectionalStreamId( - connection_->transport_version(), n); + transport_version(), n); } + ParsedQuicVersion version() const { return GetParam(); } + QuicTransportVersion transport_version() const { - return connection_->transport_version(); + return version().transport_version; } // Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a @@ -242,10 +248,9 @@ INSTANTIATE_TEST_SUITE_P(Tests, ::testing::PrintToStringParamName()); TEST_P(QuicServerSessionBaseTest, CloseStreamDueToReset) { - // Open a stream, then reset it. - // Send two bytes of payload to open it. + // Send some data open a stream, then reset it. QuicStreamFrame data1(GetNthClientInitiatedBidirectionalId(0), false, 0, - absl::string_view("HT")); + kStreamData); session_->OnStreamFrame(data1); EXPECT_EQ(1u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get())); @@ -298,9 +303,9 @@ TEST_P(QuicServerSessionBaseTest, NeverOpenStreamDueToReset) { InjectStopSendingFrame(GetNthClientInitiatedBidirectionalId(0)); EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get())); - // Send two bytes of payload. + QuicStreamFrame data1(GetNthClientInitiatedBidirectionalId(0), false, 0, - absl::string_view("HT")); + kStreamData); session_->OnStreamFrame(data1); // The stream should never be opened, now that the reset is received. @@ -309,11 +314,11 @@ TEST_P(QuicServerSessionBaseTest, NeverOpenStreamDueToReset) { } TEST_P(QuicServerSessionBaseTest, AcceptClosedStream) { - // Send (empty) compressed headers followed by two bytes of data. + // Send some data to open two streams. QuicStreamFrame frame1(GetNthClientInitiatedBidirectionalId(0), false, 0, - absl::string_view("\1\0\0\0\0\0\0\0HT")); + kStreamData); QuicStreamFrame frame2(GetNthClientInitiatedBidirectionalId(1), false, 0, - absl::string_view("\3\0\0\0\0\0\0\0HT")); + kStreamData); session_->OnStreamFrame(frame1); session_->OnStreamFrame(frame2); EXPECT_EQ(2u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get())); @@ -341,9 +346,9 @@ TEST_P(QuicServerSessionBaseTest, AcceptClosedStream) { // past the reset point of stream 3. As it's a closed stream we just drop the // data on the floor, but accept the packet because it has data for stream 5. QuicStreamFrame frame3(GetNthClientInitiatedBidirectionalId(0), false, 2, - absl::string_view("TP")); + kStreamData); QuicStreamFrame frame4(GetNthClientInitiatedBidirectionalId(1), false, 2, - absl::string_view("TP")); + kStreamData); session_->OnStreamFrame(frame3); session_->OnStreamFrame(frame4); // The stream should never be opened, now that the reset is received. @@ -373,7 +378,7 @@ TEST_P(QuicServerSessionBaseTest, MaxOpenStreams) { for (size_t i = 0; i < kMaxStreamsForTest; ++i) { EXPECT_TRUE(QuicServerSessionBasePeer::GetOrCreateStream(session_.get(), stream_id)); - stream_id += QuicUtils::StreamIdDelta(connection_->transport_version()); + stream_id += QuicUtils::StreamIdDelta(transport_version()); } if (!VersionHasIetfQuicFrames(transport_version())) { @@ -382,11 +387,11 @@ TEST_P(QuicServerSessionBaseTest, MaxOpenStreams) { for (size_t i = 0; i < kMaxStreamsMinimumIncrement; ++i) { EXPECT_TRUE(QuicServerSessionBasePeer::GetOrCreateStream(session_.get(), stream_id)); - stream_id += QuicUtils::StreamIdDelta(connection_->transport_version()); + stream_id += QuicUtils::StreamIdDelta(transport_version()); } } // Now violate the server's internal stream limit. - stream_id += QuicUtils::StreamIdDelta(connection_->transport_version()); + stream_id += QuicUtils::StreamIdDelta(transport_version()); if (!VersionHasIetfQuicFrames(transport_version())) { // For non-version 99, QUIC responds to an attempt to exceed the stream @@ -418,8 +423,7 @@ TEST_P(QuicServerSessionBaseTest, MaxAvailableBidirectionalStreams) { session_.get(), GetNthClientInitiatedBidirectionalId(0))); // Establish available streams up to the server's limit. - QuicStreamId next_id = - QuicUtils::StreamIdDelta(connection_->transport_version()); + QuicStreamId next_id = QuicUtils::StreamIdDelta(transport_version()); const int kLimitingStreamId = GetNthClientInitiatedBidirectionalId(kAvailableStreamLimit + 1); if (!VersionHasIetfQuicFrames(transport_version())) { @@ -456,7 +460,7 @@ TEST_P(QuicServerSessionBaseTest, GetEvenIncomingError) { TEST_P(QuicServerSessionBaseTest, GetStreamDisconnected) { // EXPECT_QUIC_BUG tests are expensive so only run one instance of them. - if (GetParam() != AllSupportedVersions()[0]) { + if (version() != AllSupportedVersions()[0]) { return; } @@ -527,14 +531,13 @@ TEST_P(QuicServerSessionBaseTest, BandwidthEstimates) { if (!VersionUsesHttp3(transport_version())) { session_->UnregisterStreamPriority( - QuicUtils::GetHeadersStreamId(connection_->transport_version()), + QuicUtils::GetHeadersStreamId(transport_version()), /*is_static=*/true); } QuicServerSessionBasePeer::SetCryptoStream(session_.get(), nullptr); MockQuicCryptoServerStream* quic_crypto_stream = nullptr; MockTlsServerHandshaker* tls_server_stream = nullptr; - if (session_->connection()->version().handshake_protocol == - PROTOCOL_QUIC_CRYPTO) { + if (version().handshake_protocol == PROTOCOL_QUIC_CRYPTO) { quic_crypto_stream = new MockQuicCryptoServerStream( &crypto_config_, &compressed_certs_cache_, session_.get(), &stream_helper_); @@ -548,7 +551,7 @@ TEST_P(QuicServerSessionBaseTest, BandwidthEstimates) { } if (!VersionUsesHttp3(transport_version())) { session_->RegisterStreamPriority( - QuicUtils::GetHeadersStreamId(connection_->transport_version()), + QuicUtils::GetHeadersStreamId(transport_version()), /*is_static=*/true, spdy::SpdyStreamPrecedence(QuicStream::kDefaultPriority)); } @@ -571,11 +574,11 @@ TEST_P(QuicServerSessionBaseTest, BandwidthEstimates) { // Queue up some pending data. if (!VersionUsesHttp3(transport_version())) { session_->MarkConnectionLevelWriteBlocked( - QuicUtils::GetHeadersStreamId(connection_->transport_version())); + QuicUtils::GetHeadersStreamId(transport_version())); } else { session_->MarkConnectionLevelWriteBlocked( - QuicUtils::GetFirstUnidirectionalStreamId( - connection_->transport_version(), Perspective::IS_SERVER)); + QuicUtils::GetFirstUnidirectionalStreamId(transport_version(), + Perspective::IS_SERVER)); } EXPECT_TRUE(session_->HasDataToWrite()); @@ -643,7 +646,7 @@ TEST_P(QuicServerSessionBaseTest, BandwidthEstimates) { } TEST_P(QuicServerSessionBaseTest, BandwidthResumptionExperiment) { - if (GetParam().handshake_protocol == PROTOCOL_TLS1_3) { + if (version().handshake_protocol == PROTOCOL_TLS1_3) { // This test relies on resumption, which is not currently supported by the // TLS handshake. // TODO(nharper): Add support for resumption to the TLS handshake. @@ -720,20 +723,6 @@ TEST_P(QuicServerSessionBaseTest, NoBandwidthResumptionByDefault) { QuicServerSessionBasePeer::IsBandwidthResumptionEnabled(session_.get())); } -TEST_P(QuicServerSessionBaseTest, TurnOffServerPush) { - if (session_->version().UsesHttp3()) { - return; - } - - EXPECT_TRUE(session_->server_push_enabled()); - QuicTagVector copt; - copt.push_back(kQNSP); - QuicConfigPeer::SetReceivedConnectionOptions(session_->config(), copt); - connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); - session_->OnConfigNegotiated(); - EXPECT_FALSE(session_->server_push_enabled()); -} - // Tests which check the lifetime management of data members of // QuicCryptoServerStream objects when async GetProof is in use. class StreamMemberLifetimeTest : public QuicServerSessionBaseTest { @@ -762,7 +751,7 @@ INSTANTIATE_TEST_SUITE_P(StreamMemberLifetimeTests, // ProofSource::GetProof. Delay the completion of the operation until after the // stream has been destroyed, and verify that there are no memory bugs. TEST_P(StreamMemberLifetimeTest, Basic) { - if (GetParam().handshake_protocol == PROTOCOL_TLS1_3) { + if (version().handshake_protocol == PROTOCOL_TLS1_3) { // This test depends on the QUIC crypto protocol, so it is disabled for the // TLS handshake. // TODO(nharper): Fix this test so it doesn't rely on QUIC crypto. @@ -771,9 +760,9 @@ TEST_P(StreamMemberLifetimeTest, Basic) { const QuicClock* clock = helper_.GetClock(); CryptoHandshakeMessage chlo = crypto_test_utils::GenerateDefaultInchoateCHLO( - clock, GetParam().transport_version, &crypto_config_); + clock, transport_version(), &crypto_config_); chlo.SetVector(kCOPT, QuicTagVector{kREJ}); - std::vector<ParsedQuicVersion> packet_version_list = {GetParam()}; + std::vector<ParsedQuicVersion> packet_version_list = {version()}; std::unique_ptr<QuicEncryptedPacket> packet(ConstructEncryptedPacket( TestConnectionId(1), EmptyQuicConnectionId(), true, false, 1, std::string(chlo.GetSerialized().AsStringPiece()), CONNECTION_ID_PRESENT, 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 7197c8ab7ed..af17b54ecff 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 @@ -278,10 +278,11 @@ TEST_P(QuicSpdyClientSessionTest, NoEncryptionAfterInitialEncryption) { EXPECT_TRUE(session_->CreateOutgoingBidirectionalStream() == nullptr); // Verify that no data may be send on existing streams. char data[] = "hello world"; - EXPECT_QUIC_BUG( + QuicConsumedData consumed = session_->WritevData(stream->id(), ABSL_ARRAYSIZE(data), 0, NO_FIN, - NOT_RETRANSMISSION, ENCRYPTION_INITIAL), - "Client: Try to send data of stream"); + NOT_RETRANSMISSION, ENCRYPTION_INITIAL); + EXPECT_EQ(0u, consumed.bytes_consumed); + EXPECT_FALSE(consumed.fin_consumed); } TEST_P(QuicSpdyClientSessionTest, MaxNumStreamsWithNoFinOrRst) { 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 16948101c6c..276a7aff6b6 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 @@ -30,7 +30,6 @@ #include "quic/platform/api/quic_flags.h" #include "quic/platform/api/quic_logging.h" #include "quic/platform/api/quic_stack_trace.h" -#include "common/platform/api/quiche_text_utils.h" #include "spdy/core/http2_frame_decoder_adapter.h" using http2::Http2DecoderAdapter; @@ -497,7 +496,6 @@ QuicSpdySession::QuicSpdySession( spdy_framer_visitor_(new SpdyFramerVisitor(this)), debug_visitor_(nullptr), destruction_indicator_(123456789), - server_push_enabled_(true), next_available_datagram_flow_id_(perspective() == Perspective::IS_SERVER ? kFirstDatagramFlowIdServer : kFirstDatagramFlowIdClient) { @@ -798,15 +796,12 @@ void QuicSpdySession::SendHttp3GoAway(QuicErrorCode error_code, const std::string& reason) { QUICHE_DCHECK_EQ(perspective(), Perspective::IS_SERVER); QUICHE_DCHECK(VersionUsesHttp3(transport_version())); - if (GetQuicReloadableFlag(quic_encrypted_goaway)) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_encrypted_goaway, 2, 2); - if (!IsEncryptionEstablished()) { - QUIC_CODE_COUNT(quic_h3_goaway_before_encryption_established); - connection()->CloseConnection( - error_code, reason, - ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); - return; - } + if (!IsEncryptionEstablished()) { + QUIC_CODE_COUNT(quic_h3_goaway_before_encryption_established); + connection()->CloseConnection( + error_code, reason, + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + return; } QuicStreamId stream_id; @@ -858,10 +853,6 @@ void QuicSpdySession::WritePushPromise(QuicStreamId original_stream_id, absl::string_view(frame.data(), frame.size()), false, nullptr); } -bool QuicSpdySession::server_push_enabled() const { - return VersionUsesHttp3(transport_version()) ? false : server_push_enabled_; -} - void QuicSpdySession::SendInitialData() { if (!VersionUsesHttp3(transport_version())) { return; @@ -1239,8 +1230,7 @@ bool QuicSpdySession::OnSetting(uint64_t id, uint64_t value) { return true; } QUIC_DVLOG(1) << ENDPOINT << "SETTINGS_ENABLE_PUSH received with value " - << value; - server_push_enabled_ = value; + << value << ", ignoring."; break; } else { QUIC_DLOG(ERROR) @@ -1458,14 +1448,7 @@ QuicStream* QuicSpdySession::ProcessPendingStream(PendingStream* pending) { default: break; } - if (GetQuicReloadableFlag(quic_unify_stop_sending)) { - QUIC_RELOADABLE_FLAG_COUNT(quic_unify_stop_sending); - MaybeSendStopSendingFrame(pending->id(), QUIC_STREAM_STREAM_CREATION_ERROR); - } else { - // TODO(renjietang): deprecate SendStopSending() when the flag is - // deprecated. - SendStopSending(QUIC_STREAM_STREAM_CREATION_ERROR, pending->id()); - } + MaybeSendStopSendingFrame(pending->id(), QUIC_STREAM_STREAM_CREATION_ERROR); pending->StopReading(); return nullptr; } 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 b2004845306..214d1da13e2 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 @@ -26,13 +26,13 @@ #include "quic/core/qpack/qpack_encoder_stream_sender.h" #include "quic/core/qpack/qpack_receive_stream.h" #include "quic/core/qpack/qpack_send_stream.h" -#include "quic/core/quic_circular_deque.h" #include "quic/core/quic_session.h" #include "quic/core/quic_time.h" #include "quic/core/quic_types.h" #include "quic/core/quic_versions.h" #include "quic/platform/api/quic_containers.h" #include "quic/platform/api/quic_export.h" +#include "common/quiche_circular_deque.h" #include "spdy/core/http2_frame_decoder_adapter.h" namespace quic { @@ -251,12 +251,6 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession const QuicHeadersStream* headers_stream() const { return headers_stream_; } - // Returns whether server push is enabled. - // For a Google QUIC client this always returns false. - // For a Google QUIC server this is set by incoming SETTINGS_ENABLE_PUSH. - // For an IETF QUIC client or server this returns false. - bool server_push_enabled() const; - // Called when the control stream receives HTTP/3 SETTINGS. // Returns false in case of 0-RTT if received settings are incompatible with // cached values, true otherwise. @@ -684,10 +678,6 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession // an use-after-free. int32_t destruction_indicator_; - // Used in Google QUIC only. Set every time SETTINGS_ENABLE_PUSH is received. - // Defaults to true. - bool server_push_enabled_; - // The identifier in the most recently received GOAWAY frame. Unset if no // GOAWAY frame has been received yet. absl::optional<uint64_t> last_received_http3_goaway_id_; 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 d8bfa782aa7..29e1f6b7bcd 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 @@ -38,7 +38,6 @@ #include "quic/platform/api/quic_map_util.h" #include "quic/platform/api/quic_test.h" #include "quic/test_tools/qpack/qpack_encoder_peer.h" -#include "quic/test_tools/qpack/qpack_header_table_peer.h" #include "quic/test_tools/qpack/qpack_test_utils.h" #include "quic/test_tools/quic_config_peer.h" #include "quic/test_tools/quic_connection_peer.h" @@ -48,7 +47,6 @@ #include "quic/test_tools/quic_stream_peer.h" #include "quic/test_tools/quic_stream_send_buffer_peer.h" #include "quic/test_tools/quic_test_utils.h" -#include "common/platform/api/quiche_text_utils.h" #include "common/quiche_endian.h" #include "common/test_tools/quiche_test_utils.h" #include "spdy/core/spdy_framer.h" @@ -559,7 +557,6 @@ class QuicSpdySessionTestBase : public QuicTestWithParam<ParsedQuicVersion> { } void ReceiveWebTransportSession(WebTransportSessionId session_id) { - SetQuicReloadableFlag(quic_accept_empty_stream_frame_with_no_fin, true); QuicStreamFrame frame(session_id, /*fin=*/false, /*offset=*/0, absl::string_view()); session_.OnStreamFrame(frame); @@ -1178,7 +1175,6 @@ TEST_P(QuicSpdySessionTestServer, SendGoAway) { } TEST_P(QuicSpdySessionTestServer, SendGoAwayWithoutEncryption) { - SetQuicReloadableFlag(quic_encrypted_goaway, true); if (VersionHasIetfQuicFrames(transport_version())) { // HTTP/3 GOAWAY has different semantic and thus has its own test. return; @@ -1220,7 +1216,6 @@ TEST_P(QuicSpdySessionTestServer, SendHttp3GoAway) { } TEST_P(QuicSpdySessionTestServer, SendHttp3GoAwayWithoutEncryption) { - SetQuicReloadableFlag(quic_encrypted_goaway, true); if (!VersionUsesHttp3(transport_version())) { return; } @@ -1918,12 +1913,6 @@ TEST_P(QuicSpdySessionTestClient, BadStreamFramePendingStream) { GetNthServerInitiatedUnidirectionalStreamId(transport_version(), 0); // A bad stream frame with no data and no fin. QuicStreamFrame data1(stream_id1, false, 0, 0); - if (!GetQuicReloadableFlag(quic_accept_empty_stream_frame_with_no_fin)) { - EXPECT_CALL(*connection_, CloseConnection(_, _, _)) - .WillOnce( - Invoke(connection_, &MockQuicConnection::ReallyCloseConnection)); - EXPECT_CALL(*connection_, SendConnectionClosePacket(_, _, _)); - } session_.OnStreamFrame(data1); } @@ -2519,19 +2508,17 @@ TEST_P(QuicSpdySessionTestServer, ReceiveControlStream) { QuicStreamFrame frame(stream_id, false, 1, absl::string_view(data)); QpackEncoder* qpack_encoder = session_.qpack_encoder(); - QpackHeaderTable* header_table = + QpackEncoderHeaderTable* header_table = QpackEncoderPeer::header_table(qpack_encoder); - EXPECT_NE(512u, - QpackHeaderTablePeer::maximum_dynamic_table_capacity(header_table)); + EXPECT_NE(512u, header_table->maximum_dynamic_table_capacity()); EXPECT_NE(5u, session_.max_outbound_header_list_size()); EXPECT_NE(42u, QpackEncoderPeer::maximum_blocked_streams(qpack_encoder)); EXPECT_CALL(debug_visitor, OnSettingsFrameReceived(settings)); session_.OnStreamFrame(frame); - EXPECT_EQ(512u, - QpackHeaderTablePeer::maximum_dynamic_table_capacity(header_table)); + EXPECT_EQ(512u, header_table->maximum_dynamic_table_capacity()); EXPECT_EQ(5u, session_.max_outbound_header_list_size()); EXPECT_EQ(42u, QpackEncoderPeer::maximum_blocked_streams(qpack_encoder)); } @@ -2618,10 +2605,10 @@ TEST_P(QuicSpdySessionTestServer, SessionDestroyedWhileHeaderDecodingBlocked) { EXPECT_FALSE(stream->headers_decompressed()); // |session_| gets destoyed. That destroys QpackDecoder, a member of - // QuicSpdySession (derived class), which destroys QpackHeaderTable. + // QuicSpdySession (derived class), which destroys QpackDecoderHeaderTable. // Then |*stream|, owned by QuicSession (base class) get destroyed, which - // destroys QpackProgessiveDecoder, a registered Observer of QpackHeaderTable. - // This must not cause a crash. + // destroys QpackProgessiveDecoder, a registered Observer of + // QpackDecoderHeaderTable. This must not cause a crash. } TEST_P(QuicSpdySessionTestClient, ResetAfterInvalidIncomingStreamType) { @@ -2897,10 +2884,7 @@ TEST_P(QuicSpdySessionTestClient, Http3GoAwayLargerIdThanBefore) { session_.OnHttp3GoAway(stream_id2); } -// Test that receipt of CANCEL_PUSH frame does not result in closing the -// connection. -// TODO(b/151841240): Handle CANCEL_PUSH frames instead of ignoring them. -TEST_P(QuicSpdySessionTestClient, IgnoreCancelPush) { +TEST_P(QuicSpdySessionTestClient, CloseConnectionOnCancelPush) { if (!VersionUsesHttp3(transport_version())) { return; } @@ -2937,16 +2921,19 @@ TEST_P(QuicSpdySessionTestClient, IgnoreCancelPush) { "00"); // push ID QuicStreamFrame data3(receive_control_stream_id, /* fin = */ false, offset, cancel_push_frame); - EXPECT_CALL(debug_visitor, OnCancelPushFrameReceived(_)); - session_.OnStreamFrame(data3); -} - -TEST_P(QuicSpdySessionTestServer, ServerPushEnabledDefaultValue) { - if (VersionUsesHttp3(transport_version())) { - EXPECT_FALSE(session_.server_push_enabled()); + if (GetQuicReloadableFlag(quic_error_on_http3_push)) { + EXPECT_CALL(*connection_, CloseConnection(QUIC_HTTP_FRAME_ERROR, + "CANCEL_PUSH frame received.", _)) + .WillOnce( + Invoke(connection_, &MockQuicConnection::ReallyCloseConnection)); + EXPECT_CALL(*connection_, + SendConnectionClosePacket(QUIC_HTTP_FRAME_ERROR, _, + "CANCEL_PUSH frame received.")); } else { - EXPECT_TRUE(session_.server_push_enabled()); + // CANCEL_PUSH is ignored. + EXPECT_CALL(debug_visitor, OnCancelPushFrameReceived(_)); } + session_.OnStreamFrame(data3); } TEST_P(QuicSpdySessionTestServer, OnSetting) { @@ -2964,7 +2951,7 @@ TEST_P(QuicSpdySessionTestServer, OnSetting) { session_.OnSetting(SETTINGS_QPACK_BLOCKED_STREAMS, 12); EXPECT_EQ(12u, QpackEncoderPeer::maximum_blocked_streams(qpack_encoder)); - QpackHeaderTable* header_table = + QpackEncoderHeaderTable* header_table = QpackEncoderPeer::header_table(qpack_encoder); EXPECT_EQ(0u, header_table->maximum_dynamic_table_capacity()); session_.OnSetting(SETTINGS_QPACK_MAX_TABLE_CAPACITY, 37); @@ -2978,10 +2965,6 @@ TEST_P(QuicSpdySessionTestServer, OnSetting) { session_.OnSetting(SETTINGS_MAX_FIELD_SECTION_SIZE, 5); EXPECT_EQ(5u, session_.max_outbound_header_list_size()); - EXPECT_TRUE(session_.server_push_enabled()); - session_.OnSetting(spdy::SETTINGS_ENABLE_PUSH, 0); - EXPECT_FALSE(session_.server_push_enabled()); - spdy::HpackEncoder* hpack_encoder = QuicSpdySessionPeer::GetSpdyFramer(&session_)->GetHpackEncoder(); EXPECT_EQ(4096u, hpack_encoder->CurrentHeaderTableSizeSetting()); @@ -3108,10 +3091,7 @@ TEST_P(QuicSpdySessionTestServer, PeerClosesCriticalSendStream) { session_.OnStopSendingFrame(stop_sending_encoder_stream); } -// Test that receipt of CANCEL_PUSH frame does not result in closing the -// connection. -// TODO(b/151841240): Handle CANCEL_PUSH frames instead of ignoring them. -TEST_P(QuicSpdySessionTestServer, IgnoreCancelPush) { +TEST_P(QuicSpdySessionTestServer, CloseConnectionOnCancelPush) { if (!VersionUsesHttp3(transport_version())) { return; } @@ -3148,7 +3128,18 @@ TEST_P(QuicSpdySessionTestServer, IgnoreCancelPush) { "00"); // push ID QuicStreamFrame data3(receive_control_stream_id, /* fin = */ false, offset, cancel_push_frame); - EXPECT_CALL(debug_visitor, OnCancelPushFrameReceived(_)); + if (GetQuicReloadableFlag(quic_error_on_http3_push)) { + EXPECT_CALL(*connection_, CloseConnection(QUIC_HTTP_FRAME_ERROR, + "CANCEL_PUSH frame received.", _)) + .WillOnce( + Invoke(connection_, &MockQuicConnection::ReallyCloseConnection)); + EXPECT_CALL(*connection_, + SendConnectionClosePacket(QUIC_HTTP_FRAME_ERROR, _, + "CANCEL_PUSH frame received.")); + } else { + // CANCEL_PUSH is ignored. + EXPECT_CALL(debug_visitor, OnCancelPushFrameReceived(_)); + } session_.OnStreamFrame(data3); } 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 4d4cc95f94d..6ec48ca5896 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 @@ -30,7 +30,7 @@ #include "quic/platform/api/quic_flags.h" #include "quic/platform/api/quic_logging.h" #include "quic/platform/api/quic_mem_slice_storage.h" -#include "common/platform/api/quiche_text_utils.h" +#include "common/quiche_text_utils.h" #include "spdy/core/spdy_protocol.h" using spdy::SpdyHeaderBlock; @@ -434,7 +434,12 @@ QuicConsumedData QuicSpdyStream::WriteBodySlices(QuicMemSliceSpan slices, QuicConnection::ScopedPacketFlusher flusher(spdy_session_->connection()); // Write frame header. +#if !defined(__ANDROID__) struct iovec header_iov = {static_cast<void*>(buffer.get()), header_length}; +#else + struct iovec header_iov = {static_cast<void*>(buffer.get()), + static_cast<__kernel_size_t>(header_length)}; +#endif QuicMemSliceStorage storage( &header_iov, 1, spdy_session_->connection()->helper()->GetStreamSendBufferAllocator(), diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_manager.h b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_manager.h index 7b2d9f19186..f34801a383c 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_manager.h +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_manager.h @@ -7,11 +7,11 @@ #include "absl/base/attributes.h" #include "absl/strings/string_view.h" -#include "quic/core/quic_circular_deque.h" #include "quic/core/quic_constants.h" #include "quic/platform/api/quic_bug_tracker.h" #include "quic/platform/api/quic_export.h" #include "quic/platform/api/quic_iovec.h" +#include "common/quiche_circular_deque.h" namespace quic { @@ -84,7 +84,7 @@ class QUIC_EXPORT_PRIVATE QuicSpdyStreamBodyManager { QuicByteCount trailing_non_body_byte_count; }; // Queue of body fragments and trailing non-body byte counts. - QuicCircularDeque<Fragment> fragments_; + quiche::QuicheCircularDeque<Fragment> fragments_; // Total body bytes received. QuicByteCount total_body_bytes_received_; }; 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 bb464bdb4d5..8b814b8400b 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 @@ -2772,6 +2772,9 @@ TEST_P(QuicSpdyStreamIncrementalConsumptionTest, UnknownFramesInterleaved) { // TODO(b/171463363): Remove. TEST_P(QuicSpdyStreamTest, PushPromiseOnDataStream) { Initialize(kShouldProcessData); + if (GetQuicReloadableFlag(quic_error_on_http3_push)) { + return; + } if (!UsesHttp3()) { return; } @@ -2802,6 +2805,9 @@ TEST_P(QuicSpdyStreamTest, PushPromiseOnDataStream) { TEST_P(QuicSpdyStreamTest, OnStreamHeaderBlockArgumentDoesNotIncludePushedHeaderBlock) { Initialize(kShouldProcessData); + if (GetQuicReloadableFlag(quic_error_on_http3_push)) { + return; + } if (!UsesHttp3()) { return; } diff --git a/chromium/net/third_party/quiche/src/quic/core/http/spdy_utils.cc b/chromium/net/third_party/quiche/src/quic/core/http/spdy_utils.cc index d3a3c92d209..28b463afebe 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/spdy_utils.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/spdy_utils.cc @@ -17,7 +17,7 @@ #include "quic/platform/api/quic_flags.h" #include "quic/platform/api/quic_logging.h" #include "quic/platform/api/quic_map_util.h" -#include "common/platform/api/quiche_text_utils.h" +#include "common/quiche_text_utils.h" #include "spdy/core/spdy_protocol.h" using spdy::SpdyHeaderBlock; diff --git a/chromium/net/third_party/quiche/src/quic/core/http/spdy_utils_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/spdy_utils_test.cc index c7207f383b3..7307665da3d 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/spdy_utils_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/spdy_utils_test.cc @@ -9,7 +9,6 @@ #include "absl/strings/string_view.h" #include "quic/core/http/spdy_utils.h" #include "quic/platform/api/quic_test.h" -#include "common/platform/api/quiche_text_utils.h" using spdy::SpdyHeaderBlock; using testing::Pair; diff --git a/chromium/net/third_party/quiche/src/quic/core/http/web_transport_http3.h b/chromium/net/third_party/quiche/src/quic/core/http/web_transport_http3.h index 0c91c2b32a4..667256ea515 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/web_transport_http3.h +++ b/chromium/net/third_party/quiche/src/quic/core/http/web_transport_http3.h @@ -75,8 +75,8 @@ class QUIC_EXPORT_PRIVATE WebTransportHttp3 bool ready_ = false; std::unique_ptr<WebTransportVisitor> visitor_; absl::flat_hash_set<QuicStreamId> streams_; - QuicCircularDeque<QuicStreamId> incoming_bidirectional_streams_; - QuicCircularDeque<QuicStreamId> incoming_unidirectional_streams_; + quiche::QuicheCircularDeque<QuicStreamId> incoming_bidirectional_streams_; + quiche::QuicheCircularDeque<QuicStreamId> incoming_unidirectional_streams_; }; class QUIC_EXPORT_PRIVATE WebTransportHttp3UnidirectionalStream diff --git a/chromium/net/third_party/quiche/src/quic/core/packet_number_indexed_queue.h b/chromium/net/third_party/quiche/src/quic/core/packet_number_indexed_queue.h index b83916060e9..8e80c7de4b7 100644 --- a/chromium/net/third_party/quiche/src/quic/core/packet_number_indexed_queue.h +++ b/chromium/net/third_party/quiche/src/quic/core/packet_number_indexed_queue.h @@ -5,11 +5,11 @@ #ifndef QUICHE_QUIC_CORE_PACKET_NUMBER_INDEXED_QUEUE_H_ #define QUICHE_QUIC_CORE_PACKET_NUMBER_INDEXED_QUEUE_H_ -#include "quic/core/quic_circular_deque.h" #include "quic/core/quic_constants.h" #include "quic/core/quic_packet_number.h" #include "quic/core/quic_types.h" #include "quic/platform/api/quic_bug_tracker.h" +#include "common/quiche_circular_deque.h" namespace quic { @@ -115,7 +115,7 @@ class QUIC_NO_EXPORT PacketNumberIndexedQueue { return const_cast<EntryWrapper*>(const_this->GetEntryWrapper(offset)); } - QuicCircularDeque<EntryWrapper> entries_; + quiche::QuicheCircularDeque<EntryWrapper> entries_; // NOTE(wub): When --quic_bw_sampler_remove_packets_once_per_congestion_event // is enabled, |number_of_present_entries_| only represents number of holes, // which does not include number of acked or lost packets. diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.h index 70870a60314..4188350e463 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.h +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.h @@ -75,8 +75,8 @@ class QUIC_EXPORT_PRIVATE QpackBlockingManager { // 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 QuicCircularDeque because it has lower - // memory footprint when holding few elements. + // same time. Use std::list instead of quiche::QuicheCircularDeque because it + // has lower memory footprint when holding few elements. using HeaderBlocksForStream = std::list<IndexSet>; using HeaderBlocks = absl::flat_hash_map<QuicStreamId, HeaderBlocksForStream>; 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 9ba7f1c511f..217f866dce1 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 @@ -12,7 +12,6 @@ #include "quic/platform/api/quic_test.h" #include "quic/test_tools/qpack/qpack_decoder_test_utils.h" #include "quic/test_tools/qpack/qpack_test_utils.h" -#include "common/platform/api/quiche_text_utils.h" using ::testing::_; using ::testing::ElementsAre; 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 32178bd9d7c..b947ce3cf0e 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 @@ -111,7 +111,7 @@ class QUIC_EXPORT_PRIVATE QpackDecoder EncoderStreamErrorDelegate* const encoder_stream_error_delegate_; QpackEncoderStreamReceiver encoder_stream_receiver_; QpackDecoderStreamSender decoder_stream_sender_; - QpackHeaderTable header_table_; + QpackDecoderHeaderTable header_table_; std::set<QuicStreamId> blocked_streams_; const uint64_t maximum_blocked_streams_; diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_receiver_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_receiver_test.cc index 272597ac191..0a76a17450f 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_receiver_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_receiver_test.cc @@ -7,7 +7,6 @@ #include "absl/strings/escaping.h" #include "absl/strings/string_view.h" #include "quic/platform/api/quic_test.h" -#include "common/platform/api/quiche_text_utils.h" using testing::Eq; using testing::StrictMock; 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 275e76f3ca1..708e7a3d3f1 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 @@ -7,7 +7,6 @@ #include "absl/strings/escaping.h" #include "quic/platform/api/quic_test.h" #include "quic/test_tools/qpack/qpack_test_utils.h" -#include "common/platform/api/quiche_text_utils.h" using ::testing::Eq; using ::testing::StrictMock; diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test.cc index 3b57ca6f1c3..772b1d25480 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 @@ -13,7 +13,6 @@ #include "quic/platform/api/quic_test.h" #include "quic/test_tools/qpack/qpack_decoder_test_utils.h" #include "quic/test_tools/qpack/qpack_test_utils.h" -#include "common/platform/api/quiche_text_utils.h" #include "spdy/core/spdy_header_block.h" using ::testing::_; 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 5e61ee7490b..3ae944152c0 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 @@ -122,7 +122,7 @@ QpackEncoder::Representations QpackEncoder::FirstPassEncode( header_table_.FindHeaderField(name, value, &is_static, &index); switch (match_type) { - case QpackHeaderTable::MatchType::kNameAndValue: + case QpackEncoderHeaderTable::MatchType::kNameAndValue: if (is_static) { // Refer to entry directly. representations.push_back( @@ -175,7 +175,7 @@ QpackEncoder::Representations QpackEncoder::FirstPassEncode( break; - case QpackHeaderTable::MatchType::kName: + case QpackEncoderHeaderTable::MatchType::kName: if (is_static) { if (blocking_allowed && QpackEntry::Size(name, value) <= @@ -242,7 +242,7 @@ QpackEncoder::Representations QpackEncoder::FirstPassEncode( break; - case QpackHeaderTable::MatchType::kNoMatch: + case QpackEncoderHeaderTable::MatchType::kNoMatch: // If allowed, insert entry and refer to it. if (!blocking_allowed) { blocked_stream_limit_exhausted = true; 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 9d024417c93..c3d77fea061 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 @@ -153,7 +153,7 @@ class QUIC_EXPORT_PRIVATE QpackEncoder DecoderStreamErrorDelegate* const decoder_stream_error_delegate_; QpackDecoderStreamReceiver decoder_stream_receiver_; QpackEncoderStreamSender encoder_stream_sender_; - QpackHeaderTable header_table_; + QpackEncoderHeaderTable header_table_; uint64_t maximum_blocked_streams_; QpackBlockingManager blocking_manager_; int header_list_count_; diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_receiver_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_receiver_test.cc index efe5eb90b98..2fa440b51b4 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_receiver_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_receiver_test.cc @@ -7,7 +7,6 @@ #include "absl/strings/escaping.h" #include "absl/strings/string_view.h" #include "quic/platform/api/quic_test.h" -#include "common/platform/api/quiche_text_utils.h" using testing::Eq; using testing::StrictMock; 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 5078c8f0d05..98e3e23030f 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 @@ -7,7 +7,6 @@ #include "absl/strings/escaping.h" #include "quic/platform/api/quic_test.h" #include "quic/test_tools/qpack/qpack_test_utils.h" -#include "common/platform/api/quiche_text_utils.h" using ::testing::Eq; using ::testing::StrictMock; diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test.cc index 5045c8fb350..21397ed8571 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 @@ -14,9 +14,7 @@ #include "quic/platform/api/quic_test.h" #include "quic/test_tools/qpack/qpack_encoder_peer.h" #include "quic/test_tools/qpack/qpack_encoder_test_utils.h" -#include "quic/test_tools/qpack/qpack_header_table_peer.h" #include "quic/test_tools/qpack/qpack_test_utils.h" -#include "common/platform/api/quiche_text_utils.h" using ::testing::_; using ::testing::Eq; @@ -186,7 +184,8 @@ TEST_F(QpackEncoderTest, TooLargeInsertCountIncrement) { // Regression test for https://crbug.com/1014372. TEST_F(QpackEncoderTest, InsertCountIncrementOverflow) { - QpackHeaderTable* header_table = QpackEncoderPeer::header_table(&encoder_); + QpackEncoderHeaderTable* header_table = + QpackEncoderPeer::header_table(&encoder_); // Set dynamic table capacity large enough to hold one entry. header_table->SetMaximumDynamicTableCapacity(4096); @@ -461,11 +460,11 @@ TEST_F(QpackEncoderTest, DynamicTableCapacityLessThanMaximum) { encoder_.SetMaximumDynamicTableCapacity(1024); encoder_.SetDynamicTableCapacity(30); - QpackHeaderTable* header_table = QpackEncoderPeer::header_table(&encoder_); + QpackEncoderHeaderTable* 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)); + EXPECT_EQ(1024u, header_table->maximum_dynamic_table_capacity()); + EXPECT_EQ(30u, header_table->dynamic_table_capacity()); } } // namespace 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 da3636db4e4..660727231d6 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 @@ -10,47 +10,47 @@ namespace quic { -QpackHeaderTable::QpackHeaderTable() - : static_entries_(ObtainQpackStaticTable().GetStaticEntries()), - static_index_(ObtainQpackStaticTable().GetStaticIndex()), - static_name_index_(ObtainQpackStaticTable().GetStaticNameIndex()), - dynamic_table_size_(0), - dynamic_table_capacity_(0), - maximum_dynamic_table_capacity_(0), - max_entries_(0), - dropped_entry_count_(0), - dynamic_table_entry_referenced_(false) {} - -QpackHeaderTable::~QpackHeaderTable() { - for (auto& entry : observers_) { - entry.second->Cancel(); - } -} +QpackEncoderHeaderTable::QpackEncoderHeaderTable() + : static_index_(ObtainQpackStaticTable().GetStaticIndex()), + static_name_index_(ObtainQpackStaticTable().GetStaticNameIndex()) {} -const QpackEntry* QpackHeaderTable::LookupEntry(bool is_static, - uint64_t index) const { - if (is_static) { - if (index >= static_entries_.size()) { - return nullptr; - } +uint64_t QpackEncoderHeaderTable::InsertEntry(absl::string_view name, + absl::string_view value) { + const uint64_t index = + QpackHeaderTableBase<QpackEncoderDynamicTable>::InsertEntry(name, value); - return &static_entries_[index]; - } + // Make name and value point to the new entry. + name = dynamic_entries().back().name(); + value = dynamic_entries().back().value(); - if (index < dropped_entry_count_) { - return nullptr; + auto index_result = dynamic_index_.insert( + std::make_pair(QpackLookupEntry{name, value}, index)); + if (!index_result.second) { + // An entry with the same name and value already exists. It needs to be + // replaced, because |dynamic_index_| tracks the most recent entry for a + // given name and value. + QUICHE_DCHECK_GT(index, index_result.first->second); + dynamic_index_.erase(index_result.first); + auto result = dynamic_index_.insert( + std::make_pair(QpackLookupEntry{name, value}, index)); + QUICHE_CHECK(result.second); } - index -= dropped_entry_count_; - - if (index >= dynamic_entries_.size()) { - return nullptr; + auto name_result = dynamic_name_index_.insert({name, index}); + if (!name_result.second) { + // An entry with the same name already exists. It needs to be replaced, + // because |dynamic_name_index_| tracks the most recent entry for a given + // name. + QUICHE_DCHECK_GT(index, name_result.first->second); + dynamic_name_index_.erase(name_result.first); + auto result = dynamic_name_index_.insert({name, index}); + QUICHE_CHECK(result.second); } - return &dynamic_entries_[index]; + return index; } -QpackHeaderTable::MatchType QpackHeaderTable::FindHeaderField( +QpackEncoderHeaderTable::MatchType QpackEncoderHeaderTable::FindHeaderField( absl::string_view name, absl::string_view value, bool* is_static, @@ -92,56 +92,92 @@ QpackHeaderTable::MatchType QpackHeaderTable::FindHeaderField( return MatchType::kNoMatch; } -bool QpackHeaderTable::EntryFitsDynamicTableCapacity( - absl::string_view name, - absl::string_view value) const { - return QpackEntry::Size(name, value) <= dynamic_table_capacity_; +uint64_t QpackEncoderHeaderTable::MaxInsertSizeWithoutEvictingGivenEntry( + uint64_t index) const { + QUICHE_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(); + + uint64_t entry_index = dropped_entry_count(); + for (const auto& entry : dynamic_entries()) { + if (entry_index >= index) { + break; + } + ++entry_index; + max_insert_size += entry.Size(); + } + + return max_insert_size; } -uint64_t QpackHeaderTable::InsertEntry(absl::string_view name, - absl::string_view value) { - QUICHE_DCHECK(EntryFitsDynamicTableCapacity(name, value)); +uint64_t QpackEncoderHeaderTable::draining_index( + float draining_fraction) const { + QUICHE_DCHECK_LE(0.0, draining_fraction); + QUICHE_DCHECK_LE(draining_fraction, 1.0); - const uint64_t index = dropped_entry_count_ + dynamic_entries_.size(); + const uint64_t required_space = draining_fraction * dynamic_table_capacity(); + uint64_t space_above_draining_index = + dynamic_table_capacity() - dynamic_table_size(); - // Copy name and value before modifying the container, because evicting - // entries or even inserting a new one might invalidate |name| or |value| if - // they point to an entry. - QpackEntry new_entry((std::string(name)), (std::string(value))); - const size_t entry_size = new_entry.Size(); + if (dynamic_entries().empty() || + space_above_draining_index >= required_space) { + return dropped_entry_count(); + } - EvictDownToCapacity(dynamic_table_capacity_ - entry_size); + auto it = dynamic_entries().begin(); + uint64_t entry_index = dropped_entry_count(); + while (space_above_draining_index < required_space) { + space_above_draining_index += it->Size(); + ++it; + ++entry_index; + if (it == dynamic_entries().end()) { + return inserted_entry_count(); + } + } - dynamic_table_size_ += entry_size; - dynamic_entries_.push_back(std::move(new_entry)); + return entry_index; +} - // Make name and value point to the new entry. - name = dynamic_entries_.back().name(); - value = dynamic_entries_.back().value(); +void QpackEncoderHeaderTable::RemoveEntryFromEnd() { + const QpackEntry* const entry = &dynamic_entries().front(); + const uint64_t index = dropped_entry_count(); - auto index_result = dynamic_index_.insert( - std::make_pair(QpackLookupEntry{name, value}, index)); - if (!index_result.second) { - // An entry with the same name and value already exists. It needs to be - // replaced, because |dynamic_index_| tracks the most recent entry for a - // given name and value. - QUICHE_DCHECK_GT(index, index_result.first->second); - dynamic_index_.erase(index_result.first); - auto result = dynamic_index_.insert( - std::make_pair(QpackLookupEntry{name, value}, index)); - QUICHE_CHECK(result.second); + auto index_it = dynamic_index_.find({entry->name(), entry->value()}); + // Remove |dynamic_index_| entry only if it points to the same + // QpackEntry in dynamic_entries(). + if (index_it != dynamic_index_.end() && index_it->second == index) { + dynamic_index_.erase(index_it); } - auto name_result = dynamic_name_index_.insert({name, index}); - if (!name_result.second) { - // An entry with the same name already exists. It needs to be replaced, - // because |dynamic_name_index_| tracks the most recent entry for a given - // name. - QUICHE_DCHECK_GT(index, name_result.first->second); - dynamic_name_index_.erase(name_result.first); - auto result = dynamic_name_index_.insert({name, index}); - QUICHE_CHECK(result.second); + auto name_it = dynamic_name_index_.find(entry->name()); + // Remove |dynamic_name_index_| entry only if it points to the same + // QpackEntry in dynamic_entries(). + if (name_it != dynamic_name_index_.end() && name_it->second == index) { + dynamic_name_index_.erase(name_it); + } + + QpackHeaderTableBase<QpackEncoderDynamicTable>::RemoveEntryFromEnd(); +} + +QpackDecoderHeaderTable::QpackDecoderHeaderTable() + : static_entries_(ObtainQpackStaticTable().GetStaticEntries()) {} + +QpackDecoderHeaderTable::~QpackDecoderHeaderTable() { + for (auto& entry : observers_) { + entry.second->Cancel(); } +} + +uint64_t QpackDecoderHeaderTable::InsertEntry(absl::string_view name, + absl::string_view value) { + const uint64_t index = + QpackHeaderTableBase<QpackDecoderDynamicTable>::InsertEntry(name, value); // Notify and deregister observers whose threshold is met, if any. while (!observers_.empty()) { @@ -157,62 +193,37 @@ uint64_t QpackHeaderTable::InsertEntry(absl::string_view name, return index; } -uint64_t QpackHeaderTable::MaxInsertSizeWithoutEvictingGivenEntry( - uint64_t index) const { - QUICHE_DCHECK_LE(dropped_entry_count_, index); +const QpackEntry* QpackDecoderHeaderTable::LookupEntry(bool is_static, + uint64_t index) const { + if (is_static) { + if (index >= static_entries_.size()) { + return nullptr; + } - if (index > inserted_entry_count()) { - // All entries are allowed to be evicted. - return dynamic_table_capacity_; + return &static_entries_[index]; } - // Initialize to current available capacity. - uint64_t max_insert_size = dynamic_table_capacity_ - dynamic_table_size_; - - uint64_t entry_index = dropped_entry_count_; - for (const auto& entry : dynamic_entries_) { - if (entry_index >= index) { - break; - } - ++entry_index; - max_insert_size += entry.Size(); + if (index < dropped_entry_count()) { + return nullptr; } - return max_insert_size; -} + index -= dropped_entry_count(); -bool QpackHeaderTable::SetDynamicTableCapacity(uint64_t capacity) { - if (capacity > maximum_dynamic_table_capacity_) { - return false; + if (index >= dynamic_entries().size()) { + return nullptr; } - dynamic_table_capacity_ = capacity; - EvictDownToCapacity(capacity); - - QUICHE_DCHECK_LE(dynamic_table_size_, dynamic_table_capacity_); - - return true; -} - -bool QpackHeaderTable::SetMaximumDynamicTableCapacity( - uint64_t maximum_dynamic_table_capacity) { - if (maximum_dynamic_table_capacity_ == 0) { - maximum_dynamic_table_capacity_ = maximum_dynamic_table_capacity; - max_entries_ = maximum_dynamic_table_capacity / 32; - return true; - } - // If the value is already set, it should not be changed. - return maximum_dynamic_table_capacity == maximum_dynamic_table_capacity_; + return &dynamic_entries()[index]; } -void QpackHeaderTable::RegisterObserver(uint64_t required_insert_count, - Observer* observer) { +void QpackDecoderHeaderTable::RegisterObserver(uint64_t required_insert_count, + Observer* observer) { QUICHE_DCHECK_GT(required_insert_count, 0u); observers_.insert({required_insert_count, observer}); } -void QpackHeaderTable::UnregisterObserver(uint64_t required_insert_count, - Observer* observer) { +void QpackDecoderHeaderTable::UnregisterObserver(uint64_t required_insert_count, + Observer* observer) { auto it = observers_.lower_bound(required_insert_count); while (it != observers_.end() && it->first == required_insert_count) { if (it->second == observer) { @@ -226,62 +237,4 @@ void QpackHeaderTable::UnregisterObserver(uint64_t required_insert_count, QUIC_NOTREACHED(); } -uint64_t QpackHeaderTable::draining_index(float draining_fraction) const { - QUICHE_DCHECK_LE(0.0, draining_fraction); - QUICHE_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(); - uint64_t entry_index = dropped_entry_count_; - while (space_above_draining_index < required_space) { - space_above_draining_index += it->Size(); - ++it; - ++entry_index; - if (it == dynamic_entries_.end()) { - return inserted_entry_count(); - } - } - - return entry_index; -} - -void QpackHeaderTable::EvictDownToCapacity(uint64_t capacity) { - while (dynamic_table_size_ > capacity) { - QUICHE_DCHECK(!dynamic_entries_.empty()); - - QpackEntry* const entry = &dynamic_entries_.front(); - - const uint64_t entry_size = entry->Size(); - QUICHE_DCHECK_GE(dynamic_table_size_, entry_size); - dynamic_table_size_ -= entry_size; - - const uint64_t index = dropped_entry_count_; - - auto index_it = dynamic_index_.find({entry->name(), entry->value()}); - // Remove |dynamic_index_| entry only if it points to the same - // QpackEntry in |dynamic_entries_|. - if (index_it != dynamic_index_.end() && index_it->second == index) { - dynamic_index_.erase(index_it); - } - - auto name_it = dynamic_name_index_.find(entry->name()); - // Remove |dynamic_name_index_| entry only if it points to the same - // QpackEntry in |dynamic_entries_|. - if (name_it != dynamic_name_index_.end() && name_it->second == index) { - dynamic_name_index_.erase(name_it); - } - - dynamic_entries_.pop_front(); - ++dropped_entry_count_; - } -} - } // namespace quic 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 a5d6c5d74b8..7193d102294 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 @@ -6,75 +6,41 @@ #define QUICHE_QUIC_CORE_QPACK_QPACK_HEADER_TABLE_H_ #include <cstdint> -#include <functional> -#include <queue> -#include <vector> +#include <deque> #include "absl/strings/string_view.h" #include "quic/platform/api/quic_export.h" +#include "common/quiche_circular_deque.h" #include "spdy/core/hpack/hpack_entry.h" #include "spdy/core/hpack/hpack_header_table.h" namespace quic { -namespace test { - -class QpackHeaderTablePeer; - -} // namespace test - using QpackEntry = spdy::HpackEntry; using QpackLookupEntry = spdy::HpackLookupEntry; constexpr size_t kQpackEntrySizeOverhead = spdy::kHpackEntrySizeOverhead; -// This class manages the QPACK static and dynamic tables. For dynamic entries, -// it only has a concept of absolute indices. The caller needs to perform the -// necessary transformations to and from relative indices and post-base indices. -class QUIC_EXPORT_PRIVATE QpackHeaderTable { +// Encoder needs pointer stability for |dynamic_index_| and +// |dynamic_name_index_|. However, it does not need random access. +// TODO(b/182349990): Change to a more memory efficient container. +using QpackEncoderDynamicTable = std::deque<QpackEntry>; + +// Decoder needs random access for LookupEntry(). +// However, it does not need pointer stability. +using QpackDecoderDynamicTable = quiche::QuicheCircularDeque<QpackEntry>; + +// This is a base class for encoder and decoder classes that manage the QPACK +// static and dynamic tables. For dynamic entries, it only has a concept of +// absolute indices. The caller needs to perform the necessary transformations +// to and from relative indices and post-base indices. +template <typename DynamicEntryTable> +class QUIC_EXPORT_PRIVATE QpackHeaderTableBase { public: - using StaticEntryTable = spdy::HpackHeaderTable::StaticEntryTable; - using DynamicEntryTable = spdy::HpackHeaderTable::DynamicEntryTable; - using NameValueToEntryMap = spdy::HpackHeaderTable::NameValueToEntryMap; - using NameToEntryMap = spdy::HpackHeaderTable::NameToEntryMap; + QpackHeaderTableBase(); + QpackHeaderTableBase(const QpackHeaderTableBase&) = delete; + QpackHeaderTableBase& operator=(const QpackHeaderTableBase&) = delete; - // Result of header table lookup. - enum class MatchType { kNameAndValue, kName, kNoMatch }; - - // Observer interface for dynamic table insertion. - class QUIC_EXPORT_PRIVATE Observer { - public: - virtual ~Observer() = default; - - // Called when inserted_entry_count() reaches the threshold the Observer was - // registered with. After this call the Observer automatically gets - // deregistered. - virtual void OnInsertCountReachedThreshold() = 0; - - // Called when QpackHeaderTable is destroyed to let the Observer know that - // it must not call UnregisterObserver(). - virtual void Cancel() = 0; - }; - - QpackHeaderTable(); - QpackHeaderTable(const QpackHeaderTable&) = delete; - QpackHeaderTable& operator=(const QpackHeaderTable&) = delete; - - ~QpackHeaderTable(); - - // Returns the entry at absolute index |index| from the static or dynamic - // table according to |is_static|. |index| is zero based for both the static - // and the dynamic table. The returned pointer is valid until the entry is - // evicted, even if other entries are inserted into the dynamic table. - // Returns nullptr if entry does not exist. - const QpackEntry* LookupEntry(bool is_static, uint64_t index) const; - - // Returns the absolute index of an entry with matching name and value if such - // exists, otherwise one with matching name is such exists. |index| is zero - // based for both the static and the dynamic table. - MatchType FindHeaderField(absl::string_view name, - absl::string_view value, - bool* is_static, - uint64_t* index) const; + virtual ~QpackHeaderTableBase() = default; // Returns whether an entry with |name| and |value| has a size (including // overhead) that is smaller than or equal to the capacity of the dynamic @@ -89,13 +55,7 @@ class QUIC_EXPORT_PRIVATE QpackHeaderTable { // the underlying container might move entries around when resizing for // insertion. // Returns the absolute index of the inserted dynamic table entry. - uint64_t InsertEntry(absl::string_view name, absl::string_view 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; + virtual uint64_t InsertEntry(absl::string_view name, absl::string_view value); // Change dynamic table capacity to |capacity|. Returns true on success. // Returns false is |capacity| exceeds maximum dynamic table capacity. @@ -112,24 +72,11 @@ class QUIC_EXPORT_PRIVATE QpackHeaderTable { // returning false. bool SetMaximumDynamicTableCapacity(uint64_t maximum_dynamic_table_capacity); - // Get |maximum_dynamic_table_capacity_|. + uint64_t dynamic_table_size() const { return dynamic_table_size_; } + uint64_t dynamic_table_capacity() const { return dynamic_table_capacity_; } uint64_t maximum_dynamic_table_capacity() const { return maximum_dynamic_table_capacity_; } - - // Register an observer to be notified when inserted_entry_count() reaches - // |required_insert_count|. After the notification, |observer| automatically - // gets unregistered. Each observer must only be registered at most once. - void RegisterObserver(uint64_t required_insert_count, Observer* observer); - - // Unregister previously registered observer. Must be called with the same - // |required_insert_count| value that |observer| was registered with. Must be - // called before an observer still waiting for notification is destroyed, - // unless QpackHeaderTable already called Observer::Cancel(), in which case - // this method must not be called. - void UnregisterObserver(uint64_t required_insert_count, Observer* observer); - - // Used on request streams to encode and decode Required Insert Count. uint64_t max_entries() const { return max_entries_; } // The number of entries inserted to the dynamic table (including ones that @@ -141,14 +88,6 @@ 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; - void set_dynamic_table_entry_referenced() { dynamic_table_entry_referenced_ = true; } @@ -156,20 +95,178 @@ class QUIC_EXPORT_PRIVATE QpackHeaderTable { return dynamic_table_entry_referenced_; } - private: - friend class test::QpackHeaderTablePeer; + protected: + // Removes a single entry from the end of the dynamic table, updates + // |dynamic_table_size_| and |dropped_entry_count_|. + virtual void RemoveEntryFromEnd(); + const DynamicEntryTable& dynamic_entries() const { return dynamic_entries_; } + + private: // Evict entries from the dynamic table until table size is less than or equal // to |capacity|. void EvictDownToCapacity(uint64_t capacity); - // Static Table + // Dynamic Table entries. + DynamicEntryTable dynamic_entries_; - // |static_entries_|, |static_index_|, |static_name_index_| are owned by - // QpackStaticTable singleton. + // Size of the dynamic table. This is the sum of the size of its entries. + uint64_t dynamic_table_size_; - // Tracks QpackEntries by index. - const StaticEntryTable& static_entries_; + // Dynamic Table Capacity is the maximum allowed value of + // |dynamic_table_size_|. Entries are evicted if necessary before inserting a + // new entry to ensure that dynamic table size never exceeds capacity. + // Initial value is |maximum_dynamic_table_capacity_|. Capacity can be + // changed by the encoder, as long as it does not exceed + // |maximum_dynamic_table_capacity_|. + uint64_t dynamic_table_capacity_; + + // Maximum allowed value of |dynamic_table_capacity|. The initial value is + // zero. Can be changed by SetMaximumDynamicTableCapacity(). + uint64_t maximum_dynamic_table_capacity_; + + // MaxEntries, see Section 3.2.2. Calculated based on + // |maximum_dynamic_table_capacity_|. Used on request streams to encode and + // decode Required Insert Count. + uint64_t max_entries_; + + // The number of entries dropped from the dynamic table. + uint64_t dropped_entry_count_; + + // True if any dynamic table entries have been referenced from a header block. + // Set directly by the encoder or decoder. Used for stats. + bool dynamic_table_entry_referenced_; +}; + +template <typename DynamicEntryTable> +QpackHeaderTableBase<DynamicEntryTable>::QpackHeaderTableBase() + : dynamic_table_size_(0), + dynamic_table_capacity_(0), + maximum_dynamic_table_capacity_(0), + max_entries_(0), + dropped_entry_count_(0), + dynamic_table_entry_referenced_(false) {} + +template <typename DynamicEntryTable> +bool QpackHeaderTableBase<DynamicEntryTable>::EntryFitsDynamicTableCapacity( + absl::string_view name, + absl::string_view value) const { + return QpackEntry::Size(name, value) <= dynamic_table_capacity_; +} + +template <typename DynamicEntryTable> +uint64_t QpackHeaderTableBase<DynamicEntryTable>::InsertEntry( + absl::string_view name, + absl::string_view value) { + QUICHE_DCHECK(EntryFitsDynamicTableCapacity(name, value)); + + const uint64_t index = dropped_entry_count_ + dynamic_entries_.size(); + + // Copy name and value before modifying the container, because evicting + // entries or even inserting a new one might invalidate |name| or |value| if + // they point to an entry. + QpackEntry new_entry((std::string(name)), (std::string(value))); + const size_t entry_size = new_entry.Size(); + + EvictDownToCapacity(dynamic_table_capacity_ - entry_size); + + dynamic_table_size_ += entry_size; + dynamic_entries_.push_back(std::move(new_entry)); + + return index; +} + +template <typename DynamicEntryTable> +bool QpackHeaderTableBase<DynamicEntryTable>::SetDynamicTableCapacity( + uint64_t capacity) { + if (capacity > maximum_dynamic_table_capacity_) { + return false; + } + + dynamic_table_capacity_ = capacity; + EvictDownToCapacity(capacity); + + QUICHE_DCHECK_LE(dynamic_table_size_, dynamic_table_capacity_); + + return true; +} + +template <typename DynamicEntryTable> +bool QpackHeaderTableBase<DynamicEntryTable>::SetMaximumDynamicTableCapacity( + uint64_t maximum_dynamic_table_capacity) { + if (maximum_dynamic_table_capacity_ == 0) { + maximum_dynamic_table_capacity_ = maximum_dynamic_table_capacity; + max_entries_ = maximum_dynamic_table_capacity / 32; + return true; + } + // If the value is already set, it should not be changed. + return maximum_dynamic_table_capacity == maximum_dynamic_table_capacity_; +} + +template <typename DynamicEntryTable> +void QpackHeaderTableBase<DynamicEntryTable>::RemoveEntryFromEnd() { + const uint64_t entry_size = dynamic_entries_.front().Size(); + QUICHE_DCHECK_GE(dynamic_table_size_, entry_size); + dynamic_table_size_ -= entry_size; + + dynamic_entries_.pop_front(); + ++dropped_entry_count_; +} + +template <typename DynamicEntryTable> +void QpackHeaderTableBase<DynamicEntryTable>::EvictDownToCapacity( + uint64_t capacity) { + while (dynamic_table_size_ > capacity) { + QUICHE_DCHECK(!dynamic_entries_.empty()); + RemoveEntryFromEnd(); + } +} + +class QUIC_EXPORT_PRIVATE QpackEncoderHeaderTable + : public QpackHeaderTableBase<QpackEncoderDynamicTable> { + public: + // Result of header table lookup. + enum class MatchType { kNameAndValue, kName, kNoMatch }; + + QpackEncoderHeaderTable(); + ~QpackEncoderHeaderTable() override = default; + + uint64_t InsertEntry(absl::string_view name, + absl::string_view value) override; + + // Returns the absolute index of an entry with matching name and value if such + // exists, otherwise one with matching name is such exists. |index| is zero + // based for both the static and the dynamic table. + MatchType FindHeaderField(absl::string_view name, + absl::string_view value, + bool* is_static, + uint64_t* index) const; + + // 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; + + // 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; + + protected: + void RemoveEntryFromEnd() override; + + private: + using NameValueToEntryMap = spdy::HpackHeaderTable::NameValueToEntryMap; + using NameToEntryMap = spdy::HpackHeaderTable::NameToEntryMap; + + // Static Table + + // |static_index_| and |static_name_index_| are owned by QpackStaticTable + // singleton. // Tracks the unique static entry for a given header name and value. const NameValueToEntryMap& static_index_; @@ -179,49 +276,69 @@ class QUIC_EXPORT_PRIVATE QpackHeaderTable { // Dynamic Table - // Queue of dynamic table entries, for lookup by index. - // |dynamic_entries_| owns the entries in the dynamic table. - DynamicEntryTable dynamic_entries_; - // An unordered set of QpackEntry pointers with a comparison operator that // only cares about name and value. This allows fast lookup of the most // recently inserted dynamic entry for a given header name and value pair. - // Entries point to entries owned by |dynamic_entries_|. + // Entries point to entries owned by |QpackHeaderTableBase::dynamic_entries_|. NameValueToEntryMap dynamic_index_; // An unordered map of QpackEntry pointers keyed off header name. This allows // fast lookup of the most recently inserted dynamic entry for a given header - // name. Entries point to entries owned by |dynamic_entries_|. + // name. Entries point to entries owned by + // |QpackHeaderTableBase::dynamic_entries_|. NameToEntryMap dynamic_name_index_; +}; - // Size of the dynamic table. This is the sum of the size of its entries. - uint64_t dynamic_table_size_; +class QUIC_EXPORT_PRIVATE QpackDecoderHeaderTable + : public QpackHeaderTableBase<QpackDecoderDynamicTable> { + public: + // Observer interface for dynamic table insertion. + class QUIC_EXPORT_PRIVATE Observer { + public: + virtual ~Observer() = default; - // Dynamic Table Capacity is the maximum allowed value of - // |dynamic_table_size_|. Entries are evicted if necessary before inserting a - // new entry to ensure that dynamic table size never exceeds capacity. - // Initial value is |maximum_dynamic_table_capacity_|. Capacity can be - // changed by the encoder, as long as it does not exceed - // |maximum_dynamic_table_capacity_|. - uint64_t dynamic_table_capacity_; + // Called when inserted_entry_count() reaches the threshold the Observer was + // registered with. After this call the Observer automatically gets + // deregistered. + virtual void OnInsertCountReachedThreshold() = 0; - // Maximum allowed value of |dynamic_table_capacity|. The initial value is - // zero. Can be changed by SetMaximumDynamicTableCapacity(). - uint64_t maximum_dynamic_table_capacity_; + // Called when QpackDecoderHeaderTable is destroyed to let the Observer know + // that it must not call UnregisterObserver(). + virtual void Cancel() = 0; + }; - // MaxEntries, see Section 3.2.2. Calculated based on - // |maximum_dynamic_table_capacity_|. - uint64_t max_entries_; + QpackDecoderHeaderTable(); + ~QpackDecoderHeaderTable() override; - // The number of entries dropped from the dynamic table. - uint64_t dropped_entry_count_; + uint64_t InsertEntry(absl::string_view name, + absl::string_view value) override; + + // Returns the entry at absolute index |index| from the static or dynamic + // table according to |is_static|. |index| is zero based for both the static + // and the dynamic table. The returned pointer is valid until the entry is + // evicted, even if other entries are inserted into the dynamic table. + // Returns nullptr if entry does not exist. + const QpackEntry* LookupEntry(bool is_static, uint64_t index) const; + + // Register an observer to be notified when inserted_entry_count() reaches + // |required_insert_count|. After the notification, |observer| automatically + // gets unregistered. Each observer must only be registered at most once. + void RegisterObserver(uint64_t required_insert_count, Observer* observer); + + // Unregister previously registered observer. Must be called with the same + // |required_insert_count| value that |observer| was registered with. Must be + // called before an observer still waiting for notification is destroyed, + // unless QpackDecoderHeaderTable already called Observer::Cancel(), in which + // case this method must not be called. + void UnregisterObserver(uint64_t required_insert_count, Observer* observer); + + private: + // Static Table entries. Owned by QpackStaticTable singleton. + using StaticEntryTable = spdy::HpackHeaderTable::StaticEntryTable; + const StaticEntryTable& static_entries_; // Observers waiting to be notified, sorted by required insert count. std::multimap<uint64_t, Observer*> observers_; - - // True if any dynamic table entries have been referenced from a header block. - // Set directly by the encoder or decoder. Used for stats. - bool dynamic_table_entry_referenced_; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table_test.cc index 0af250efd32..4a1e39c2325 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 @@ -21,64 +21,16 @@ namespace { const uint64_t kMaximumDynamicTableCapacityForTesting = 1024 * 1024; -class MockObserver : public QpackHeaderTable::Observer { - public: - ~MockObserver() override = default; - - MOCK_METHOD(void, OnInsertCountReachedThreshold, (), (override)); - MOCK_METHOD(void, Cancel, (), (override)); -}; - +template <typename T> class QpackHeaderTableTest : public QuicTest { protected: - QpackHeaderTableTest() { - table_.SetMaximumDynamicTableCapacity( - kMaximumDynamicTableCapacityForTesting); - table_.SetDynamicTableCapacity(kMaximumDynamicTableCapacityForTesting); - } ~QpackHeaderTableTest() override = default; - void ExpectEntryAtIndex(bool is_static, - uint64_t index, - absl::string_view expected_name, - absl::string_view expected_value) const { - const auto* entry = table_.LookupEntry(is_static, index); - ASSERT_TRUE(entry); - EXPECT_EQ(expected_name, entry->name()); - EXPECT_EQ(expected_value, entry->value()); - } - - void ExpectNoEntryAtIndex(bool is_static, uint64_t index) const { - EXPECT_FALSE(table_.LookupEntry(is_static, index)); - } - - void ExpectMatch(absl::string_view name, - absl::string_view value, - QpackHeaderTable::MatchType expected_match_type, - bool expected_is_static, - uint64_t expected_index) const { - // Initialize outparams to a value different from the expected to ensure - // that FindHeaderField() sets them. - bool is_static = !expected_is_static; - uint64_t index = expected_index + 1; - - QpackHeaderTable::MatchType matchtype = - table_.FindHeaderField(name, value, &is_static, &index); - - EXPECT_EQ(expected_match_type, matchtype) << name << ": " << value; - EXPECT_EQ(expected_is_static, is_static) << name << ": " << value; - EXPECT_EQ(expected_index, index) << name << ": " << value; - } - - void ExpectNoMatch(absl::string_view name, absl::string_view value) const { - bool is_static = false; - uint64_t index = 0; - - QpackHeaderTable::MatchType matchtype = - table_.FindHeaderField(name, value, &is_static, &index); - - EXPECT_EQ(QpackHeaderTable::MatchType::kNoMatch, matchtype) - << name << ": " << value; + void SetUp() override { + ASSERT_TRUE(table_.SetMaximumDynamicTableCapacity( + kMaximumDynamicTableCapacityForTesting)); + ASSERT_TRUE( + table_.SetDynamicTableCapacity(kMaximumDynamicTableCapacityForTesting)); } bool EntryFitsDynamicTableCapacity(absl::string_view name, @@ -94,110 +46,129 @@ class QpackHeaderTableTest : public QuicTest { return table_.SetDynamicTableCapacity(capacity); } - void RegisterObserver(uint64_t required_insert_count, - QpackHeaderTable::Observer* observer) { - table_.RegisterObserver(required_insert_count, observer); - } - - void UnregisterObserver(uint64_t required_insert_count, - QpackHeaderTable::Observer* observer) { - table_.UnregisterObserver(required_insert_count, observer); - } - uint64_t max_entries() const { return table_.max_entries(); } uint64_t inserted_entry_count() const { return table_.inserted_entry_count(); } uint64_t dropped_entry_count() const { return table_.dropped_entry_count(); } - private: - QpackHeaderTable table_; + T table_; }; -TEST_F(QpackHeaderTableTest, LookupStaticEntry) { - ExpectEntryAtIndex(/* is_static = */ true, 0, ":authority", ""); +using MyTypes = + ::testing::Types<QpackEncoderHeaderTable, QpackDecoderHeaderTable>; +TYPED_TEST_SUITE(QpackHeaderTableTest, MyTypes); - ExpectEntryAtIndex(/* is_static = */ true, 1, ":path", "/"); - - // 98 is the last entry. - ExpectEntryAtIndex(/* is_static = */ true, 98, "x-frame-options", - "sameorigin"); +// MaxEntries is determined by maximum dynamic table capacity, +// which is set at construction time. +TYPED_TEST(QpackHeaderTableTest, MaxEntries) { + TypeParam table1; + table1.SetMaximumDynamicTableCapacity(1024); + EXPECT_EQ(32u, table1.max_entries()); - ASSERT_EQ(99u, QpackStaticTableVector().size()); - ExpectNoEntryAtIndex(/* is_static = */ true, 99); + TypeParam table2; + table2.SetMaximumDynamicTableCapacity(500); + EXPECT_EQ(15u, table2.max_entries()); } -TEST_F(QpackHeaderTableTest, InsertAndLookupDynamicEntry) { - // Dynamic table is initially entry. - ExpectNoEntryAtIndex(/* is_static = */ false, 0); - ExpectNoEntryAtIndex(/* is_static = */ false, 1); - ExpectNoEntryAtIndex(/* is_static = */ false, 2); - ExpectNoEntryAtIndex(/* is_static = */ false, 3); +TYPED_TEST(QpackHeaderTableTest, SetDynamicTableCapacity) { + // Dynamic table capacity does not affect MaxEntries. + EXPECT_TRUE(this->SetDynamicTableCapacity(1024)); + EXPECT_EQ(32u * 1024, this->max_entries()); - // Insert one entry. - InsertEntry("foo", "bar"); + EXPECT_TRUE(this->SetDynamicTableCapacity(500)); + EXPECT_EQ(32u * 1024, this->max_entries()); - ExpectEntryAtIndex(/* is_static = */ false, 0, "foo", "bar"); + // Dynamic table capacity cannot exceed maximum dynamic table capacity. + EXPECT_FALSE(this->SetDynamicTableCapacity( + 2 * kMaximumDynamicTableCapacityForTesting)); +} - ExpectNoEntryAtIndex(/* is_static = */ false, 1); - ExpectNoEntryAtIndex(/* is_static = */ false, 2); - ExpectNoEntryAtIndex(/* is_static = */ false, 3); +TYPED_TEST(QpackHeaderTableTest, EntryFitsDynamicTableCapacity) { + EXPECT_TRUE(this->SetDynamicTableCapacity(39)); - // Insert a different entry. - InsertEntry("baz", "bing"); + EXPECT_TRUE(this->EntryFitsDynamicTableCapacity("foo", "bar")); + EXPECT_TRUE(this->EntryFitsDynamicTableCapacity("foo", "bar2")); + EXPECT_FALSE(this->EntryFitsDynamicTableCapacity("foo", "bar12")); +} - ExpectEntryAtIndex(/* is_static = */ false, 0, "foo", "bar"); +class QpackEncoderHeaderTableTest + : public QpackHeaderTableTest<QpackEncoderHeaderTable> { + protected: + ~QpackEncoderHeaderTableTest() override = default; - ExpectEntryAtIndex(/* is_static = */ false, 1, "baz", "bing"); + void ExpectMatch(absl::string_view name, + absl::string_view value, + QpackEncoderHeaderTable::MatchType expected_match_type, + bool expected_is_static, + uint64_t expected_index) const { + // Initialize outparams to a value different from the expected to ensure + // that FindHeaderField() sets them. + bool is_static = !expected_is_static; + uint64_t index = expected_index + 1; - ExpectNoEntryAtIndex(/* is_static = */ false, 2); - ExpectNoEntryAtIndex(/* is_static = */ false, 3); + QpackEncoderHeaderTable::MatchType matchtype = + table_.FindHeaderField(name, value, &is_static, &index); - // Insert an entry identical to the most recently inserted one. - InsertEntry("baz", "bing"); + EXPECT_EQ(expected_match_type, matchtype) << name << ": " << value; + EXPECT_EQ(expected_is_static, is_static) << name << ": " << value; + EXPECT_EQ(expected_index, index) << name << ": " << value; + } - ExpectEntryAtIndex(/* is_static = */ false, 0, "foo", "bar"); + void ExpectNoMatch(absl::string_view name, absl::string_view value) const { + bool is_static = false; + uint64_t index = 0; - ExpectEntryAtIndex(/* is_static = */ false, 1, "baz", "bing"); + QpackEncoderHeaderTable::MatchType matchtype = + table_.FindHeaderField(name, value, &is_static, &index); - ExpectEntryAtIndex(/* is_static = */ false, 2, "baz", "bing"); + EXPECT_EQ(QpackEncoderHeaderTable::MatchType::kNoMatch, matchtype) + << name << ": " << value; + } - ExpectNoEntryAtIndex(/* is_static = */ false, 3); -} + uint64_t MaxInsertSizeWithoutEvictingGivenEntry(uint64_t index) const { + return table_.MaxInsertSizeWithoutEvictingGivenEntry(index); + } -TEST_F(QpackHeaderTableTest, FindStaticHeaderField) { + uint64_t draining_index(float draining_fraction) const { + return table_.draining_index(draining_fraction); + } +}; + +TEST_F(QpackEncoderHeaderTableTest, FindStaticHeaderField) { // A header name that has multiple entries with different values. - ExpectMatch(":method", "GET", QpackHeaderTable::MatchType::kNameAndValue, - true, 17u); + ExpectMatch(":method", "GET", + QpackEncoderHeaderTable::MatchType::kNameAndValue, true, 17u); - ExpectMatch(":method", "POST", QpackHeaderTable::MatchType::kNameAndValue, - true, 20u); + ExpectMatch(":method", "POST", + QpackEncoderHeaderTable::MatchType::kNameAndValue, true, 20u); - ExpectMatch(":method", "TRACE", QpackHeaderTable::MatchType::kName, true, - 15u); + ExpectMatch(":method", "TRACE", QpackEncoderHeaderTable::MatchType::kName, + true, 15u); // A header name that has a single entry with non-empty value. ExpectMatch("accept-encoding", "gzip, deflate, br", - QpackHeaderTable::MatchType::kNameAndValue, true, 31u); + QpackEncoderHeaderTable::MatchType::kNameAndValue, true, 31u); - ExpectMatch("accept-encoding", "compress", QpackHeaderTable::MatchType::kName, - true, 31u); + ExpectMatch("accept-encoding", "compress", + QpackEncoderHeaderTable::MatchType::kName, true, 31u); - ExpectMatch("accept-encoding", "", QpackHeaderTable::MatchType::kName, true, - 31u); + ExpectMatch("accept-encoding", "", QpackEncoderHeaderTable::MatchType::kName, + true, 31u); // A header name that has a single entry with empty value. - ExpectMatch("location", "", QpackHeaderTable::MatchType::kNameAndValue, true, - 12u); + ExpectMatch("location", "", QpackEncoderHeaderTable::MatchType::kNameAndValue, + true, 12u); - ExpectMatch("location", "foo", QpackHeaderTable::MatchType::kName, true, 12u); + ExpectMatch("location", "foo", QpackEncoderHeaderTable::MatchType::kName, + true, 12u); // No matching header name. ExpectNoMatch("foo", ""); ExpectNoMatch("foo", "bar"); } -TEST_F(QpackHeaderTableTest, FindDynamicHeaderField) { +TEST_F(QpackEncoderHeaderTableTest, FindDynamicHeaderField) { // Dynamic table is initially entry. ExpectNoMatch("foo", "bar"); ExpectNoMatch("foo", "baz"); @@ -206,75 +177,49 @@ TEST_F(QpackHeaderTableTest, FindDynamicHeaderField) { InsertEntry("foo", "bar"); // Match name and value. - ExpectMatch("foo", "bar", QpackHeaderTable::MatchType::kNameAndValue, false, - 0u); + ExpectMatch("foo", "bar", QpackEncoderHeaderTable::MatchType::kNameAndValue, + false, 0u); // Match name only. - ExpectMatch("foo", "baz", QpackHeaderTable::MatchType::kName, false, 0u); + ExpectMatch("foo", "baz", QpackEncoderHeaderTable::MatchType::kName, false, + 0u); // Insert an identical entry. FindHeaderField() should return the index of // the most recently inserted matching entry. InsertEntry("foo", "bar"); // Match name and value. - ExpectMatch("foo", "bar", QpackHeaderTable::MatchType::kNameAndValue, false, - 1u); + ExpectMatch("foo", "bar", QpackEncoderHeaderTable::MatchType::kNameAndValue, + false, 1u); // Match name only. - ExpectMatch("foo", "baz", QpackHeaderTable::MatchType::kName, false, 1u); + ExpectMatch("foo", "baz", QpackEncoderHeaderTable::MatchType::kName, false, + 1u); } -TEST_F(QpackHeaderTableTest, FindHeaderFieldPrefersStaticTable) { +TEST_F(QpackEncoderHeaderTableTest, FindHeaderFieldPrefersStaticTable) { // Insert an entry to the dynamic table that exists in the static table. InsertEntry(":method", "GET"); - // Insertion works. - ExpectEntryAtIndex(/* is_static = */ false, 0, ":method", "GET"); - // FindHeaderField() prefers static table if both have name-and-value match. - ExpectMatch(":method", "GET", QpackHeaderTable::MatchType::kNameAndValue, - true, 17u); + ExpectMatch(":method", "GET", + QpackEncoderHeaderTable::MatchType::kNameAndValue, true, 17u); // FindHeaderField() prefers static table if both have name match but no value // match, and prefers the first entry with matching name. - ExpectMatch(":method", "TRACE", QpackHeaderTable::MatchType::kName, true, - 15u); + ExpectMatch(":method", "TRACE", QpackEncoderHeaderTable::MatchType::kName, + true, 15u); // Add new entry to the dynamic table. InsertEntry(":method", "TRACE"); // FindHeaderField prefers name-and-value match in dynamic table over name // only match in static table. - ExpectMatch(":method", "TRACE", QpackHeaderTable::MatchType::kNameAndValue, - false, 1u); + ExpectMatch(":method", "TRACE", + QpackEncoderHeaderTable::MatchType::kNameAndValue, false, 1u); } -// MaxEntries is determined by maximum dynamic table capacity, -// which is set at construction time. -TEST_F(QpackHeaderTableTest, MaxEntries) { - QpackHeaderTable table1; - table1.SetMaximumDynamicTableCapacity(1024); - EXPECT_EQ(32u, table1.max_entries()); - - QpackHeaderTable table2; - table2.SetMaximumDynamicTableCapacity(500); - EXPECT_EQ(15u, table2.max_entries()); -} - -TEST_F(QpackHeaderTableTest, SetDynamicTableCapacity) { - // Dynamic table capacity does not affect MaxEntries. - EXPECT_TRUE(SetDynamicTableCapacity(1024)); - EXPECT_EQ(32u * 1024, max_entries()); - - EXPECT_TRUE(SetDynamicTableCapacity(500)); - EXPECT_EQ(32u * 1024, max_entries()); - - // Dynamic table capacity cannot exceed maximum dynamic table capacity. - EXPECT_FALSE( - SetDynamicTableCapacity(2 * kMaximumDynamicTableCapacityForTesting)); -} - -TEST_F(QpackHeaderTableTest, EvictByInsertion) { +TEST_F(QpackEncoderHeaderTableTest, EvictByInsertion) { EXPECT_TRUE(SetDynamicTableCapacity(40)); // Entry size is 3 + 3 + 32 = 38. @@ -282,7 +227,7 @@ TEST_F(QpackHeaderTableTest, EvictByInsertion) { EXPECT_EQ(1u, inserted_entry_count()); EXPECT_EQ(0u, dropped_entry_count()); - ExpectMatch("foo", "bar", QpackHeaderTable::MatchType::kNameAndValue, + ExpectMatch("foo", "bar", QpackEncoderHeaderTable::MatchType::kNameAndValue, /* expected_is_static = */ false, 0u); // Inserting second entry evicts the first one. @@ -291,20 +236,20 @@ TEST_F(QpackHeaderTableTest, EvictByInsertion) { EXPECT_EQ(1u, dropped_entry_count()); ExpectNoMatch("foo", "bar"); - ExpectMatch("baz", "qux", QpackHeaderTable::MatchType::kNameAndValue, + ExpectMatch("baz", "qux", QpackEncoderHeaderTable::MatchType::kNameAndValue, /* expected_is_static = */ false, 1u); } -TEST_F(QpackHeaderTableTest, EvictByUpdateTableSize) { +TEST_F(QpackEncoderHeaderTableTest, EvictByUpdateTableSize) { // Entry size is 3 + 3 + 32 = 38. InsertEntry("foo", "bar"); InsertEntry("baz", "qux"); EXPECT_EQ(2u, inserted_entry_count()); EXPECT_EQ(0u, dropped_entry_count()); - ExpectMatch("foo", "bar", QpackHeaderTable::MatchType::kNameAndValue, + ExpectMatch("foo", "bar", QpackEncoderHeaderTable::MatchType::kNameAndValue, /* expected_is_static = */ false, 0u); - ExpectMatch("baz", "qux", QpackHeaderTable::MatchType::kNameAndValue, + ExpectMatch("baz", "qux", QpackEncoderHeaderTable::MatchType::kNameAndValue, /* expected_is_static = */ false, 1u); EXPECT_TRUE(SetDynamicTableCapacity(40)); @@ -312,7 +257,7 @@ TEST_F(QpackHeaderTableTest, EvictByUpdateTableSize) { EXPECT_EQ(1u, dropped_entry_count()); ExpectNoMatch("foo", "bar"); - ExpectMatch("baz", "qux", QpackHeaderTable::MatchType::kNameAndValue, + ExpectMatch("baz", "qux", QpackEncoderHeaderTable::MatchType::kNameAndValue, /* expected_is_static = */ false, 1u); EXPECT_TRUE(SetDynamicTableCapacity(20)); @@ -323,7 +268,7 @@ TEST_F(QpackHeaderTableTest, EvictByUpdateTableSize) { ExpectNoMatch("baz", "qux"); } -TEST_F(QpackHeaderTableTest, EvictOldestOfIdentical) { +TEST_F(QpackEncoderHeaderTableTest, EvictOldestOfIdentical) { EXPECT_TRUE(SetDynamicTableCapacity(80)); // Entry size is 3 + 3 + 32 = 38. @@ -334,7 +279,7 @@ TEST_F(QpackHeaderTableTest, EvictOldestOfIdentical) { EXPECT_EQ(0u, dropped_entry_count()); // Find most recently inserted entry. - ExpectMatch("foo", "bar", QpackHeaderTable::MatchType::kNameAndValue, + ExpectMatch("foo", "bar", QpackEncoderHeaderTable::MatchType::kNameAndValue, /* expected_is_static = */ false, 1u); // Inserting third entry evicts the first one, not the second. @@ -342,13 +287,13 @@ TEST_F(QpackHeaderTableTest, EvictOldestOfIdentical) { EXPECT_EQ(3u, inserted_entry_count()); EXPECT_EQ(1u, dropped_entry_count()); - ExpectMatch("foo", "bar", QpackHeaderTable::MatchType::kNameAndValue, + ExpectMatch("foo", "bar", QpackEncoderHeaderTable::MatchType::kNameAndValue, /* expected_is_static = */ false, 1u); - ExpectMatch("baz", "qux", QpackHeaderTable::MatchType::kNameAndValue, + ExpectMatch("baz", "qux", QpackEncoderHeaderTable::MatchType::kNameAndValue, /* expected_is_static = */ false, 2u); } -TEST_F(QpackHeaderTableTest, EvictOldestOfSameName) { +TEST_F(QpackEncoderHeaderTableTest, EvictOldestOfSameName) { EXPECT_TRUE(SetDynamicTableCapacity(80)); // Entry size is 3 + 3 + 32 = 38. @@ -359,7 +304,7 @@ TEST_F(QpackHeaderTableTest, EvictOldestOfSameName) { EXPECT_EQ(0u, dropped_entry_count()); // Find most recently inserted entry with matching name. - ExpectMatch("foo", "foo", QpackHeaderTable::MatchType::kName, + ExpectMatch("foo", "foo", QpackEncoderHeaderTable::MatchType::kName, /* expected_is_static = */ false, 1u); // Inserting third entry evicts the first one, not the second. @@ -367,63 +312,276 @@ TEST_F(QpackHeaderTableTest, EvictOldestOfSameName) { EXPECT_EQ(3u, inserted_entry_count()); EXPECT_EQ(1u, dropped_entry_count()); - ExpectMatch("foo", "foo", QpackHeaderTable::MatchType::kName, + ExpectMatch("foo", "foo", QpackEncoderHeaderTable::MatchType::kName, /* expected_is_static = */ false, 1u); - ExpectMatch("baz", "qux", QpackHeaderTable::MatchType::kNameAndValue, + ExpectMatch("baz", "qux", QpackEncoderHeaderTable::MatchType::kNameAndValue, /* 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) { +TEST_F(QpackEncoderHeaderTableTest, MaxInsertSizeWithoutEvictingGivenEntry) { const uint64_t dynamic_table_capacity = 100; - QpackHeaderTable table; - table.SetMaximumDynamicTableCapacity(dynamic_table_capacity); - EXPECT_TRUE(table.SetDynamicTableCapacity(dynamic_table_capacity)); + EXPECT_TRUE(SetDynamicTableCapacity(dynamic_table_capacity)); // Empty table can take an entry up to its capacity. - EXPECT_EQ(dynamic_table_capacity, - table.MaxInsertSizeWithoutEvictingGivenEntry(0)); + EXPECT_EQ(dynamic_table_capacity, MaxInsertSizeWithoutEvictingGivenEntry(0)); const uint64_t entry_size1 = QpackEntry::Size("foo", "bar"); - table.InsertEntry("foo", "bar"); + InsertEntry("foo", "bar"); EXPECT_EQ(dynamic_table_capacity - entry_size1, - table.MaxInsertSizeWithoutEvictingGivenEntry(0)); + 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)); + EXPECT_EQ(dynamic_table_capacity, MaxInsertSizeWithoutEvictingGivenEntry(1)); const uint64_t entry_size2 = QpackEntry::Size("baz", "foobar"); - table.InsertEntry("baz", "foobar"); + 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)); + EXPECT_EQ(dynamic_table_capacity, MaxInsertSizeWithoutEvictingGivenEntry(2)); // Second entry must stay. EXPECT_EQ(dynamic_table_capacity - entry_size2, - table.MaxInsertSizeWithoutEvictingGivenEntry(1)); + MaxInsertSizeWithoutEvictingGivenEntry(1)); // First and second entry must stay. EXPECT_EQ(dynamic_table_capacity - entry_size2 - entry_size1, - table.MaxInsertSizeWithoutEvictingGivenEntry(0)); + MaxInsertSizeWithoutEvictingGivenEntry(0)); // Third entry evicts first one. const uint64_t entry_size3 = QpackEntry::Size("last", "entry"); - table.InsertEntry("last", "entry"); - EXPECT_EQ(1u, table.dropped_entry_count()); + InsertEntry("last", "entry"); + EXPECT_EQ(1u, 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)); + EXPECT_EQ(dynamic_table_capacity, MaxInsertSizeWithoutEvictingGivenEntry(3)); // Third entry must stay. EXPECT_EQ(dynamic_table_capacity - entry_size3, - table.MaxInsertSizeWithoutEvictingGivenEntry(2)); + MaxInsertSizeWithoutEvictingGivenEntry(2)); // Second and third entry must stay. EXPECT_EQ(dynamic_table_capacity - entry_size3 - entry_size2, - table.MaxInsertSizeWithoutEvictingGivenEntry(1)); + MaxInsertSizeWithoutEvictingGivenEntry(1)); +} + +TEST_F(QpackEncoderHeaderTableTest, DrainingIndex) { + EXPECT_TRUE(SetDynamicTableCapacity(4 * QpackEntry::Size("foo", "bar"))); + + // Empty table: no draining entry. + EXPECT_EQ(0u, draining_index(0.0)); + EXPECT_EQ(0u, draining_index(1.0)); + + // Table with one entry. + InsertEntry("foo", "bar"); + // Any entry can be referenced if none of the table is draining. + EXPECT_EQ(0u, draining_index(0.0)); + // No entry can be referenced if all of the table is draining. + EXPECT_EQ(1u, draining_index(1.0)); + + // Table with two entries is at half capacity. + 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, draining_index(0.0)); + EXPECT_EQ(0u, draining_index(0.5)); + // No entry can be referenced if all of the table is draining. + EXPECT_EQ(2u, draining_index(1.0)); + + // Table with four entries is full. + InsertEntry("foo", "bar"); + InsertEntry("foo", "bar"); + // Any entry can be referenced if none of the table is draining. + EXPECT_EQ(0u, draining_index(0.0)); + // In a full table with identically sized entries, |draining_fraction| of all + // entries are draining. + EXPECT_EQ(2u, draining_index(0.5)); + // No entry can be referenced if all of the table is draining. + EXPECT_EQ(4u, draining_index(1.0)); } -TEST_F(QpackHeaderTableTest, RegisterObserver) { +class MockObserver : public QpackDecoderHeaderTable::Observer { + public: + ~MockObserver() override = default; + + MOCK_METHOD(void, OnInsertCountReachedThreshold, (), (override)); + MOCK_METHOD(void, Cancel, (), (override)); +}; + +class QpackDecoderHeaderTableTest + : public QpackHeaderTableTest<QpackDecoderHeaderTable> { + protected: + ~QpackDecoderHeaderTableTest() override = default; + + void ExpectEntryAtIndex(bool is_static, + uint64_t index, + absl::string_view expected_name, + absl::string_view expected_value) const { + const auto* entry = table_.LookupEntry(is_static, index); + ASSERT_TRUE(entry); + EXPECT_EQ(expected_name, entry->name()); + EXPECT_EQ(expected_value, entry->value()); + } + + void ExpectNoEntryAtIndex(bool is_static, uint64_t index) const { + EXPECT_FALSE(table_.LookupEntry(is_static, index)); + } + + void RegisterObserver(uint64_t required_insert_count, + QpackDecoderHeaderTable::Observer* observer) { + table_.RegisterObserver(required_insert_count, observer); + } + + void UnregisterObserver(uint64_t required_insert_count, + QpackDecoderHeaderTable::Observer* observer) { + table_.UnregisterObserver(required_insert_count, observer); + } +}; + +TEST_F(QpackDecoderHeaderTableTest, LookupStaticEntry) { + ExpectEntryAtIndex(/* is_static = */ true, 0, ":authority", ""); + + ExpectEntryAtIndex(/* is_static = */ true, 1, ":path", "/"); + + // 98 is the last entry. + ExpectEntryAtIndex(/* is_static = */ true, 98, "x-frame-options", + "sameorigin"); + + ASSERT_EQ(99u, QpackStaticTableVector().size()); + ExpectNoEntryAtIndex(/* is_static = */ true, 99); +} + +TEST_F(QpackDecoderHeaderTableTest, InsertAndLookupDynamicEntry) { + // Dynamic table is initially entry. + ExpectNoEntryAtIndex(/* is_static = */ false, 0); + ExpectNoEntryAtIndex(/* is_static = */ false, 1); + ExpectNoEntryAtIndex(/* is_static = */ false, 2); + ExpectNoEntryAtIndex(/* is_static = */ false, 3); + + // Insert one entry. + InsertEntry("foo", "bar"); + + ExpectEntryAtIndex(/* is_static = */ false, 0, "foo", "bar"); + + ExpectNoEntryAtIndex(/* is_static = */ false, 1); + ExpectNoEntryAtIndex(/* is_static = */ false, 2); + ExpectNoEntryAtIndex(/* is_static = */ false, 3); + + // Insert a different entry. + InsertEntry("baz", "bing"); + + ExpectEntryAtIndex(/* is_static = */ false, 0, "foo", "bar"); + + ExpectEntryAtIndex(/* is_static = */ false, 1, "baz", "bing"); + + ExpectNoEntryAtIndex(/* is_static = */ false, 2); + ExpectNoEntryAtIndex(/* is_static = */ false, 3); + + // Insert an entry identical to the most recently inserted one. + InsertEntry("baz", "bing"); + + ExpectEntryAtIndex(/* is_static = */ false, 0, "foo", "bar"); + + ExpectEntryAtIndex(/* is_static = */ false, 1, "baz", "bing"); + + ExpectEntryAtIndex(/* is_static = */ false, 2, "baz", "bing"); + + ExpectNoEntryAtIndex(/* is_static = */ false, 3); +} + +TEST_F(QpackDecoderHeaderTableTest, EvictByInsertion) { + EXPECT_TRUE(SetDynamicTableCapacity(40)); + + // Entry size is 3 + 3 + 32 = 38. + InsertEntry("foo", "bar"); + EXPECT_EQ(1u, inserted_entry_count()); + EXPECT_EQ(0u, dropped_entry_count()); + + ExpectEntryAtIndex(/* is_static = */ false, 0u, "foo", "bar"); + + // Inserting second entry evicts the first one. + InsertEntry("baz", "qux"); + EXPECT_EQ(2u, inserted_entry_count()); + EXPECT_EQ(1u, dropped_entry_count()); + + ExpectNoEntryAtIndex(/* is_static = */ false, 0u); + ExpectEntryAtIndex(/* is_static = */ false, 1u, "baz", "qux"); +} + +TEST_F(QpackDecoderHeaderTableTest, EvictByUpdateTableSize) { + ExpectNoEntryAtIndex(/* is_static = */ false, 0u); + ExpectNoEntryAtIndex(/* is_static = */ false, 1u); + + // Entry size is 3 + 3 + 32 = 38. + InsertEntry("foo", "bar"); + InsertEntry("baz", "qux"); + EXPECT_EQ(2u, inserted_entry_count()); + EXPECT_EQ(0u, dropped_entry_count()); + + ExpectEntryAtIndex(/* is_static = */ false, 0u, "foo", "bar"); + ExpectEntryAtIndex(/* is_static = */ false, 1u, "baz", "qux"); + + EXPECT_TRUE(SetDynamicTableCapacity(40)); + EXPECT_EQ(2u, inserted_entry_count()); + EXPECT_EQ(1u, dropped_entry_count()); + + ExpectNoEntryAtIndex(/* is_static = */ false, 0u); + ExpectEntryAtIndex(/* is_static = */ false, 1u, "baz", "qux"); + + EXPECT_TRUE(SetDynamicTableCapacity(20)); + EXPECT_EQ(2u, inserted_entry_count()); + EXPECT_EQ(2u, dropped_entry_count()); + + ExpectNoEntryAtIndex(/* is_static = */ false, 0u); + ExpectNoEntryAtIndex(/* is_static = */ false, 1u); +} + +TEST_F(QpackDecoderHeaderTableTest, EvictOldestOfIdentical) { + EXPECT_TRUE(SetDynamicTableCapacity(80)); + + // Entry size is 3 + 3 + 32 = 38. + // Insert same entry twice. + InsertEntry("foo", "bar"); + InsertEntry("foo", "bar"); + EXPECT_EQ(2u, inserted_entry_count()); + EXPECT_EQ(0u, dropped_entry_count()); + + ExpectEntryAtIndex(/* is_static = */ false, 0u, "foo", "bar"); + ExpectEntryAtIndex(/* is_static = */ false, 1u, "foo", "bar"); + ExpectNoEntryAtIndex(/* is_static = */ false, 2u); + + // Inserting third entry evicts the first one, not the second. + InsertEntry("baz", "qux"); + EXPECT_EQ(3u, inserted_entry_count()); + EXPECT_EQ(1u, dropped_entry_count()); + + ExpectNoEntryAtIndex(/* is_static = */ false, 0u); + ExpectEntryAtIndex(/* is_static = */ false, 1u, "foo", "bar"); + ExpectEntryAtIndex(/* is_static = */ false, 2u, "baz", "qux"); +} + +TEST_F(QpackDecoderHeaderTableTest, EvictOldestOfSameName) { + EXPECT_TRUE(SetDynamicTableCapacity(80)); + + // Entry size is 3 + 3 + 32 = 38. + // Insert two entries with same name but different values. + InsertEntry("foo", "bar"); + InsertEntry("foo", "baz"); + EXPECT_EQ(2u, inserted_entry_count()); + EXPECT_EQ(0u, dropped_entry_count()); + + ExpectEntryAtIndex(/* is_static = */ false, 0u, "foo", "bar"); + ExpectEntryAtIndex(/* is_static = */ false, 1u, "foo", "baz"); + ExpectNoEntryAtIndex(/* is_static = */ false, 2u); + + // Inserting third entry evicts the first one, not the second. + InsertEntry("baz", "qux"); + EXPECT_EQ(3u, inserted_entry_count()); + EXPECT_EQ(1u, dropped_entry_count()); + + ExpectNoEntryAtIndex(/* is_static = */ false, 0u); + ExpectEntryAtIndex(/* is_static = */ false, 1u, "foo", "baz"); + ExpectEntryAtIndex(/* is_static = */ false, 2u, "baz", "qux"); +} + +TEST_F(QpackDecoderHeaderTableTest, RegisterObserver) { StrictMock<MockObserver> observer1; RegisterObserver(1, &observer1); EXPECT_CALL(observer1, OnInsertCountReachedThreshold); @@ -462,7 +620,7 @@ TEST_F(QpackHeaderTableTest, RegisterObserver) { Mock::VerifyAndClearExpectations(&observer5); } -TEST_F(QpackHeaderTableTest, UnregisterObserver) { +TEST_F(QpackDecoderHeaderTableTest, UnregisterObserver) { StrictMock<MockObserver> observer1; StrictMock<MockObserver> observer2; StrictMock<MockObserver> observer3; @@ -483,61 +641,15 @@ TEST_F(QpackHeaderTableTest, UnregisterObserver) { EXPECT_EQ(3u, inserted_entry_count()); } -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. - 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. - 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. - table.InsertEntry("foo", "bar"); - 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)); -} - -TEST_F(QpackHeaderTableTest, Cancel) { +TEST_F(QpackDecoderHeaderTableTest, Cancel) { StrictMock<MockObserver> observer; - auto table = std::make_unique<QpackHeaderTable>(); + auto table = std::make_unique<QpackDecoderHeaderTable>(); table->RegisterObserver(1, &observer); EXPECT_CALL(observer, Cancel); table.reset(); } -TEST_F(QpackHeaderTableTest, EntryFitsDynamicTableCapacity) { - EXPECT_TRUE(SetDynamicTableCapacity(39)); - - EXPECT_TRUE(EntryFitsDynamicTableCapacity("foo", "bar")); - EXPECT_TRUE(EntryFitsDynamicTableCapacity("foo", "bar2")); - EXPECT_FALSE(EntryFitsDynamicTableCapacity("foo", "bar12")); -} - } // namespace } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder_test.cc index 3f68d749f36..b10c1b42d86 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder_test.cc @@ -12,7 +12,6 @@ #include "quic/platform/api/quic_logging.h" #include "quic/platform/api/quic_test.h" #include "quic/test_tools/qpack/qpack_test_utils.h" -#include "common/platform/api/quiche_text_utils.h" using ::testing::_; using ::testing::Eq; diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder_test.cc index 36b89bd01ec..c84634b1321 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder_test.cc @@ -8,7 +8,6 @@ #include "absl/strings/string_view.h" #include "quic/platform/api/quic_logging.h" #include "quic/platform/api/quic_test.h" -#include "common/platform/api/quiche_text_utils.h" namespace quic { namespace test { 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 ac07fedff61..3e7d0ad5127 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 @@ -20,7 +20,7 @@ QpackProgressiveDecoder::QpackProgressiveDecoder( QuicStreamId stream_id, BlockedStreamLimitEnforcer* enforcer, DecodingCompletedVisitor* visitor, - QpackHeaderTable* header_table, + QpackDecoderHeaderTable* header_table, HeadersHandlerInterface* handler) : stream_id_(stream_id), prefix_decoder_( 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 e806ea0fd66..ced6bf0c2dd 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 @@ -18,12 +18,12 @@ namespace quic { -class QpackHeaderTable; +class QpackDecoderHeaderTable; // Class to decode a single header block. class QUIC_EXPORT_PRIVATE QpackProgressiveDecoder : public QpackInstructionDecoder::Delegate, - public QpackHeaderTable::Observer { + public QpackDecoderHeaderTable::Observer { public: // Interface for receiving decoded header block from the decoder. class QUIC_EXPORT_PRIVATE HeadersHandlerInterface { @@ -82,7 +82,7 @@ class QUIC_EXPORT_PRIVATE QpackProgressiveDecoder QpackProgressiveDecoder(QuicStreamId stream_id, BlockedStreamLimitEnforcer* enforcer, DecodingCompletedVisitor* visitor, - QpackHeaderTable* header_table, + QpackDecoderHeaderTable* header_table, HeadersHandlerInterface* handler); QpackProgressiveDecoder(const QpackProgressiveDecoder&) = delete; QpackProgressiveDecoder& operator=(const QpackProgressiveDecoder&) = delete; @@ -103,7 +103,7 @@ class QUIC_EXPORT_PRIVATE QpackProgressiveDecoder void OnInstructionDecodingError(QpackInstructionDecoder::ErrorCode error_code, absl::string_view error_message) override; - // QpackHeaderTable::Observer implementation. + // QpackDecoderHeaderTable::Observer implementation. void OnInsertCountReachedThreshold() override; void Cancel() override; @@ -134,7 +134,7 @@ class QUIC_EXPORT_PRIVATE QpackProgressiveDecoder BlockedStreamLimitEnforcer* const enforcer_; DecodingCompletedVisitor* const visitor_; - QpackHeaderTable* const header_table_; + QpackDecoderHeaderTable* const header_table_; HeadersHandlerInterface* const handler_; // Required Insert Count and Base are decoded from the Header Data Prefix. @@ -163,7 +163,7 @@ class QUIC_EXPORT_PRIVATE QpackProgressiveDecoder // True if a decoding error has been detected. bool error_detected_; - // True if QpackHeaderTable has been destroyed + // True if QpackDecoderHeaderTable has been destroyed // while decoding is still blocked. bool cancelled_; }; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_chaos_protector.cc b/chromium/net/third_party/quiche/src/quic/core/quic_chaos_protector.cc new file mode 100644 index 00000000000..4eb353b183d --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/quic_chaos_protector.cc @@ -0,0 +1,229 @@ +// Copyright (c) 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "quic/core/quic_chaos_protector.h" + +#include <algorithm> +#include <cstddef> +#include <cstdint> +#include <limits> +#include <memory> + +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "quic/core/crypto/quic_random.h" +#include "quic/core/frames/quic_crypto_frame.h" +#include "quic/core/frames/quic_frame.h" +#include "quic/core/frames/quic_padding_frame.h" +#include "quic/core/frames/quic_ping_frame.h" +#include "quic/core/quic_data_reader.h" +#include "quic/core/quic_data_writer.h" +#include "quic/core/quic_framer.h" +#include "quic/core/quic_packets.h" +#include "quic/core/quic_stream_frame_data_producer.h" +#include "quic/platform/api/quic_bug_tracker.h" +#include "common/platform/api/quiche_logging.h" + +namespace quic { + +QuicChaosProtector::QuicChaosProtector(const QuicCryptoFrame& crypto_frame, + int num_padding_bytes, + size_t packet_size, + QuicFramer* framer, + QuicRandom* random) + : packet_size_(packet_size), + crypto_data_length_(crypto_frame.data_length), + crypto_buffer_offset_(crypto_frame.offset), + level_(crypto_frame.level), + remaining_padding_bytes_(num_padding_bytes), + framer_(framer), + random_(random) { + QUICHE_DCHECK_NE(framer_, nullptr); + QUICHE_DCHECK_NE(framer_->data_producer(), nullptr); + QUICHE_DCHECK_NE(random_, nullptr); +} + +QuicChaosProtector::~QuicChaosProtector() { + DeleteFrames(&frames_); +} + +absl::optional<size_t> QuicChaosProtector::BuildDataPacket( + const QuicPacketHeader& header, + char* buffer) { + if (!CopyCryptoDataToLocalBuffer()) { + return absl::nullopt; + } + SplitCryptoFrame(); + AddPingFrames(); + SpreadPadding(); + ReorderFrames(); + return BuildPacket(header, buffer); +} + +WriteStreamDataResult QuicChaosProtector::WriteStreamData( + QuicStreamId id, + QuicStreamOffset offset, + QuicByteCount data_length, + QuicDataWriter* /*writer*/) { + QUIC_BUG(chaos stream) << "This should never be called; id " << id + << " offset " << offset << " data_length " + << data_length; + return STREAM_MISSING; +} + +bool QuicChaosProtector::WriteCryptoData(EncryptionLevel level, + QuicStreamOffset offset, + QuicByteCount data_length, + QuicDataWriter* writer) { + if (level != level_) { + QUIC_BUG(chaos bad level) << "Unexpected " << level << " != " << level_; + return false; + } + // This is `offset + data_length > buffer_offset_ + buffer_length_` + // but with integer overflow protection. + if (offset < crypto_buffer_offset_ || data_length > crypto_data_length_ || + offset - crypto_buffer_offset_ > crypto_data_length_ - data_length) { + QUIC_BUG(chaos bad lengths) + << "Unexpected buffer_offset_ " << crypto_buffer_offset_ << " offset " + << offset << " buffer_length_ " << crypto_data_length_ + << " data_length " << data_length; + return false; + } + writer->WriteBytes(&crypto_data_buffer_[offset - crypto_buffer_offset_], + data_length); + return true; +} + +bool QuicChaosProtector::CopyCryptoDataToLocalBuffer() { + crypto_frame_buffer_ = std::make_unique<char[]>(packet_size_); + frames_.push_back(QuicFrame( + new QuicCryptoFrame(level_, crypto_buffer_offset_, crypto_data_length_))); + // We use |framer_| to serialize the CRYPTO frame in order to extract its + // data from the crypto data producer. This ensures that we reuse the + // usual serialization code path, but has the downside that we then need to + // parse the offset and length in order to skip over those fields. + QuicDataWriter writer(packet_size_, crypto_frame_buffer_.get()); + if (!framer_->AppendCryptoFrame(*frames_.front().crypto_frame, &writer)) { + QUIC_BUG(chaos write crypto data); + return false; + } + QuicDataReader reader(crypto_frame_buffer_.get(), writer.length()); + uint64_t parsed_offset, parsed_length; + if (!reader.ReadVarInt62(&parsed_offset) || + !reader.ReadVarInt62(&parsed_length)) { + QUIC_BUG(chaos parse crypto frame); + return false; + } + + absl::string_view crypto_data = reader.ReadRemainingPayload(); + crypto_data_buffer_ = crypto_data.data(); + + QUICHE_DCHECK_EQ(parsed_offset, crypto_buffer_offset_); + QUICHE_DCHECK_EQ(parsed_length, crypto_data_length_); + QUICHE_DCHECK_EQ(parsed_length, crypto_data.length()); + + return true; +} + +void QuicChaosProtector::SplitCryptoFrame() { + const int max_overhead_of_adding_a_crypto_frame = + static_cast<int>(QuicFramer::GetMinCryptoFrameSize( + crypto_buffer_offset_ + crypto_data_length_, crypto_data_length_)); + // Pick a random number of CRYPTO frames to add. + constexpr uint64_t kMaxAddedCryptoFrames = 10; + const uint64_t num_added_crypto_frames = + random_->InsecureRandUint64() % (kMaxAddedCryptoFrames + 1); + for (uint64_t i = 0; i < num_added_crypto_frames; i++) { + if (remaining_padding_bytes_ < max_overhead_of_adding_a_crypto_frame) { + break; + } + // Pick a random frame and split it by shrinking the picked frame and + // moving the second half of its data to a new frame that is then appended + // to |frames|. + size_t frame_to_split_index = + random_->InsecureRandUint64() % frames_.size(); + QuicCryptoFrame* frame_to_split = + frames_[frame_to_split_index].crypto_frame; + if (frame_to_split->data_length <= 1) { + continue; + } + const int frame_to_split_old_overhead = + static_cast<int>(QuicFramer::GetMinCryptoFrameSize( + frame_to_split->offset, frame_to_split->data_length)); + const QuicPacketLength frame_to_split_new_data_length = + 1 + (random_->InsecureRandUint64() % (frame_to_split->data_length - 1)); + const QuicPacketLength new_frame_data_length = + frame_to_split->data_length - frame_to_split_new_data_length; + const QuicStreamOffset new_frame_offset = + frame_to_split->offset + frame_to_split_new_data_length; + frame_to_split->data_length -= new_frame_data_length; + frames_.push_back(QuicFrame( + new QuicCryptoFrame(level_, new_frame_offset, new_frame_data_length))); + const int frame_to_split_new_overhead = + static_cast<int>(QuicFramer::GetMinCryptoFrameSize( + frame_to_split->offset, frame_to_split->data_length)); + const int new_frame_overhead = + static_cast<int>(QuicFramer::GetMinCryptoFrameSize( + new_frame_offset, new_frame_data_length)); + QUICHE_DCHECK_LE(frame_to_split_new_overhead, frame_to_split_old_overhead); + // Readjust padding based on increased overhead. + remaining_padding_bytes_ -= new_frame_overhead; + remaining_padding_bytes_ -= frame_to_split_new_overhead; + remaining_padding_bytes_ += frame_to_split_old_overhead; + } +} + +void QuicChaosProtector::AddPingFrames() { + constexpr uint64_t kMaxAddedPingFrames = 10; + const uint64_t num_ping_frames = + random_->InsecureRandUint64() % + std::min<uint64_t>(kMaxAddedPingFrames, remaining_padding_bytes_); + for (uint64_t i = 0; i < num_ping_frames; i++) { + frames_.push_back(QuicFrame(QuicPingFrame())); + } + remaining_padding_bytes_ -= static_cast<int>(num_ping_frames); +} + +void QuicChaosProtector::ReorderFrames() { + // Walk the array backwards and swap each frame with a random earlier one. + for (size_t i = frames_.size() - 1; i > 0; i--) { + std::swap(frames_[i], frames_[random_->InsecureRandUint64() % (i + 1)]); + } +} + +void QuicChaosProtector::SpreadPadding() { + for (auto it = frames_.begin(); it != frames_.end(); ++it) { + const int padding_bytes_in_this_frame = + random_->InsecureRandUint64() % (remaining_padding_bytes_ + 1); + if (padding_bytes_in_this_frame <= 0) { + continue; + } + it = frames_.insert( + it, QuicFrame(QuicPaddingFrame(padding_bytes_in_this_frame))); + ++it; // Skip over the padding frame we just added. + remaining_padding_bytes_ -= padding_bytes_in_this_frame; + } + if (remaining_padding_bytes_ > 0) { + frames_.push_back(QuicFrame(QuicPaddingFrame(remaining_padding_bytes_))); + } +} + +absl::optional<size_t> QuicChaosProtector::BuildPacket( + const QuicPacketHeader& header, + char* buffer) { + QuicStreamFrameDataProducer* original_data_producer = + framer_->data_producer(); + framer_->set_data_producer(this); + + size_t length = + framer_->BuildDataPacket(header, frames_, buffer, packet_size_, level_); + + framer_->set_data_producer(original_data_producer); + if (length == 0) { + return absl::nullopt; + } + return length; +} + +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_chaos_protector.h b/chromium/net/third_party/quiche/src/quic/core/quic_chaos_protector.h new file mode 100644 index 00000000000..6bcd42087e7 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/quic_chaos_protector.h @@ -0,0 +1,99 @@ +// Copyright (c) 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_QUIC_CHAOS_PROTECTOR_H_ +#define QUICHE_QUIC_CORE_QUIC_CHAOS_PROTECTOR_H_ + +#include <cstddef> +#include <memory> + +#include "absl/types/optional.h" +#include "quic/core/crypto/quic_random.h" +#include "quic/core/frames/quic_crypto_frame.h" +#include "quic/core/frames/quic_frame.h" +#include "quic/core/quic_data_writer.h" +#include "quic/core/quic_framer.h" +#include "quic/core/quic_packets.h" +#include "quic/core/quic_stream_frame_data_producer.h" +#include "quic/core/quic_types.h" + +namespace quic { + +namespace test { +class QuicChaosProtectorTest; +} + +// QuicChaosProtector will take a crypto frame and an amount of padding and +// build a data packet that will parse to something equivalent. +class QUIC_EXPORT_PRIVATE QuicChaosProtector + : public QuicStreamFrameDataProducer { + public: + // |framer| and |random| must be valid for the lifetime of QuicChaosProtector. + explicit QuicChaosProtector(const QuicCryptoFrame& crypto_frame, + int num_padding_bytes, + size_t packet_size, + QuicFramer* framer, + QuicRandom* random); + + ~QuicChaosProtector() override; + + QuicChaosProtector(const QuicChaosProtector&) = delete; + QuicChaosProtector(QuicChaosProtector&&) = delete; + QuicChaosProtector& operator=(const QuicChaosProtector&) = delete; + QuicChaosProtector& operator=(QuicChaosProtector&&) = delete; + + // Attempts to build a data packet with chaos protection. If an error occurs, + // then absl::nullopt is returned. Otherwise returns the serialized length. + absl::optional<size_t> BuildDataPacket(const QuicPacketHeader& header, + char* buffer); + + // From QuicStreamFrameDataProducer. + WriteStreamDataResult WriteStreamData(QuicStreamId id, + QuicStreamOffset offset, + QuicByteCount data_length, + QuicDataWriter* /*writer*/) override; + bool WriteCryptoData(EncryptionLevel level, + QuicStreamOffset offset, + QuicByteCount data_length, + QuicDataWriter* writer) override; + + private: + friend class test::QuicChaosProtectorTest; + + // Allocate the crypto data buffer, create the CRYPTO frame and write the + // crypto data to our buffer. + bool CopyCryptoDataToLocalBuffer(); + + // Split the CRYPTO frame in |frames_| into one or more CRYPTO frames that + // collectively represent the same data. Adjusts padding to compensate. + void SplitCryptoFrame(); + + // Add a random number of PING frames to |frames_| and adjust padding. + void AddPingFrames(); + + // Randomly reorder |frames_|. + void ReorderFrames(); + + // Add PADDING frames randomly between all other frames. + void SpreadPadding(); + + // Serialize |frames_| using |framer_|. + absl::optional<size_t> BuildPacket(const QuicPacketHeader& header, + char* buffer); + + size_t packet_size_; + std::unique_ptr<char[]> crypto_frame_buffer_; + const char* crypto_data_buffer_ = nullptr; + QuicByteCount crypto_data_length_; + QuicStreamOffset crypto_buffer_offset_; + EncryptionLevel level_; + int remaining_padding_bytes_; + QuicFrames frames_; // Inner frames owned, will be deleted by destructor. + QuicFramer* framer_; // Unowned. + QuicRandom* random_; // Unowned. +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_QUIC_CHAOS_PROTECTOR_H_ diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_chaos_protector_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_chaos_protector_test.cc new file mode 100644 index 00000000000..1ec985beea1 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/quic_chaos_protector_test.cc @@ -0,0 +1,207 @@ +// Copyright (c) 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "quic/core/quic_chaos_protector.h" + +#include <cstddef> +#include <memory> + +#include "absl/strings/string_view.h" +#include "quic/core/frames/quic_crypto_frame.h" +#include "quic/core/quic_connection_id.h" +#include "quic/core/quic_framer.h" +#include "quic/core/quic_packet_number.h" +#include "quic/core/quic_packets.h" +#include "quic/core/quic_stream_frame_data_producer.h" +#include "quic/core/quic_time.h" +#include "quic/core/quic_types.h" +#include "quic/core/quic_versions.h" +#include "quic/platform/api/quic_test.h" +#include "quic/test_tools/mock_random.h" +#include "quic/test_tools/quic_test_utils.h" +#include "quic/test_tools/simple_quic_framer.h" + +namespace quic { +namespace test { + +class QuicChaosProtectorTest : public QuicTestWithParam<ParsedQuicVersion>, + public QuicStreamFrameDataProducer { + public: + QuicChaosProtectorTest() + : version_(GetParam()), + framer_({version_}, + QuicTime::Zero(), + Perspective::IS_CLIENT, + kQuicDefaultConnectionIdLength), + validation_framer_({version_}), + random_(/*base=*/3), + level_(ENCRYPTION_INITIAL), + crypto_offset_(0), + crypto_data_length_(100), + crypto_frame_(level_, crypto_offset_, crypto_data_length_), + num_padding_bytes_(50), + packet_size_(1000), + packet_buffer_(std::make_unique<char[]>(packet_size_)), + chaos_protector_(crypto_frame_, + num_padding_bytes_, + packet_size_, + SetupHeaderAndFramers(), + &random_) {} + + // From QuicStreamFrameDataProducer. + WriteStreamDataResult WriteStreamData(QuicStreamId /*id*/, + QuicStreamOffset /*offset*/, + QuicByteCount /*data_length*/, + QuicDataWriter* /*writer*/) override { + ADD_FAILURE() << "This should never be called"; + return STREAM_MISSING; + } + + // From QuicStreamFrameDataProducer. + bool WriteCryptoData(EncryptionLevel level, + QuicStreamOffset offset, + QuicByteCount data_length, + QuicDataWriter* writer) override { + EXPECT_EQ(level, level); + EXPECT_EQ(offset, crypto_offset_); + EXPECT_EQ(data_length, crypto_data_length_); + for (QuicByteCount i = 0; i < data_length; i++) { + EXPECT_TRUE(writer->WriteUInt8(static_cast<uint8_t>(i & 0xFF))); + } + return true; + } + + protected: + QuicFramer* SetupHeaderAndFramers() { + // Setup header. + header_.destination_connection_id = TestConnectionId(); + header_.destination_connection_id_included = CONNECTION_ID_PRESENT; + header_.source_connection_id = EmptyQuicConnectionId(); + header_.source_connection_id_included = CONNECTION_ID_PRESENT; + header_.reset_flag = false; + header_.version_flag = true; + header_.has_possible_stateless_reset_token = false; + header_.packet_number_length = PACKET_4BYTE_PACKET_NUMBER; + header_.version = version_; + header_.packet_number = QuicPacketNumber(1); + header_.form = IETF_QUIC_LONG_HEADER_PACKET; + header_.long_packet_type = INITIAL; + header_.retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_1; + header_.length_length = kQuicDefaultLongHeaderLengthLength; + // Setup validation framer. + validation_framer_.framer()->SetInitialObfuscators( + header_.destination_connection_id); + // Setup framer. + framer_.SetInitialObfuscators(header_.destination_connection_id); + framer_.set_data_producer(this); + return &framer_; + } + + void BuildEncryptAndParse() { + absl::optional<size_t> length = + chaos_protector_.BuildDataPacket(header_, packet_buffer_.get()); + ASSERT_TRUE(length.has_value()); + ASSERT_GT(length.value(), 0u); + size_t encrypted_length = framer_.EncryptInPlace( + level_, header_.packet_number, + GetStartOfEncryptedData(framer_.transport_version(), header_), + length.value(), packet_size_, packet_buffer_.get()); + ASSERT_GT(encrypted_length, 0u); + ASSERT_TRUE(validation_framer_.ProcessPacket(QuicEncryptedPacket( + absl::string_view(packet_buffer_.get(), encrypted_length)))); + } + + void ResetOffset(QuicStreamOffset offset) { + crypto_offset_ = offset; + crypto_frame_.offset = offset; + chaos_protector_.crypto_buffer_offset_ = offset; + } + + ParsedQuicVersion version_; + QuicPacketHeader header_; + QuicFramer framer_; + SimpleQuicFramer validation_framer_; + MockRandom random_; + EncryptionLevel level_; + QuicStreamOffset crypto_offset_; + QuicByteCount crypto_data_length_; + QuicCryptoFrame crypto_frame_; + int num_padding_bytes_; + size_t packet_size_; + std::unique_ptr<char[]> packet_buffer_; + QuicChaosProtector chaos_protector_; +}; + +namespace { + +ParsedQuicVersionVector TestVersions() { + ParsedQuicVersionVector versions; + for (const ParsedQuicVersion& version : AllSupportedVersions()) { + if (version.UsesCryptoFrames()) { + versions.push_back(version); + } + } + return versions; +} + +INSTANTIATE_TEST_SUITE_P(QuicChaosProtectorTests, + QuicChaosProtectorTest, + ::testing::ValuesIn(TestVersions()), + ::testing::PrintToStringParamName()); + +TEST_P(QuicChaosProtectorTest, Main) { + BuildEncryptAndParse(); + ASSERT_EQ(validation_framer_.crypto_frames().size(), 4u); + EXPECT_EQ(validation_framer_.crypto_frames()[0]->offset, 0u); + EXPECT_EQ(validation_framer_.crypto_frames()[0]->data_length, 1u); + ASSERT_EQ(validation_framer_.ping_frames().size(), 3u); + ASSERT_EQ(validation_framer_.padding_frames().size(), 7u); + EXPECT_EQ(validation_framer_.padding_frames()[0].num_padding_bytes, 3); +} + +TEST_P(QuicChaosProtectorTest, DifferentRandom) { + random_.ResetBase(4); + BuildEncryptAndParse(); + ASSERT_EQ(validation_framer_.crypto_frames().size(), 4u); + ASSERT_EQ(validation_framer_.ping_frames().size(), 4u); + ASSERT_EQ(validation_framer_.padding_frames().size(), 8u); +} + +TEST_P(QuicChaosProtectorTest, RandomnessZero) { + random_.ResetBase(0); + BuildEncryptAndParse(); + ASSERT_EQ(validation_framer_.crypto_frames().size(), 1u); + EXPECT_EQ(validation_framer_.crypto_frames()[0]->offset, crypto_offset_); + EXPECT_EQ(validation_framer_.crypto_frames()[0]->data_length, + crypto_data_length_); + ASSERT_EQ(validation_framer_.ping_frames().size(), 0u); + ASSERT_EQ(validation_framer_.padding_frames().size(), 1u); +} + +TEST_P(QuicChaosProtectorTest, Offset) { + ResetOffset(123); + BuildEncryptAndParse(); + ASSERT_EQ(validation_framer_.crypto_frames().size(), 4u); + EXPECT_EQ(validation_framer_.crypto_frames()[0]->offset, crypto_offset_); + EXPECT_EQ(validation_framer_.crypto_frames()[0]->data_length, 1u); + ASSERT_EQ(validation_framer_.ping_frames().size(), 3u); + ASSERT_EQ(validation_framer_.padding_frames().size(), 7u); + EXPECT_EQ(validation_framer_.padding_frames()[0].num_padding_bytes, 3); +} + +TEST_P(QuicChaosProtectorTest, OffsetAndRandomnessZero) { + ResetOffset(123); + random_.ResetBase(0); + BuildEncryptAndParse(); + ASSERT_EQ(validation_framer_.crypto_frames().size(), 1u); + EXPECT_EQ(validation_framer_.crypto_frames()[0]->offset, crypto_offset_); + EXPECT_EQ(validation_framer_.crypto_frames()[0]->data_length, + crypto_data_length_); + ASSERT_EQ(validation_framer_.ping_frames().size(), 0u); + ASSERT_EQ(validation_framer_.padding_frames().size(), 1u); +} + +} // namespace +} // namespace test +} // namespace quic 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 9bd21403263..09806f5a8a8 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 @@ -48,7 +48,7 @@ #include "quic/platform/api/quic_map_util.h" #include "quic/platform/api/quic_server_stats.h" #include "quic/platform/api/quic_socket_address.h" -#include "common/platform/api/quiche_text_utils.h" +#include "common/quiche_text_utils.h" namespace quic { @@ -225,8 +225,8 @@ class ScopedCoalescedPacketClearer { }; // Whether this incoming packet is allowed to replace our connection ID. -bool PacketCanReplaceConnectionId(const QuicPacketHeader& header, - Perspective perspective) { +bool PacketCanReplaceServerConnectionId(const QuicPacketHeader& header, + Perspective perspective) { return perspective == Perspective::IS_CLIENT && header.form == IETF_QUIC_LONG_HEADER_PACKET && header.version.IsKnown() && @@ -282,7 +282,12 @@ QuicConnection::QuicConnection( client_connection_id_(EmptyQuicConnectionId()), client_connection_id_is_set_(false), direct_peer_address_(initial_peer_address), - default_path_(initial_self_address, QuicSocketAddress()), + default_path_(initial_self_address, + QuicSocketAddress(), + /*client_connection_id=*/EmptyQuicConnectionId(), + server_connection_id, + /*stateless_reset_token_received=*/false, + /*stateless_reset_token=*/{}), active_effective_peer_migration_type_(NO_CHANGE), support_key_update_for_connection_(false), last_packet_decrypted_(false), @@ -329,7 +334,7 @@ QuicConnection::QuicConnection( &arena_)), visitor_(nullptr), debug_visitor_(nullptr), - packet_creator_(server_connection_id_, &framer_, random_generator_, this), + packet_creator_(server_connection_id, &framer_, random_generator_, this), time_of_last_received_packet_(clock_->ApproximateNow()), sent_packet_manager_(perspective, clock_, @@ -370,11 +375,7 @@ QuicConnection::QuicConnection( encrypted_control_frames_ && GetQuicReloadableFlag(quic_use_encryption_level_context)), path_validator_(alarm_factory_, &arena_, this, random_generator_), - alternative_path_(QuicSocketAddress(), QuicSocketAddress()), most_recent_frame_type_(NUM_FRAME_TYPES) { - QUIC_BUG_IF(quic_bug_12714_1, - !start_peer_migration_earlier_ && send_path_response_); - QUICHE_DCHECK(perspective_ == Perspective::IS_CLIENT || default_path_.self_address.IsInitialized()); @@ -384,12 +385,10 @@ QuicConnection::QuicConnection( support_multiple_connection_ids_ = version().HasIetfQuicFrames() && - framer_.do_not_synthesize_source_cid_for_short_header() && - GetQuicRestartFlag(quic_use_reference_counted_sesssion_map) && GetQuicRestartFlag(quic_time_wait_list_support_multiple_cid_v2) && GetQuicRestartFlag( quic_dispatcher_support_multiple_cid_per_connection_v2) && - GetQuicReloadableFlag(quic_connection_support_multiple_cids_v2); + GetQuicReloadableFlag(quic_connection_support_multiple_cids_v4); QUIC_DLOG(INFO) << ENDPOINT << "Created connection with server connection ID " << server_connection_id @@ -418,7 +417,7 @@ QuicConnection::QuicConnection( MaybeEnableMultiplePacketNumberSpacesSupport(); QUICHE_DCHECK(perspective_ == Perspective::IS_CLIENT || supported_versions.size() == 1); - InstallInitialCrypters(server_connection_id_); + InstallInitialCrypters(ServerConnectionId()); // On the server side, version negotiation has been done by the dispatcher, // and the server connection is created with the right version. @@ -449,6 +448,7 @@ void QuicConnection::InstallInitialCrypters(QuicConnectionId connection_id) { } QuicConnection::~QuicConnection() { + QUICHE_DCHECK_GE(stats_.max_egress_mtu, long_term_mtu_); if (owns_writer_) { delete writer_; } @@ -482,9 +482,9 @@ bool QuicConnection::ValidateConfigConnectionIds(const QuicConfig& config) { // Validate initial_source_connection_id. QuicConnectionId expected_initial_source_connection_id; if (perspective_ == Perspective::IS_CLIENT) { - expected_initial_source_connection_id = server_connection_id_; + expected_initial_source_connection_id = ServerConnectionId(); } else { - expected_initial_source_connection_id = client_connection_id_; + expected_initial_source_connection_id = ClientConnectionId(); } if (!config.HasReceivedInitialSourceConnectionId() || config.ReceivedInitialSourceConnectionId() != @@ -585,6 +585,9 @@ void QuicConnection::SetFromConfig(const QuicConfig& config) { } else { SetNetworkTimeouts(config.max_time_before_crypto_handshake(), config.max_idle_time_before_crypto_handshake()); + if (config.HasClientRequestedIndependentOption(kCHSP, perspective_)) { + packet_creator_.set_chaos_protection_enabled(true); + } } if (support_multiple_connection_ids_ && @@ -679,8 +682,14 @@ void QuicConnection::SetFromConfig(const QuicConfig& config) { no_stop_waiting_frames_ = true; } if (config.HasReceivedStatelessResetToken()) { - stateless_reset_token_received_ = true; - received_stateless_reset_token_ = config.ReceivedStatelessResetToken(); + if (use_connection_id_on_default_path_) { + default_path_.stateless_reset_token_received = true; + default_path_.stateless_reset_token = + config.ReceivedStatelessResetToken(); + } else { + stateless_reset_token_received_ = true; + received_stateless_reset_token_ = config.ReceivedStatelessResetToken(); + } } if (config.HasReceivedAckDelayExponent()) { framer_.set_peer_ack_delay_exponent(config.ReceivedAckDelayExponent()); @@ -704,6 +713,17 @@ void QuicConnection::SetFromConfig(const QuicConfig& config) { QUIC_CODE_COUNT_N(quic_server_reverse_validate_new_path3, 6, 6); validate_client_addresses_ = true; } + // Having connection_migration_use_new_cid_ depends on the same set of flags + // and connection option on both client and server sides has the advantage of: + // 1) Less chance of skew in using new connection ID or not between client + // and server in unit tests with random flag combinations. + // 2) Client side's rollout can be protected by the same connection option. + connection_migration_use_new_cid_ = + support_multiple_connection_ids_ && validate_client_addresses_ && + use_connection_id_on_default_path_ && + group_path_response_and_challenge_sending_closer_ && + GetQuicReloadableFlag(quic_drop_unsent_path_response) && + GetQuicReloadableFlag(quic_connection_migration_use_new_cid_v2); if (config.HasReceivedMaxPacketSize()) { peer_max_packet_size_ = config.ReceivedMaxPacketSize(); MaybeUpdatePacketCreatorMaxPacketLengthAndPadding(); @@ -865,7 +885,7 @@ void QuicConnection::OnPublicResetPacket(const QuicPublicResetPacket& packet) { // Check that any public reset packet with a different connection ID that was // routed to this QuicConnection has been redirected before control reaches // here. (Check for a bug regression.) - QUICHE_DCHECK_EQ(server_connection_id_, packet.connection_id); + QUICHE_DCHECK_EQ(ServerConnectionId(), packet.connection_id); QUICHE_DCHECK_EQ(perspective_, Perspective::IS_CLIENT); QUICHE_DCHECK(!version().HasIetfInvariantHeader()); if (debug_visitor_ != nullptr) { @@ -903,7 +923,7 @@ void QuicConnection::OnVersionNegotiationPacket( // Check that any public reset packet with a different connection ID that was // routed to this QuicConnection has been redirected before control reaches // here. (Check for a bug regression.) - QUICHE_DCHECK_EQ(server_connection_id_, packet.connection_id); + QUICHE_DCHECK_EQ(ServerConnectionId(), packet.connection_id); if (perspective_ == Perspective::IS_SERVER) { const std::string error_details = "Server received version negotiation packet."; @@ -954,17 +974,17 @@ void QuicConnection::OnRetryPacket(QuicConnectionId original_connection_id, absl::string_view retry_without_tag) { QUICHE_DCHECK_EQ(Perspective::IS_CLIENT, perspective_); if (version().UsesTls()) { - if (!CryptoUtils::ValidateRetryIntegrityTag( - version(), server_connection_id_, retry_without_tag, - retry_integrity_tag)) { + if (!CryptoUtils::ValidateRetryIntegrityTag(version(), ServerConnectionId(), + retry_without_tag, + retry_integrity_tag)) { QUIC_DLOG(ERROR) << "Ignoring RETRY with invalid integrity tag"; return; } } else { - if (original_connection_id != server_connection_id_) { + if (original_connection_id != ServerConnectionId()) { QUIC_DLOG(ERROR) << "Ignoring RETRY with original connection ID " << original_connection_id << " not matching expected " - << server_connection_id_ << " token " + << ServerConnectionId() << " token " << absl::BytesToHexString(retry_token); return; } @@ -972,10 +992,10 @@ void QuicConnection::OnRetryPacket(QuicConnectionId original_connection_id, framer_.set_drop_incoming_retry_packets(true); stats_.retry_packet_processed = true; QUIC_DLOG(INFO) << "Received RETRY, replacing connection ID " - << server_connection_id_ << " with " << new_connection_id + << ServerConnectionId() << " with " << new_connection_id << ", received token " << absl::BytesToHexString(retry_token); if (!original_destination_connection_id_.has_value()) { - original_destination_connection_id_ = server_connection_id_; + original_destination_connection_id_ = ServerConnectionId(); } QUICHE_DCHECK(!retry_source_connection_id_.has_value()) << retry_source_connection_id_.value(); @@ -984,12 +1004,18 @@ void QuicConnection::OnRetryPacket(QuicConnectionId original_connection_id, packet_creator_.SetRetryToken(retry_token); // Reinstall initial crypters because the connection ID changed. - InstallInitialCrypters(server_connection_id_); + InstallInitialCrypters(ServerConnectionId()); sent_packet_manager_.MarkInitialPacketsForRetransmission(); } -bool QuicConnection::HasIncomingConnectionId(QuicConnectionId connection_id) { +bool QuicConnection::HasIncomingConnectionId( + QuicConnectionId connection_id) const { + if (quic_deprecate_incoming_connection_ids_) { + QUIC_RELOADABLE_FLAG_COUNT(quic_deprecate_incoming_connection_ids); + // TODO(haoyuewang) Inline this after the flag is deprecated. + return connection_id == original_destination_connection_id_; + } for (QuicConnectionId const& incoming_connection_id : incoming_connection_ids_) { if (incoming_connection_id == connection_id) { @@ -1004,54 +1030,89 @@ void QuicConnection::SetOriginalDestinationConnectionId( QUIC_DLOG(INFO) << "Setting original_destination_connection_id to " << original_destination_connection_id << " on connection with server_connection_id " - << server_connection_id_; - QUICHE_DCHECK_NE(original_destination_connection_id, server_connection_id_); - if (!HasIncomingConnectionId(original_destination_connection_id)) { - incoming_connection_ids_.push_back(original_destination_connection_id); + << ServerConnectionId(); + QUICHE_DCHECK_NE(original_destination_connection_id, ServerConnectionId()); + if (!quic_deprecate_incoming_connection_ids_) { + if (!HasIncomingConnectionId(original_destination_connection_id)) { + incoming_connection_ids_.push_back(original_destination_connection_id); + } } InstallInitialCrypters(original_destination_connection_id); QUICHE_DCHECK(!original_destination_connection_id_.has_value()) << original_destination_connection_id_.value(); original_destination_connection_id_ = original_destination_connection_id; + original_destination_connection_id_replacement_ = ServerConnectionId(); } QuicConnectionId QuicConnection::GetOriginalDestinationConnectionId() { if (original_destination_connection_id_.has_value()) { return original_destination_connection_id_.value(); } - return server_connection_id_; + return ServerConnectionId(); +} + +bool QuicConnection::ValidateServerConnectionId( + const QuicPacketHeader& header) const { + if (perspective_ == Perspective::IS_CLIENT && + header.form == IETF_QUIC_SHORT_HEADER_PACKET) { + return true; + } + + QuicConnectionId server_connection_id = + GetServerConnectionIdAsRecipient(header, perspective_); + + if (server_connection_id == ServerConnectionId() || + HasIncomingConnectionId(server_connection_id)) { + return true; + } + + if (PacketCanReplaceServerConnectionId(header, perspective_)) { + QUIC_DLOG(INFO) << ENDPOINT << "Accepting packet with new connection ID " + << server_connection_id << " instead of " + << ServerConnectionId(); + return true; + } + + if (connection_migration_use_new_cid_ && + perspective_ == Perspective::IS_SERVER && + self_issued_cid_manager_ != nullptr && + self_issued_cid_manager_->IsConnectionIdInUse(server_connection_id)) { + return true; + } + + return false; } bool QuicConnection::OnUnauthenticatedPublicHeader( const QuicPacketHeader& header) { + last_packet_destination_connection_id_ = header.destination_connection_id; + // If last packet destination connection ID is the original server + // connection ID chosen by client, replaces it with the connection ID chosen + // by server. + if (use_connection_id_on_default_path_ && + perspective_ == Perspective::IS_SERVER && + original_destination_connection_id_.has_value() && + last_packet_destination_connection_id_ == + *original_destination_connection_id_) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_use_connection_id_on_default_path_v2, 3, + 3); + last_packet_destination_connection_id_ = + original_destination_connection_id_replacement_; + } + // As soon as we receive an initial we start ignoring subsequent retries. if (header.version_flag && header.long_packet_type == INITIAL) { framer_.set_drop_incoming_retry_packets(true); } - bool skip_server_connection_id_validation = - framer_.do_not_synthesize_source_cid_for_short_header() && - perspective_ == Perspective::IS_CLIENT && - header.form == IETF_QUIC_SHORT_HEADER_PACKET; - - QuicConnectionId server_connection_id = - GetServerConnectionIdAsRecipient(header, perspective_); - - if (!skip_server_connection_id_validation && - server_connection_id != server_connection_id_ && - !HasIncomingConnectionId(server_connection_id)) { - if (PacketCanReplaceConnectionId(header, perspective_)) { - QUIC_DLOG(INFO) << ENDPOINT << "Accepting packet with new connection ID " - << server_connection_id << " instead of " - << server_connection_id_; - return true; - } - + if (!ValidateServerConnectionId(header)) { ++stats_.packets_dropped; + QuicConnectionId server_connection_id = + GetServerConnectionIdAsRecipient(header, perspective_); QUIC_DLOG(INFO) << ENDPOINT << "Ignoring packet from unexpected server connection ID " << server_connection_id << " instead of " - << server_connection_id_; + << ServerConnectionId(); if (debug_visitor_ != nullptr) { debug_visitor_->OnIncorrectConnectionId(server_connection_id); } @@ -1066,18 +1127,15 @@ bool QuicConnection::OnUnauthenticatedPublicHeader( return true; } - if (framer_.do_not_synthesize_source_cid_for_short_header() && - perspective_ == Perspective::IS_SERVER && + if (perspective_ == Perspective::IS_SERVER && header.form == IETF_QUIC_SHORT_HEADER_PACKET) { - QUIC_RELOADABLE_FLAG_COUNT_N( - quic_do_not_synthesize_source_cid_for_short_header, 3, 3); return true; } QuicConnectionId client_connection_id = GetClientConnectionIdAsRecipient(header, perspective_); - if (client_connection_id == client_connection_id_) { + if (client_connection_id == ClientConnectionId()) { return true; } @@ -1089,11 +1147,18 @@ bool QuicConnection::OnUnauthenticatedPublicHeader( return true; } + if (connection_migration_use_new_cid_ && + perspective_ == Perspective::IS_CLIENT && + self_issued_cid_manager_ != nullptr && + self_issued_cid_manager_->IsConnectionIdInUse(client_connection_id)) { + return true; + } + ++stats_.packets_dropped; QUIC_DLOG(INFO) << ENDPOINT << "Ignoring packet from unexpected client connection ID " << client_connection_id << " instead of " - << client_connection_id_; + << ClientConnectionId(); return false; } @@ -1102,17 +1167,8 @@ bool QuicConnection::OnUnauthenticatedHeader(const QuicPacketHeader& header) { debug_visitor_->OnUnauthenticatedHeader(header); } - // Check that any public reset packet with a different connection ID that was - // routed to this QuicConnection has been redirected before control reaches - // here. - QUICHE_DCHECK((framer_.do_not_synthesize_source_cid_for_short_header() && - perspective_ == Perspective::IS_CLIENT && - header.form == IETF_QUIC_SHORT_HEADER_PACKET) || - GetServerConnectionIdAsRecipient(header, perspective_) == - server_connection_id_ || - HasIncomingConnectionId( - GetServerConnectionIdAsRecipient(header, perspective_)) || - PacketCanReplaceConnectionId(header, perspective_)); + // Sanity check on the server connection ID in header. + QUICHE_DCHECK(ValidateServerConnectionId(header)); if (packet_creator_.HasPendingFrames()) { // Incoming packets may change a queued ACK frame. @@ -1264,6 +1320,43 @@ bool QuicConnection::OnPacketHeader(const QuicPacketHeader& header) { default_path_.peer_address, GetEffectivePeerAddressFromCurrentPacket()); + if (connection_migration_use_new_cid_) { + auto effective_peer_address = GetEffectivePeerAddressFromCurrentPacket(); + // Since server does not send new connection ID to client before handshake + // completion and source connection ID is omitted in short header packet, + // the server_connection_id on PathState on the server side does not + // affect the packets server writes after handshake completion. On the + // other hand, it is still desirable to have the "correct" server + // connection ID set on path. + // 1) If client uses 1 unique server connection ID per path and the packet + // is received from an existing path, then + // last_packet_destination_connection_id_ will always be the same as the + // server connection ID on path. Server side will maintain the 1-to-1 + // mapping from server connection ID to path. + // 2) If client uses multiple server connection IDs on the same path, + // compared to the server_connection_id on path, + // last_packet_destination_connection_id_ has the advantage that it is + // still present in the session map since the packet can be routed here + // regardless of packet reordering. + if (IsDefaultPath(last_packet_destination_address_, + effective_peer_address)) { + default_path_.server_connection_id = + last_packet_destination_connection_id_; + } else if (IsAlternativePath(last_packet_destination_address_, + effective_peer_address)) { + alternative_path_.server_connection_id = + last_packet_destination_connection_id_; + } + } + + if (use_connection_id_on_default_path_ && + last_packet_destination_connection_id_ != ServerConnectionId() && + (!original_destination_connection_id_.has_value() || + last_packet_destination_connection_id_ != + *original_destination_connection_id_)) { + QUIC_CODE_COUNT(quic_connection_id_change); + } + QUIC_DLOG_IF(INFO, current_effective_peer_migration_type_ != NO_CHANGE) << ENDPOINT << "Effective peer's ip:port changed from " << default_path_.peer_address.ToString() << " to " @@ -1284,17 +1377,13 @@ bool QuicConnection::OnPacketHeader(const QuicPacketHeader& header) { uber_received_packet_manager_.RecordPacketReceived( last_decrypted_packet_level_, last_header_, idle_network_detector_.time_of_last_received_packet()); - if (GetQuicReloadableFlag(quic_enable_token_based_address_validation)) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_token_based_address_validation, 2, - 2); - if (EnforceAntiAmplificationLimit() && !IsHandshakeConfirmed() && - !header.retry_token.empty() && - visitor_->ValidateToken(header.retry_token)) { - QUIC_DLOG(INFO) << ENDPOINT << "Address validated via token."; - QUIC_CODE_COUNT(quic_address_validated_via_token); - default_path_.validated = true; - stats_.address_validated_via_token = true; - } + if (EnforceAntiAmplificationLimit() && !IsHandshakeConfirmed() && + !header.retry_token.empty() && + visitor_->ValidateToken(header.retry_token)) { + QUIC_DLOG(INFO) << ENDPOINT << "Address validated via token."; + QUIC_CODE_COUNT(quic_address_validated_via_token); + default_path_.validated = true; + stats_.address_validated_via_token = true; } QUICHE_DCHECK(connected_); return true; @@ -1684,8 +1773,12 @@ bool QuicConnection::OnPathChallengeFrame(const QuicPathChallengeFrame& frame) { // PATH_RESPONSE. This context needs to be out of scope before returning. // TODO(danzh) inline OnPathChallengeFrameInternal() once // support_reverse_path_validation_ is deprecated. - QuicPacketCreator::ScopedPeerAddressContext context( - &packet_creator_, last_packet_source_address_); + auto context = + group_path_response_and_challenge_sending_closer_ + ? nullptr + : std::make_unique<QuicPacketCreator::ScopedPeerAddressContext>( + &packet_creator_, last_packet_source_address_, + /*update_connection_id=*/false); if (!OnPathChallengeFrameInternal(frame)) { return false; } @@ -1695,6 +1788,7 @@ bool QuicConnection::OnPathChallengeFrame(const QuicPathChallengeFrame& frame) { bool QuicConnection::OnPathChallengeFrameInternal( const QuicPathChallengeFrame& frame) { + should_proactively_validate_peer_address_on_path_challenge_ = false; // UpdatePacketContent() may start reverse path validation. if (!UpdatePacketContent(PATH_CHALLENGE_FRAME)) { return false; @@ -1703,6 +1797,35 @@ bool QuicConnection::OnPathChallengeFrameInternal( debug_visitor_->OnPathChallengeFrame(frame); } + std::unique_ptr<QuicPacketCreator::ScopedPeerAddressContext> context; + const QuicSocketAddress current_effective_peer_address = + GetEffectivePeerAddressFromCurrentPacket(); + if (group_path_response_and_challenge_sending_closer_) { + QuicConnectionId client_cid, server_cid; + FindOnPathConnectionIds(last_packet_destination_address_, + current_effective_peer_address, &client_cid, + &server_cid); + context = std::make_unique<QuicPacketCreator::ScopedPeerAddressContext>( + &packet_creator_, last_packet_source_address_, client_cid, server_cid, + connection_migration_use_new_cid_); + } + if (should_proactively_validate_peer_address_on_path_challenge_) { + QUIC_RELOADABLE_FLAG_COUNT( + quic_group_path_response_and_challenge_sending_closer); + // Conditions to proactively validate peer address: + // The perspective is server + // The PATH_CHALLENGE is received on an unvalidated alternative path. + // The connection isn't validating migrated peer address, which is of + // higher prority. + QUIC_DVLOG(1) << "Proactively validate the effective peer address " + << current_effective_peer_address; + QUIC_CODE_COUNT_N(quic_kick_off_client_address_validation, 2, 6); + ValidatePath(std::make_unique<ReversePathValidationContext>( + default_path_.self_address, last_packet_source_address_, + current_effective_peer_address, this), + std::make_unique<ReversePathValidationResultDelegate>( + this, peer_address())); + } if (!send_path_response_) { // Save the path challenge's payload, for later use in generating the // response. @@ -1717,10 +1840,19 @@ bool QuicConnection::OnPathChallengeFrameInternal( // Queue or send PATH_RESPONSE. Send PATH_RESPONSE to the source address of // the current incoming packet, even if it's not the default path or the // alternative path. - if (!SendPathResponse(frame.data_buffer, last_packet_source_address_)) { - // Queue the payloads to re-try later. - pending_path_challenge_payloads_.push_back( - {frame.data_buffer, last_packet_source_address_}); + const bool success = + SendPathResponse(frame.data_buffer, last_packet_source_address_, + current_effective_peer_address); + if (GetQuicReloadableFlag(quic_drop_unsent_path_response)) { + QUIC_RELOADABLE_FLAG_COUNT(quic_drop_unsent_path_response); + } + if (!success) { + QUIC_CODE_COUNT(quic_failed_to_send_path_response); + if (!GetQuicReloadableFlag(quic_drop_unsent_path_response)) { + // Queue the payloads to re-try later. + pending_path_challenge_payloads_.push_back( + {frame.data_buffer, last_packet_source_address_}); + } } // TODO(b/150095588): change the stats to // num_valid_path_challenge_received. @@ -1885,6 +2017,39 @@ bool QuicConnection::OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) { return connected_; } +void QuicConnection::OnClientConnectionIdAvailable() { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_connection_migration_use_new_cid_v2, 3, 5); + QUICHE_DCHECK(perspective_ == Perspective::IS_SERVER); + if (!peer_issued_cid_manager_->HasUnusedConnectionId()) { + return; + } + if (default_path_.client_connection_id.IsEmpty()) { + const QuicConnectionIdData* unused_cid_data = + peer_issued_cid_manager_->ConsumeOneUnusedConnectionId(); + QUIC_DVLOG(1) << ENDPOINT << "Patch connection ID " + << unused_cid_data->connection_id << " to default path"; + default_path_.client_connection_id = unused_cid_data->connection_id; + default_path_.stateless_reset_token_received = true; + default_path_.stateless_reset_token = + unused_cid_data->stateless_reset_token; + QUICHE_DCHECK(!packet_creator_.HasPendingFrames()); + QUICHE_DCHECK(packet_creator_.GetDestinationConnectionId().IsEmpty()); + packet_creator_.SetClientConnectionId(default_path_.client_connection_id); + return; + } + if (alternative_path_.peer_address.IsInitialized() && + alternative_path_.client_connection_id.IsEmpty()) { + const QuicConnectionIdData* unused_cid_data = + peer_issued_cid_manager_->ConsumeOneUnusedConnectionId(); + QUIC_DVLOG(1) << ENDPOINT << "Patch connection ID " + << unused_cid_data->connection_id << " to alternative path"; + alternative_path_.client_connection_id = unused_cid_data->connection_id; + alternative_path_.stateless_reset_token_received = true; + alternative_path_.stateless_reset_token = + unused_cid_data->stateless_reset_token; + } +} + bool QuicConnection::OnNewConnectionIdFrameInner( const QuicNewConnectionIdFrame& frame) { QUICHE_DCHECK(support_multiple_connection_ids_); @@ -1903,7 +2068,11 @@ bool QuicConnection::OnNewConnectionIdFrameInner( ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); return false; } - QUIC_RELOADABLE_FLAG_COUNT_N(quic_connection_support_multiple_cids_v2, 1, 2); + if (use_connection_id_on_default_path_ && + perspective_ == Perspective::IS_SERVER) { + OnClientConnectionIdAvailable(); + } + QUIC_RELOADABLE_FLAG_COUNT_N(quic_connection_support_multiple_cids_v4, 1, 2); return true; } @@ -1939,6 +2108,11 @@ bool QuicConnection::OnRetireConnectionIdFrame( if (debug_visitor_ != nullptr) { debug_visitor_->OnRetireConnectionIdFrame(frame); } + if (use_connection_id_on_default_path_ && + !connection_migration_use_new_cid_) { + // Do not respond to RetireConnectionId frame. + return true; + } if (!support_multiple_connection_ids_) { return true; } @@ -1957,7 +2131,7 @@ bool QuicConnection::OnRetireConnectionIdFrame( ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); return false; } - QUIC_RELOADABLE_FLAG_COUNT_N(quic_connection_support_multiple_cids_v2, 2, 2); + QUIC_RELOADABLE_FLAG_COUNT_N(quic_connection_support_multiple_cids_v4, 2, 2); return true; } @@ -1972,17 +2146,14 @@ bool QuicConnection::OnNewTokenFrame(const QuicNewTokenFrame& frame) { if (debug_visitor_ != nullptr) { debug_visitor_->OnNewTokenFrame(frame); } - if (GetQuicReloadableFlag(quic_enable_token_based_address_validation)) { - if (perspective_ == Perspective::IS_SERVER) { - CloseConnection(QUIC_INVALID_NEW_TOKEN, - "Server received new token frame.", - ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); - return false; - } - // NEW_TOKEN frame should insitgate ACKs. - MaybeUpdateAckTimeout(); - visitor_->OnNewTokenReceived(frame.token); + if (perspective_ == Perspective::IS_SERVER) { + CloseConnection(QUIC_INVALID_NEW_TOKEN, "Server received new token frame.", + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + return false; } + // NEW_TOKEN frame should insitgate ACKs. + MaybeUpdateAckTimeout(); + visitor_->OnNewTokenReceived(frame.token); return true; } @@ -2181,21 +2352,14 @@ void QuicConnection::MaybeRespondToConnectivityProbingOrMigration() { return; } } - // Server starts to migrate connection upon receiving of non-probing packet - // from a new peer address. - if (!start_peer_migration_earlier_ && - last_header_.packet_number == GetLargestReceivedPacket()) { - direct_peer_address_ = last_packet_source_address_; - if (current_effective_peer_migration_type_ != NO_CHANGE) { - // TODO(fayang): When multiple packet number spaces is supported, only - // start peer migration for the application data. - StartEffectivePeerMigration(current_effective_peer_migration_type_); - } - } } bool QuicConnection::IsValidStatelessResetToken( const StatelessResetToken& token) const { + if (use_connection_id_on_default_path_) { + return default_path_.stateless_reset_token_received && + token == default_path_.stateless_reset_token; + } return stateless_reset_token_received_ && token == received_stateless_reset_token_; } @@ -2280,23 +2444,13 @@ void QuicConnection::ClearLastFrames() { } void QuicConnection::CloseIfTooManyOutstandingSentPackets() { - bool should_close; - if (GetQuicReloadableFlag( - quic_close_connection_with_too_many_outstanding_packets)) { - QUIC_RELOADABLE_FLAG_COUNT( - quic_close_connection_with_too_many_outstanding_packets); - should_close = - sent_packet_manager_.GetLargestSentPacket().IsInitialized() && - sent_packet_manager_.GetLargestSentPacket() > - sent_packet_manager_.GetLeastUnacked() + max_tracked_packets_; - } else { - should_close = - sent_packet_manager_.GetLargestObserved().IsInitialized() && - sent_packet_manager_.GetLargestObserved() > - sent_packet_manager_.GetLeastUnacked() + max_tracked_packets_; - } // This occurs if we don't discard old packets we've seen fast enough. It's // possible largest observed is less than leaset unacked. + const bool should_close = + sent_packet_manager_.GetLargestSentPacket().IsInitialized() && + sent_packet_manager_.GetLargestSentPacket() > + sent_packet_manager_.GetLeastUnacked() + max_tracked_packets_; + if (should_close) { CloseConnection( QUIC_TOO_MANY_OUTSTANDING_SENT_PACKETS, @@ -2414,18 +2568,23 @@ QuicConsumedData QuicConnection::SendStreamData(QuicStreamId id, QuicUtils::IsCryptoStreamId(transport_version(), id)) { MaybeActivateLegacyVersionEncapsulation(); } - if (GetQuicReloadableFlag(quic_preempt_stream_data_with_handshake_packet) && - perspective_ == Perspective::IS_SERVER && + if (perspective_ == Perspective::IS_SERVER && version().CanSendCoalescedPackets() && !IsHandshakeConfirmed()) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_preempt_stream_data_with_handshake_packet, - 1, 2); + if (GetQuicReloadableFlag(quic_donot_pto_half_rtt_data)) { + QUIC_RELOADABLE_FLAG_COUNT(quic_donot_pto_half_rtt_data); + if (in_on_retransmission_time_out_ && + coalesced_packet_.NumberOfPackets() == 0u) { + // PTO fires while handshake is not confirmed. Do not preempt handshake + // data with stream data. + QUIC_CODE_COUNT(quic_try_to_send_half_rtt_data_when_pto_fires); + return QuicConsumedData(0, false); + } + } if (coalesced_packet_.ContainsPacketOfEncryptionLevel(ENCRYPTION_INITIAL) && coalesced_packet_.NumberOfPackets() == 1u) { // Handshake is not confirmed yet, if there is only an initial packet in // the coalescer, try to bundle an ENCRYPTION_HANDSHAKE packet before // sending stream data. - QUIC_RELOADABLE_FLAG_COUNT_N( - quic_preempt_stream_data_with_handshake_packet, 2, 2); sent_packet_manager_.RetransmitDataOfSpaceIfAny(HANDSHAKE_DATA); } } @@ -2510,8 +2669,8 @@ const QuicConnectionStats& QuicConnection::GetStats() { stats_.estimated_bandwidth = sent_packet_manager_.BandwidthEstimate(); sent_packet_manager_.GetSendAlgorithm()->PopulateConnectionStats(&stats_); - stats_.max_packet_size = packet_creator_.max_packet_length(); - stats_.max_received_packet_size = largest_received_packet_size_; + stats_.egress_mtu = long_term_mtu_; + stats_.ingress_mtu = largest_received_packet_size_; return stats_; } @@ -2745,6 +2904,7 @@ void QuicConnection::ProcessUdpPacket(const QuicSocketAddress& self_address, MaybeSendInResponseToPacket(); } SetPingAlarm(); + RetirePeerIssuedConnectionIdsNoLongerOnPath(); current_packet_data_ = nullptr; is_current_packet_connectivity_probing_ = false; } @@ -2789,8 +2949,12 @@ void QuicConnection::OnCanWrite() { QUIC_RELOADABLE_FLAG_COUNT_N(quic_send_path_response2, 4, 5); const PendingPathChallenge& pending_path_challenge = pending_path_challenge_payloads_.front(); + // Note connection_migration_use_cid_ will depends on + // quic_drop_unsent_path_response flag eventually, and hence the empty + // effective_peer_address here will not be used. if (!SendPathResponse(pending_path_challenge.received_path_challenge, - pending_path_challenge.peer_address)) { + pending_path_challenge.peer_address, + /*effective_peer_address=*/QuicSocketAddress())) { break; } pending_path_challenge_payloads_.pop_front(); @@ -2826,6 +2990,17 @@ void QuicConnection::WriteIfNotBlocked() { } } +void QuicConnection::SetServerConnectionId( + const QuicConnectionId& server_connection_id) { + if (use_connection_id_on_default_path_) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_use_connection_id_on_default_path_v2, 2, + 3); + default_path_.server_connection_id = server_connection_id; + } else { + server_connection_id_ = server_connection_id; + } +} + void QuicConnection::ReplaceInitialServerConnectionId( const QuicConnectionId& new_server_connection_id) { QUICHE_DCHECK(perspective_ == Perspective::IS_CLIENT); @@ -2836,10 +3011,10 @@ void QuicConnection::ReplaceInitialServerConnectionId( if (peer_issued_cid_manager_ != nullptr) { QUIC_BUG_IF(quic_bug_12714_22, !peer_issued_cid_manager_->IsConnectionIdActive( - server_connection_id_)) + ServerConnectionId())) << "Connection ID replaced header is no longer active. old id: " - << server_connection_id_ << " new_id: " << new_server_connection_id; - peer_issued_cid_manager_->ReplaceConnectionId(server_connection_id_, + << ServerConnectionId() << " new_id: " << new_server_connection_id; + peer_issued_cid_manager_->ReplaceConnectionId(ServerConnectionId(), new_server_connection_id); } else { peer_issued_cid_manager_ = @@ -2849,8 +3024,74 @@ void QuicConnection::ReplaceInitialServerConnectionId( } } } - server_connection_id_ = new_server_connection_id; - packet_creator_.SetServerConnectionId(server_connection_id_); + SetServerConnectionId(new_server_connection_id); + packet_creator_.SetServerConnectionId(ServerConnectionId()); +} + +void QuicConnection::FindMatchingOrNewClientConnectionIdOrToken( + const PathState& default_path, + const PathState& alternative_path, + const QuicConnectionId& server_connection_id, + QuicConnectionId* client_connection_id, + bool* stateless_reset_token_received, + StatelessResetToken* stateless_reset_token) { + if (!use_connection_id_on_default_path_) { + return; + } + QUICHE_DCHECK(perspective_ == Perspective::IS_SERVER); + if (peer_issued_cid_manager_ == nullptr || + server_connection_id == default_path.server_connection_id) { + *client_connection_id = default_path.client_connection_id; + *stateless_reset_token_received = + default_path.stateless_reset_token_received; + *stateless_reset_token = default_path.stateless_reset_token; + return; + } + if (server_connection_id == alternative_path_.server_connection_id) { + *client_connection_id = alternative_path.client_connection_id; + *stateless_reset_token_received = + alternative_path.stateless_reset_token_received; + *stateless_reset_token = alternative_path.stateless_reset_token; + return; + } + if (!connection_migration_use_new_cid_) { + QUIC_BUG(quic_bug_46004) << "Cannot find matching connection ID."; + return; + } + auto* connection_id_data = + peer_issued_cid_manager_->ConsumeOneUnusedConnectionId(); + if (connection_id_data == nullptr) { + return; + } + *client_connection_id = connection_id_data->connection_id; + *stateless_reset_token = connection_id_data->stateless_reset_token; + *stateless_reset_token_received = true; +} + +bool QuicConnection::FindOnPathConnectionIds( + const QuicSocketAddress& self_address, + const QuicSocketAddress& peer_address, + QuicConnectionId* client_connection_id, + QuicConnectionId* server_connection_id) const { + if (IsDefaultPath(self_address, peer_address)) { + *client_connection_id = default_path_.client_connection_id, + *server_connection_id = default_path_.server_connection_id; + return true; + } + if (IsAlternativePath(self_address, peer_address)) { + *client_connection_id = alternative_path_.client_connection_id, + *server_connection_id = alternative_path_.server_connection_id; + return true; + } + return false; +} + +void QuicConnection::SetDefaultPathState(PathState new_path_state) { + default_path_ = std::move(new_path_state); + if (connection_migration_use_new_cid_) { + packet_creator_.SetClientConnectionId(default_path_.client_connection_id); + packet_creator_.SetServerConnectionId(default_path_.server_connection_id); + } } bool QuicConnection::ProcessValidatedPacket(const QuicPacketHeader& header) { @@ -2885,21 +3126,21 @@ bool QuicConnection::ProcessValidatedPacket(const QuicPacketHeader& header) { default_path_.self_address = last_packet_destination_address_; } - if (PacketCanReplaceConnectionId(header, perspective_) && - server_connection_id_ != header.source_connection_id) { + if (PacketCanReplaceServerConnectionId(header, perspective_) && + ServerConnectionId() != header.source_connection_id) { QUICHE_DCHECK_EQ(header.long_packet_type, INITIAL); if (server_connection_id_replaced_by_initial_) { QUIC_DLOG(ERROR) << ENDPOINT << "Refusing to replace connection ID " - << server_connection_id_ << " with " + << ServerConnectionId() << " with " << header.source_connection_id; return false; } server_connection_id_replaced_by_initial_ = true; QUIC_DLOG(INFO) << ENDPOINT << "Replacing connection ID " - << server_connection_id_ << " with " + << ServerConnectionId() << " with " << header.source_connection_id; if (!original_destination_connection_id_.has_value()) { - original_destination_connection_id_ = server_connection_id_; + original_destination_connection_id_ = ServerConnectionId(); } ReplaceInitialServerConnectionId(header.source_connection_id); } @@ -3039,6 +3280,15 @@ bool QuicConnection::ShouldGeneratePacket( QuicVersionUsesCryptoFrames(transport_version())) << ENDPOINT << "Handshake in STREAM frames should not check ShouldGeneratePacket"; + if (support_multiple_connection_ids_ && peer_issued_cid_manager_ != nullptr && + packet_creator_.GetDestinationConnectionId().IsEmpty()) { + QUIC_CODE_COUNT(quic_generate_packet_blocked_by_no_connection_id); + QUIC_BUG_IF(quic_bug_90265_1, perspective_ == Perspective::IS_CLIENT); + QUIC_DLOG(INFO) << ENDPOINT + << "There is no destination connection ID available to " + "generate packet."; + return false; + } if (!count_bytes_on_alternative_path_separately_) { return CanWrite(retransmittable); } @@ -3319,7 +3569,7 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) { legacy_version_encapsulation_sni_, absl::string_view(packet->encrypted_buffer, packet->encrypted_length), - server_connection_id_, framer_.creation_time(), + ServerConnectionId(), framer_.creation_time(), GetLimitedMaxPacketSize(long_term_mtu_), const_cast<char*>(packet->encrypted_buffer)); if (encapsulated_length != 0) { @@ -3514,6 +3764,7 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) { SetRetransmissionAlarm(); } SetPingAlarm(); + RetirePeerIssuedConnectionIdsNoLongerOnPath(); // The packet number length must be updated after OnPacketSent, because it // may change the packet number length in packet. @@ -3827,13 +4078,13 @@ void QuicConnection::OnPathMtuIncreased(QuicPacketLength packet_size) { std::unique_ptr<QuicSelfIssuedConnectionIdManager> QuicConnection::MakeSelfIssuedConnectionIdManager() { QUICHE_DCHECK((perspective_ == Perspective::IS_CLIENT && - !client_connection_id_.IsEmpty()) || + !ClientConnectionId().IsEmpty()) || (perspective_ == Perspective::IS_SERVER && - !server_connection_id_.IsEmpty())); + !ServerConnectionId().IsEmpty())); return std::make_unique<QuicSelfIssuedConnectionIdManager>( kMinNumOfActiveConnectionIds, - perspective_ == Perspective::IS_CLIENT ? client_connection_id_ - : server_connection_id_, + perspective_ == Perspective::IS_CLIENT ? ClientConnectionId() + : ServerConnectionId(), clock_, alarm_factory_, this); } @@ -3847,6 +4098,11 @@ void QuicConnection::MaybeSendConnectionIdToClient() { void QuicConnection::OnHandshakeComplete() { sent_packet_manager_.SetHandshakeConfirmed(); + if (connection_migration_use_new_cid_ && + perspective_ == Perspective::IS_SERVER && + self_issued_cid_manager_ != nullptr) { + self_issued_cid_manager_->MaybeSendNewConnectionIds(); + } if (send_ack_frequency_on_handshake_completion_ && sent_packet_manager_.CanSendAckFrequency()) { QUIC_RELOADABLE_FLAG_COUNT_N(quic_can_send_ack_frequency, 2, 3); @@ -3926,6 +4182,7 @@ void QuicConnection::SendAck() { } void QuicConnection::OnRetransmissionTimeout() { + ScopedRetransmissionTimeoutIndicator indicator(this); #ifndef NDEBUG if (sent_packet_manager_.unacked_packets().empty()) { QUICHE_DCHECK(sent_packet_manager_.handshake_mode_disabled()); @@ -4309,8 +4566,9 @@ void QuicConnection::SendConnectionClosePacket( QuicIetfTransportErrorCodes ietf_error, const std::string& details) { // Always use the current path to send CONNECTION_CLOSE. - QuicPacketCreator::ScopedPeerAddressContext context(&packet_creator_, - peer_address()); + QuicPacketCreator::ScopedPeerAddressContext context( + &packet_creator_, peer_address(), default_path_.client_connection_id, + default_path_.server_connection_id, connection_migration_use_new_cid_); if (!SupportsMultiplePacketNumberSpaces()) { QUIC_DLOG(INFO) << ENDPOINT << "Sending connection close packet."; if (!use_encryption_level_context_) { @@ -4472,6 +4730,7 @@ QuicByteCount QuicConnection::max_packet_length() const { void QuicConnection::SetMaxPacketLength(QuicByteCount length) { long_term_mtu_ = length; + stats_.max_egress_mtu = std::max(stats_.max_egress_mtu, long_term_mtu_); MaybeUpdatePacketCreatorMaxPacketLengthAndPadding(); } @@ -4838,7 +5097,7 @@ bool QuicConnection::SendGenericPathProbePacket( QUIC_DLOG(INFO) << ENDPOINT << "Sending path probe packet for connection_id = " - << server_connection_id_; + << ServerConnectionId(); std::unique_ptr<SerializedPacket> probing_packet; if (!version().HasIetfQuicFrames()) { @@ -4883,7 +5142,7 @@ bool QuicConnection::WritePacketUsingWriter( const QuicTime packet_send_time = clock_->Now(); QUIC_DVLOG(2) << ENDPOINT << "Sending path probe packet for server connection ID " - << server_connection_id_ << std::endl + << ServerConnectionId() << std::endl << quiche::QuicheTextUtils::HexDump(absl::string_view( packet->encrypted_buffer, packet->encrypted_length)); WriteResult result = writer->WritePacket( @@ -5083,10 +5342,19 @@ void QuicConnection::StartEffectivePeerMigration(AddressChangeType type) { // Update the default path. if (IsAlternativePath(last_packet_destination_address_, current_effective_peer_address)) { - default_path_ = std::move(alternative_path_); + SetDefaultPathState(std::move(alternative_path_)); } else { - default_path_ = PathState(last_packet_destination_address_, - current_effective_peer_address); + QuicConnectionId client_connection_id; + bool stateless_reset_token_received = false; + StatelessResetToken stateless_reset_token; + FindMatchingOrNewClientConnectionIdOrToken( + previous_default_path, alternative_path_, + last_packet_destination_connection_id_, &client_connection_id, + &stateless_reset_token_received, &stateless_reset_token); + SetDefaultPathState(PathState( + last_packet_destination_address_, current_effective_peer_address, + client_connection_id, last_packet_destination_connection_id_, + stateless_reset_token_received, stateless_reset_token)); // The path is considered validated if its peer IP address matches any // validated path's peer IP address. default_path_.validated = @@ -5293,8 +5561,17 @@ bool QuicConnection::UpdatePacketContent(QuicFrameType type) { << current_effective_peer_address << ", self address " << last_packet_destination_address_; if (!validate_client_addresses_) { - alternative_path_ = PathState(last_packet_destination_address_, - current_effective_peer_address); + QuicConnectionId client_cid; + bool stateless_reset_token_received = false; + StatelessResetToken stateless_reset_token; + FindMatchingOrNewClientConnectionIdOrToken( + default_path_, alternative_path_, + last_packet_destination_connection_id_, &client_cid, + &stateless_reset_token_received, &stateless_reset_token); + alternative_path_ = PathState( + last_packet_destination_address_, current_effective_peer_address, + client_cid, last_packet_destination_connection_id_, + stateless_reset_token_received, stateless_reset_token); } else if (!default_path_.validated) { QUIC_CODE_COUNT_N(quic_server_reverse_validate_new_path3, 4, 6); // Skip reverse path validation because either handshake hasn't @@ -5311,24 +5588,38 @@ bool QuicConnection::UpdatePacketContent(QuicFrameType type) { << "No validated peer address to send after handshake comfirmed."; } else if (!IsReceivedPeerAddressValidated()) { QUIC_CODE_COUNT_N(quic_server_reverse_validate_new_path3, 5, 6); + QuicConnectionId client_connection_id; + bool stateless_reset_token_received; + StatelessResetToken stateless_reset_token; + FindMatchingOrNewClientConnectionIdOrToken( + default_path_, alternative_path_, + last_packet_destination_connection_id_, &client_connection_id, + &stateless_reset_token_received, &stateless_reset_token); // Only override alternative path state upon receiving a PATH_CHALLENGE // from an unvalidated peer address, and the connection isn't validating // a recent peer migration. - alternative_path_ = PathState(last_packet_destination_address_, - current_effective_peer_address); - // Conditions to proactively validate peer address: - // The perspective is server - // The PATH_CHALLENGE is received on an unvalidated alternative path. - // The connection isn't validating migrated peer address, which is of - // higher prority. - QUIC_DVLOG(1) << "Proactively validate the effective peer address " - << current_effective_peer_address; - ValidatePath( - std::make_unique<ReversePathValidationContext>( - default_path_.self_address, current_effective_peer_address, - current_effective_peer_address, this), - std::make_unique<ReversePathValidationResultDelegate>( - this, peer_address())); + alternative_path_ = PathState( + last_packet_destination_address_, current_effective_peer_address, + client_connection_id, last_packet_destination_connection_id_, + stateless_reset_token_received, stateless_reset_token); + if (group_path_response_and_challenge_sending_closer_) { + should_proactively_validate_peer_address_on_path_challenge_ = true; + } else { + // Conditions to proactively validate peer address: + // The perspective is server + // The PATH_CHALLENGE is received on an unvalidated alternative path. + // The connection isn't validating migrated peer address, which is of + // higher prority. + QUIC_DVLOG(1) << "Proactively validate the effective peer address " + << current_effective_peer_address; + QUIC_CODE_COUNT_N(quic_kick_off_client_address_validation, 1, 6); + ValidatePath( + std::make_unique<ReversePathValidationContext>( + default_path_.self_address, last_packet_source_address_, + current_effective_peer_address, this), + std::make_unique<ReversePathValidationResultDelegate>( + this, peer_address())); + } } } MaybeUpdateBytesReceivedFromAlternativeAddress(last_size_); @@ -5398,10 +5689,6 @@ bool QuicConnection::UpdatePacketContent(QuicFrameType type) { void QuicConnection::MaybeStartIetfPeerMigration() { QUICHE_DCHECK(version().HasIetfQuicFrames()); - if (!start_peer_migration_earlier_) { - return; - } - QUIC_CODE_COUNT(quic_start_peer_migration_earlier); if (current_effective_peer_migration_type_ != NO_CHANGE && !IsHandshakeConfirmed()) { QUIC_LOG_EVERY_N_SEC(INFO, 60) @@ -5970,14 +6257,21 @@ void QuicConnection::set_client_connection_id( << client_connection_id << " with unsupported version " << version(); return; } - client_connection_id_ = client_connection_id; + if (use_connection_id_on_default_path_) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_use_connection_id_on_default_path_v2, 1, + 3); + default_path_.client_connection_id = client_connection_id; + } else { + client_connection_id_ = client_connection_id; + } + client_connection_id_is_set_ = true; - if (support_multiple_connection_ids_ && !client_connection_id_.IsEmpty()) { + if (support_multiple_connection_ids_ && !client_connection_id.IsEmpty()) { if (perspective_ == Perspective::IS_SERVER) { QUICHE_DCHECK(peer_issued_cid_manager_ == nullptr); peer_issued_cid_manager_ = std::make_unique<QuicPeerIssuedConnectionIdManager>( - kMinNumOfActiveConnectionIds, client_connection_id_, clock_, + kMinNumOfActiveConnectionIds, client_connection_id, clock_, alarm_factory_, this); } else { // Note in Chromium client, set_client_connection_id is not called and @@ -5986,11 +6280,11 @@ void QuicConnection::set_client_connection_id( } } QUIC_DLOG(INFO) << ENDPOINT << "setting client connection ID to " - << client_connection_id_ + << ClientConnectionId() << " for connection with server connection ID " - << server_connection_id_; - packet_creator_.SetClientConnectionId(client_connection_id_); - framer_.SetExpectedClientConnectionIdLength(client_connection_id_.length()); + << ServerConnectionId(); + packet_creator_.SetClientConnectionId(ClientConnectionId()); + framer_.SetExpectedClientConnectionIdLength(ClientConnectionId().length()); } void QuicConnection::OnPathDegradingDetected() { @@ -6069,12 +6363,21 @@ void QuicConnection::OnIdleNetworkDetected() { void QuicConnection::OnPeerIssuedConnectionIdRetired() { QUICHE_DCHECK(peer_issued_cid_manager_ != nullptr); QuicConnectionId* default_path_cid = perspective_ == Perspective::IS_CLIENT - ? &server_connection_id_ - : &client_connection_id_; + ? &ServerConnectionId() + : &ClientConnectionId(); + QuicConnectionId* alternative_path_cid = + perspective_ == Perspective::IS_CLIENT + ? &alternative_path_.server_connection_id + : &alternative_path_.client_connection_id; + bool default_path_and_alternative_path_use_the_same_peer_connection_id = + *default_path_cid == *alternative_path_cid; if (!default_path_cid->IsEmpty() && !peer_issued_cid_manager_->IsConnectionIdActive(*default_path_cid)) { *default_path_cid = QuicConnectionId(); } + // TODO(haoyuewang) Handle the change for default_path_ & alternatvie_path_ + // via the same helper function after use_connection_id_on_default_path_ is + // default true. if (default_path_cid->IsEmpty()) { // Try setting a new connection ID now such that subsequent // RetireConnectionId frames can be sent on the default path. @@ -6082,9 +6385,15 @@ void QuicConnection::OnPeerIssuedConnectionIdRetired() { peer_issued_cid_manager_->ConsumeOneUnusedConnectionId(); if (unused_connection_id_data != nullptr) { *default_path_cid = unused_connection_id_data->connection_id; - received_stateless_reset_token_ = - unused_connection_id_data->stateless_reset_token; - stateless_reset_token_received_ = true; + if (use_connection_id_on_default_path_) { + default_path_.stateless_reset_token = + unused_connection_id_data->stateless_reset_token; + default_path_.stateless_reset_token_received = true; + } else { + received_stateless_reset_token_ = + unused_connection_id_data->stateless_reset_token; + stateless_reset_token_received_ = true; + } if (perspective_ == Perspective::IS_CLIENT) { packet_creator_.SetServerConnectionId( unused_connection_id_data->connection_id); @@ -6094,32 +6403,56 @@ void QuicConnection::OnPeerIssuedConnectionIdRetired() { } } } + if (use_connection_id_on_default_path_) { + if (default_path_and_alternative_path_use_the_same_peer_connection_id) { + *alternative_path_cid = *default_path_cid; + alternative_path_.stateless_reset_token_received = + default_path_.stateless_reset_token_received; + alternative_path_.stateless_reset_token = + default_path_.stateless_reset_token; + } else if (!alternative_path_cid->IsEmpty() && + !peer_issued_cid_manager_->IsConnectionIdActive( + *alternative_path_cid)) { + *alternative_path_cid = EmptyQuicConnectionId(); + const QuicConnectionIdData* unused_connection_id_data = + peer_issued_cid_manager_->ConsumeOneUnusedConnectionId(); + if (unused_connection_id_data != nullptr) { + *alternative_path_cid = unused_connection_id_data->connection_id; + alternative_path_.stateless_reset_token = + unused_connection_id_data->stateless_reset_token; + alternative_path_.stateless_reset_token_received = true; + } + } + } std::vector<uint64_t> retired_cid_sequence_numbers = peer_issued_cid_manager_->ConsumeToBeRetiredConnectionIdSequenceNumbers(); QUICHE_DCHECK(!retired_cid_sequence_numbers.empty()); for (const auto& sequence_number : retired_cid_sequence_numbers) { + ++stats_.num_retire_connection_id_sent; visitor_->SendRetireConnectionId(sequence_number); } } bool QuicConnection::SendNewConnectionId( const QuicNewConnectionIdFrame& frame) { - QUICHE_DCHECK(perspective_ == Perspective::IS_SERVER); visitor_->SendNewConnectionId(frame); + ++stats_.num_new_connection_id_sent; return connected_; } void QuicConnection::OnNewConnectionIdIssued( const QuicConnectionId& connection_id) { - QUICHE_DCHECK(perspective_ == Perspective::IS_SERVER); - visitor_->OnServerConnectionIdIssued(connection_id); + if (perspective_ == Perspective::IS_SERVER) { + visitor_->OnServerConnectionIdIssued(connection_id); + } } void QuicConnection::OnSelfIssuedConnectionIdRetired( const QuicConnectionId& connection_id) { - QUICHE_DCHECK(perspective_ == Perspective::IS_SERVER); - visitor_->OnServerConnectionIdRetired(connection_id); + if (perspective_ == Perspective::IS_SERVER) { + visitor_->OnServerConnectionIdRetired(connection_id); + } } void QuicConnection::MaybeUpdateAckTimeout() { @@ -6197,15 +6530,41 @@ bool QuicConnection::SendPathChallenge( const QuicPathFrameBuffer& data_buffer, const QuicSocketAddress& self_address, const QuicSocketAddress& peer_address, - const QuicSocketAddress& /*effective_peer_address*/, + const QuicSocketAddress& effective_peer_address, QuicPacketWriter* writer) { + if (connection_migration_use_new_cid_) { + { + QuicConnectionId client_cid, server_cid; + FindOnPathConnectionIds(self_address, effective_peer_address, &client_cid, + &server_cid); + QuicPacketCreator::ScopedPeerAddressContext context( + &packet_creator_, peer_address, client_cid, server_cid, + connection_migration_use_new_cid_); + if (writer == writer_) { + ScopedPacketFlusher flusher(this); + // It's on current path, add the PATH_CHALLENGE the same way as other + // frames. This may cause connection to be closed. + packet_creator_.AddPathChallengeFrame(data_buffer); + } else { + std::unique_ptr<SerializedPacket> probing_packet = + packet_creator_.SerializePathChallengeConnectivityProbingPacket( + data_buffer); + QUICHE_DCHECK_EQ(IsRetransmittable(*probing_packet), + NO_RETRANSMITTABLE_DATA); + QUICHE_DCHECK_EQ(self_address, alternative_path_.self_address); + WritePacketUsingWriter(std::move(probing_packet), writer, self_address, + peer_address, /*measure_rtt=*/false); + } + } + return connected_; + } if (writer == writer_) { ScopedPacketFlusher flusher(this); { // It's on current path, add the PATH_CHALLENGE the same way as other // frames. - QuicPacketCreator::ScopedPeerAddressContext context(&packet_creator_, - peer_address); + QuicPacketCreator::ScopedPeerAddressContext context( + &packet_creator_, peer_address, /*update_connection_id=*/false); // This may cause connection to be closed. packet_creator_.AddPathChallengeFrame(data_buffer); } @@ -6236,26 +6595,75 @@ void QuicConnection::ValidatePath( std::unique_ptr<QuicPathValidationContext> context, std::unique_ptr<QuicPathValidator::ResultDelegate> result_delegate) { QUICHE_DCHECK(use_path_validator_); - if (perspective_ == Perspective::IS_CLIENT && + if (!connection_migration_use_new_cid_ && + perspective_ == Perspective::IS_CLIENT && !IsDefaultPath(context->self_address(), context->peer_address())) { - alternative_path_ = - PathState(context->self_address(), context->peer_address()); + alternative_path_ = PathState( + context->self_address(), context->peer_address(), + default_path_.client_connection_id, default_path_.server_connection_id, + default_path_.stateless_reset_token_received, + default_path_.stateless_reset_token); } if (path_validator_.HasPendingPathValidation()) { // Cancel and fail any earlier validation. path_validator_.CancelPathValidation(); } + if (connection_migration_use_new_cid_ && + perspective_ == Perspective::IS_CLIENT && + !IsDefaultPath(context->self_address(), context->peer_address())) { + if (self_issued_cid_manager_ != nullptr) { + self_issued_cid_manager_->MaybeSendNewConnectionIds(); + if (!connected_) { + return; + } + } + if ((self_issued_cid_manager_ != nullptr && + !self_issued_cid_manager_->HasConnectionIdToConsume()) || + (peer_issued_cid_manager_ != nullptr && + !peer_issued_cid_manager_->HasUnusedConnectionId())) { + QUIC_DVLOG(1) << "Client cannot start new path validation as there is no " + "requried connection ID is available."; + result_delegate->OnPathValidationFailure(std::move(context)); + return; + } + QuicConnectionId client_connection_id, server_connection_id; + StatelessResetToken stateless_reset_token; + bool stateless_reset_token_received = false; + if (self_issued_cid_manager_ != nullptr) { + client_connection_id = + *self_issued_cid_manager_->ConsumeOneConnectionId(); + } + if (peer_issued_cid_manager_ != nullptr) { + const auto* connection_id_data = + peer_issued_cid_manager_->ConsumeOneUnusedConnectionId(); + server_connection_id = connection_id_data->connection_id; + stateless_reset_token_received = true; + stateless_reset_token = connection_id_data->stateless_reset_token; + } + alternative_path_ = + PathState(context->self_address(), context->peer_address(), + client_connection_id, server_connection_id, + stateless_reset_token_received, stateless_reset_token); + } path_validator_.StartPathValidation(std::move(context), std::move(result_delegate)); } -bool QuicConnection::SendPathResponse(const QuicPathFrameBuffer& data_buffer, - QuicSocketAddress peer_address_to_send) { +bool QuicConnection::SendPathResponse( + const QuicPathFrameBuffer& data_buffer, + const QuicSocketAddress& peer_address_to_send, + const QuicSocketAddress& effective_peer_address) { + QuicConnectionId client_cid, server_cid; + if (connection_migration_use_new_cid_) { + FindOnPathConnectionIds(last_packet_destination_address_, + effective_peer_address, &client_cid, &server_cid); + } // Send PATH_RESPONSE using the provided peer address. If the creator has been // using a different peer address, it will flush before and after serializing // the current PATH_RESPONSE. - QuicPacketCreator::ScopedPeerAddressContext context(&packet_creator_, - peer_address_to_send); + QuicPacketCreator::ScopedPeerAddressContext context( + &packet_creator_, peer_address_to_send, client_cid, server_cid, + connection_migration_use_new_cid_); QUIC_DVLOG(1) << ENDPOINT << "Send PATH_RESPONSE to " << peer_address_to_send; if (default_path_.self_address == last_packet_destination_address_) { // The PATH_CHALLENGE is received on the default socket. Respond on the same @@ -6315,12 +6723,84 @@ void QuicConnection::CancelPathValidation() { path_validator_.CancelPathValidation(); } -void QuicConnection::MigratePath(const QuicSocketAddress& self_address, +bool QuicConnection::UpdateConnectionIdsOnClientMigration( + const QuicSocketAddress& self_address, + const QuicSocketAddress& peer_address) { + QUICHE_DCHECK(perspective_ == Perspective::IS_CLIENT); + if (IsAlternativePath(self_address, peer_address)) { + // Client migration is after path validation. + default_path_.client_connection_id = alternative_path_.client_connection_id; + default_path_.server_connection_id = alternative_path_.server_connection_id; + default_path_.stateless_reset_token = + alternative_path_.stateless_reset_token; + default_path_.stateless_reset_token_received = + alternative_path_.stateless_reset_token_received; + return true; + } + // Client migration is without path validation. + if (self_issued_cid_manager_ != nullptr) { + self_issued_cid_manager_->MaybeSendNewConnectionIds(); + if (!connected_) { + return false; + } + } + if ((self_issued_cid_manager_ != nullptr && + !self_issued_cid_manager_->HasConnectionIdToConsume()) || + (peer_issued_cid_manager_ != nullptr && + !peer_issued_cid_manager_->HasUnusedConnectionId())) { + return false; + } + if (self_issued_cid_manager_ != nullptr) { + default_path_.client_connection_id = + *self_issued_cid_manager_->ConsumeOneConnectionId(); + } + if (peer_issued_cid_manager_ != nullptr) { + const auto* connection_id_data = + peer_issued_cid_manager_->ConsumeOneUnusedConnectionId(); + default_path_.server_connection_id = connection_id_data->connection_id; + default_path_.stateless_reset_token_received = true; + default_path_.stateless_reset_token = + connection_id_data->stateless_reset_token; + } + return true; +} + +void QuicConnection::RetirePeerIssuedConnectionIdsNoLongerOnPath() { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_connection_migration_use_new_cid_v2, 4, 5); + if (!connection_migration_use_new_cid_ || + peer_issued_cid_manager_ == nullptr) { + return; + } + if (perspective_ == Perspective::IS_CLIENT) { + peer_issued_cid_manager_->MaybeRetireUnusedConnectionIds( + {default_path_.server_connection_id, + alternative_path_.server_connection_id}); + } else { + peer_issued_cid_manager_->MaybeRetireUnusedConnectionIds( + {default_path_.client_connection_id, + alternative_path_.client_connection_id}); + } +} + +bool QuicConnection::MigratePath(const QuicSocketAddress& self_address, const QuicSocketAddress& peer_address, QuicPacketWriter* writer, bool owns_writer) { if (!connected_) { - return; + return false; + } + QUICHE_DCHECK(!version().UsesHttp3() || IsHandshakeConfirmed()); + + if (connection_migration_use_new_cid_) { + if (!UpdateConnectionIdsOnClientMigration(self_address, peer_address)) { + return false; + } + if (packet_creator_.GetServerConnectionId().length() != + default_path_.server_connection_id.length()) { + packet_creator_.FlushCurrentPacket(); + } + packet_creator_.SetClientConnectionId(default_path_.client_connection_id); + packet_creator_.SetServerConnectionId(default_path_.server_connection_id); } const auto self_address_change_type = QuicUtils::DetermineAddressChangeType( @@ -6337,13 +6817,21 @@ void QuicConnection::MigratePath(const QuicSocketAddress& self_address, UpdatePeerAddress(peer_address); SetQuicPacketWriter(writer, owns_writer); OnSuccessfulMigration(is_port_change); + return true; +} + +void QuicConnection::OnPathValidationFailureAtClient() { + if (connection_migration_use_new_cid_) { + QUICHE_DCHECK(perspective_ == Perspective::IS_CLIENT); + alternative_path_.Clear(); + } } std::vector<QuicConnectionId> QuicConnection::GetActiveServerConnectionIds() const { if (!support_multiple_connection_ids_ || self_issued_cid_manager_ == nullptr) { - return {server_connection_id_}; + return {ServerConnectionId()}; } return self_issued_cid_manager_->GetUnretiredConnectionIds(); } @@ -6354,14 +6842,14 @@ void QuicConnection::CreateConnectionIdManager() { } if (perspective_ == Perspective::IS_CLIENT) { - if (!server_connection_id_.IsEmpty()) { + if (!ServerConnectionId().IsEmpty()) { peer_issued_cid_manager_ = std::make_unique<QuicPeerIssuedConnectionIdManager>( - kMinNumOfActiveConnectionIds, server_connection_id_, clock_, + kMinNumOfActiveConnectionIds, ServerConnectionId(), clock_, alarm_factory_, this); } } else { - if (!server_connection_id_.IsEmpty()) { + if (!ServerConnectionId().IsEmpty()) { self_issued_cid_manager_ = MakeSelfIssuedConnectionIdManager(); } } @@ -6450,6 +6938,9 @@ bool QuicConnection::IsAlternativePath( void QuicConnection::PathState::Clear() { self_address = QuicSocketAddress(); peer_address = QuicSocketAddress(); + client_connection_id = {}; + server_connection_id = {}; + stateless_reset_token_received = false; validated = false; bytes_received_before_address_validation = 0; bytes_sent_before_address_validation = 0; @@ -6466,6 +6957,10 @@ QuicConnection::PathState& QuicConnection::PathState::operator=( if (this != &other) { self_address = other.self_address; peer_address = other.peer_address; + client_connection_id = other.client_connection_id; + server_connection_id = other.server_connection_id; + stateless_reset_token_received = other.stateless_reset_token_received; + stateless_reset_token = other.stateless_reset_token; validated = other.validated; bytes_received_before_address_validation = other.bytes_received_before_address_validation; @@ -6508,10 +7003,12 @@ void QuicConnection::ReversePathValidationResultDelegate:: QUIC_DLOG(INFO) << "Successfully validated new path " << *context; if (connection_->IsDefaultPath(context->self_address(), context->peer_address())) { + QUIC_CODE_COUNT_N(quic_kick_off_client_address_validation, 3, 6); connection_->OnEffectivePeerMigrationValidated(); } else { QUICHE_DCHECK(connection_->IsAlternativePath( context->self_address(), context->effective_peer_address())); + QUIC_CODE_COUNT_N(quic_kick_off_client_address_validation, 4, 6); QUIC_DVLOG(1) << "Mark alternative peer address " << context->effective_peer_address() << " validated."; connection_->alternative_path_.validated = true; @@ -6528,13 +7025,29 @@ void QuicConnection::ReversePathValidationResultDelegate:: if (connection_->IsDefaultPath(context->self_address(), context->peer_address())) { // Only act upon validation failure on the default path. + QUIC_CODE_COUNT_N(quic_kick_off_client_address_validation, 5, 6); connection_->RestoreToLastValidatedPath(original_direct_peer_address_); } else if (connection_->IsAlternativePath( context->self_address(), context->effective_peer_address())) { + QUIC_CODE_COUNT_N(quic_kick_off_client_address_validation, 6, 6); connection_->alternative_path_.Clear(); } } +QuicConnection::ScopedRetransmissionTimeoutIndicator:: + ScopedRetransmissionTimeoutIndicator(QuicConnection* connection) + : connection_(connection) { + QUICHE_DCHECK(!connection_->in_on_retransmission_time_out_) + << "ScopedRetransmissionTimeoutIndicator is not supposed to be nested"; + connection_->in_on_retransmission_time_out_ = true; +} + +QuicConnection::ScopedRetransmissionTimeoutIndicator:: + ~ScopedRetransmissionTimeoutIndicator() { + QUICHE_DCHECK(connection_->in_on_retransmission_time_out_); + connection_->in_on_retransmission_time_out_ = false; +} + void QuicConnection::RestoreToLastValidatedPath( QuicSocketAddress original_direct_peer_address) { QUIC_DLOG(INFO) << "Switch back to use the old peer address " @@ -6562,7 +7075,7 @@ void QuicConnection::RestoreToLastValidatedPath( } UpdatePeerAddress(original_direct_peer_address); - default_path_ = std::move(alternative_path_); + SetDefaultPathState(std::move(alternative_path_)); active_effective_peer_migration_type_ = NO_CHANGE; ++stats_.num_invalid_peer_migration; 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 e2ba17bd9d8..b9567250637 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 @@ -36,7 +36,6 @@ #include "quic/core/quic_alarm.h" #include "quic/core/quic_alarm_factory.h" #include "quic/core/quic_blocked_writer_interface.h" -#include "quic/core/quic_circular_deque.h" #include "quic/core/quic_connection_id.h" #include "quic/core/quic_connection_id_manager.h" #include "quic/core/quic_connection_stats.h" @@ -58,6 +57,7 @@ #include "quic/platform/api/quic_export.h" #include "quic/platform/api/quic_flags.h" #include "quic/platform/api/quic_socket_address.h" +#include "common/quiche_circular_deque.h" namespace quic { @@ -777,9 +777,9 @@ class QUIC_EXPORT_PRIVATE QuicConnection const QuicSocketAddress& effective_peer_address() const { return default_path_.peer_address; } - QuicConnectionId connection_id() const { return server_connection_id_; } - QuicConnectionId client_connection_id() const { - return client_connection_id_; + const QuicConnectionId& connection_id() const { return ServerConnectionId(); } + const QuicConnectionId& client_connection_id() const { + return ClientConnectionId(); } void set_client_connection_id(QuicConnectionId client_connection_id); const QuicClock* clock() const { return clock_; } @@ -1211,11 +1211,17 @@ class QUIC_EXPORT_PRIVATE QuicConnection void CancelPathValidation(); - void MigratePath(const QuicSocketAddress& self_address, + // Returns true if the migration succeeds, otherwise returns false (e.g., no + // available CIDs, connection disconnected, etc). + bool MigratePath(const QuicSocketAddress& self_address, const QuicSocketAddress& peer_address, QuicPacketWriter* writer, bool owns_writer); + // Called to clear the alternative_path_ when path validation failed on the + // client side. + void OnPathValidationFailureAtClient(); + void SetSourceAddressTokenToSend(absl::string_view token); void SendPing() { @@ -1228,6 +1234,22 @@ class QUIC_EXPORT_PRIVATE QuicConnection bool validate_client_address() const { return validate_client_addresses_; } + bool support_multiple_connection_ids() const { + return support_multiple_connection_ids_; + } + + bool use_connection_id_on_default_path() const { + return use_connection_id_on_default_path_; + } + + bool connection_migration_use_new_cid() const { + return connection_migration_use_new_cid_; + } + + bool count_bytes_on_alternative_path_separately() const { + return count_bytes_on_alternative_path_separately_; + } + // Instantiates connection ID manager. void CreateConnectionIdManager(); @@ -1331,10 +1353,20 @@ class QUIC_EXPORT_PRIVATE QuicConnection }; struct QUIC_EXPORT_PRIVATE PathState { + PathState() = default; + PathState(const QuicSocketAddress& alternative_self_address, - const QuicSocketAddress& alternative_peer_address) + const QuicSocketAddress& alternative_peer_address, + const QuicConnectionId& client_connection_id, + const QuicConnectionId& server_connection_id, + bool stateless_reset_token_received, + StatelessResetToken stateless_reset_token) : self_address(alternative_self_address), - peer_address(alternative_peer_address) {} + peer_address(alternative_peer_address), + client_connection_id(client_connection_id), + server_connection_id(server_connection_id), + stateless_reset_token(stateless_reset_token), + stateless_reset_token_received(stateless_reset_token_received) {} PathState(PathState&& other); @@ -1346,6 +1378,10 @@ class QUIC_EXPORT_PRIVATE QuicConnection QuicSocketAddress self_address; // The actual peer address behind the proxy if there is any. QuicSocketAddress peer_address; + QuicConnectionId client_connection_id; + QuicConnectionId server_connection_id; + StatelessResetToken stateless_reset_token; + bool stateless_reset_token_received = false; // True if the peer address has been validated. Address is considered // validated when 1) an address token of the peer address is received and // validated, or 2) a HANDSHAKE packet has been successfully processed on @@ -1419,6 +1455,41 @@ class QUIC_EXPORT_PRIVATE QuicConnection QuicSocketAddress original_direct_peer_address_; }; + // A class which sets and clears in_on_retransmission_time_out_ when entering + // and exiting OnRetransmissionTimeout, respectively. + class QUIC_EXPORT_PRIVATE ScopedRetransmissionTimeoutIndicator { + public: + // |connection| must outlive this indicator. + explicit ScopedRetransmissionTimeoutIndicator(QuicConnection* connection); + + ~ScopedRetransmissionTimeoutIndicator(); + + private: + QuicConnection* connection_; // Not owned. + }; + + QuicConnectionId& ClientConnectionId() { + return use_connection_id_on_default_path_ + ? default_path_.client_connection_id + : client_connection_id_; + } + const QuicConnectionId& ClientConnectionId() const { + return use_connection_id_on_default_path_ + ? default_path_.client_connection_id + : client_connection_id_; + } + QuicConnectionId& ServerConnectionId() { + return use_connection_id_on_default_path_ + ? default_path_.server_connection_id + : server_connection_id_; + } + const QuicConnectionId& ServerConnectionId() const { + return use_connection_id_on_default_path_ + ? default_path_.server_connection_id + : server_connection_id_; + } + void SetServerConnectionId(const QuicConnectionId& server_connection_id); + // Notifies the visitor of the close and marks the connection as disconnected. // Does not send a connection close frame to the peer. It should only be // called by CloseConnection or OnConnectionCloseFrame, OnPublicResetPacket, @@ -1438,6 +1509,42 @@ class QUIC_EXPORT_PRIVATE QuicConnection void ReplaceInitialServerConnectionId( const QuicConnectionId& new_server_connection_id); + // Given the server_connection_id find if there is already a corresponding + // client connection ID used on default/alternative path. If not, find if + // there is an unused connection ID. + void FindMatchingOrNewClientConnectionIdOrToken( + const PathState& default_path, + const PathState& alternative_path, + const QuicConnectionId& server_connection_id, + QuicConnectionId* client_connection_id, + bool* stateless_reset_token_received, + StatelessResetToken* stateless_reset_token); + + // Returns true and sets connection IDs if (self_address, peer_address) + // corresponds to either the default path or alternative path. Returns false + // otherwise. + bool FindOnPathConnectionIds(const QuicSocketAddress& self_address, + const QuicSocketAddress& peer_address, + QuicConnectionId* client_connection_id, + QuicConnectionId* server_connection_id) const; + + // Set default_path_ to the new_path_state and update the connection IDs in + // packet creator accordingly. + void SetDefaultPathState(PathState new_path_state); + + // Returns true if header contains valid server connection ID. + bool ValidateServerConnectionId(const QuicPacketHeader& header) const; + + // Update the connection IDs when client migrates with/without validation. + // Returns false if required connection ID is not available. + bool UpdateConnectionIdsOnClientMigration( + const QuicSocketAddress& self_address, + const QuicSocketAddress& peer_address); + + // Retire active peer issued connection IDs after they are no longer used on + // any path. + void RetirePeerIssuedConnectionIdsNoLongerOnPath(); + // Writes the given packet to socket, encrypted with packet's // encryption_level. Returns true on successful write, and false if the writer // was blocked and the write needs to be tried again. Notifies the @@ -1598,7 +1705,7 @@ class QUIC_EXPORT_PRIVATE QuicConnection QuicPacketNumber GetLargestAckedPacket() const; // Whether incoming_connection_ids_ contains connection_id. - bool HasIncomingConnectionId(QuicConnectionId connection_id); + bool HasIncomingConnectionId(QuicConnectionId connection_id) const; // Whether connection is limited by amplification factor. bool LimitedByAmplificationFactor() const; @@ -1671,7 +1778,8 @@ class QUIC_EXPORT_PRIVATE QuicConnection // Send PATH_RESPONSE to the given peer address. bool SendPathResponse(const QuicPathFrameBuffer& data_buffer, - QuicSocketAddress peer_address_to_send); + const QuicSocketAddress& peer_address_to_send, + const QuicSocketAddress& effective_peer_address); // Update both connection's and packet creator's peer address. void UpdatePeerAddress(QuicSocketAddress peer_address); @@ -1734,6 +1842,10 @@ class QUIC_EXPORT_PRIVATE QuicConnection // preferred_address transport parameter. bool OnNewConnectionIdFrameInner(const QuicNewConnectionIdFrame& frame); + // Called to patch missing client connection ID on default/alternative paths + // when a new client connection ID is received. + void OnClientConnectionIdAvailable(); + QuicFramer framer_; // Contents received in the current packet, especially used to identify @@ -1829,7 +1941,7 @@ class QUIC_EXPORT_PRIVATE QuicConnection // Collection of coalesced packets which were received while processing // the current packet. - QuicCircularDeque<std::unique_ptr<QuicEncryptedPacket>> + quiche::QuicheCircularDeque<std::unique_ptr<QuicEncryptedPacket>> received_coalesced_packets_; // Maximum number of undecryptable packets the connection will store. @@ -1937,6 +2049,12 @@ class QUIC_EXPORT_PRIVATE QuicConnection // Source address of the last received packet. QuicSocketAddress last_packet_source_address_; + // Destination connection ID of the last received packet. If this ID is the + // original server connection ID chosen by client and server replaces it with + // a different ID, last_packet_destination_connection_id_ is set to the + // replacement connection ID on the server side. + QuicConnectionId last_packet_destination_connection_id_; + // Set to false if the connection should not send truncated connection IDs to // the peer, even if the peer supports it. bool can_truncate_connection_ids_; @@ -2036,12 +2154,15 @@ class QUIC_EXPORT_PRIVATE QuicConnection // saved and responded to. // TODO(danzh) deprecate this field when deprecating // --quic_send_path_response. - QuicCircularDeque<QuicPathFrameBuffer> received_path_challenge_payloads_; + quiche::QuicheCircularDeque<QuicPathFrameBuffer> + received_path_challenge_payloads_; // Buffer outstanding PATH_CHALLENGEs if socket write is blocked, future // OnCanWrite will attempt to respond with PATH_RESPONSEs using the retained // payload and peer addresses. - QuicCircularDeque<PendingPathChallenge> pending_path_challenge_payloads_; + // TODO(fayang): remove this when deprecating quic_drop_unsent_path_response. + quiche::QuicheCircularDeque<PendingPathChallenge> + pending_path_challenge_payloads_; // Set of connection IDs that should be accepted as destination on // received packets. This is conceptually a set but is implemented as a @@ -2054,6 +2175,9 @@ class QUIC_EXPORT_PRIVATE QuicConnection // |original_destination_connection_id_| for validation. absl::optional<QuicConnectionId> original_destination_connection_id_; + // The connection ID that replaces original_destination_connection_id_. + QuicConnectionId original_destination_connection_id_replacement_; + // After we receive a RETRY packet, |retry_source_connection_id_| contains // the source connection ID from that packet. absl::optional<QuicConnectionId> retry_source_connection_id_; @@ -2094,13 +2218,8 @@ class QUIC_EXPORT_PRIVATE QuicConnection size_t anti_amplification_factor_ = GetQuicFlag(FLAGS_quic_anti_amplification_factor); - bool start_peer_migration_earlier_ = - GetQuicReloadableFlag(quic_start_peer_migration_earlier); - - // latch --gfe2_reloadable_flag_quic_send_path_response and - // --gfe2_reloadable_flag_quic_start_peer_migration_earlier. - bool send_path_response_ = start_peer_migration_earlier_ && - GetQuicReloadableFlag(quic_send_path_response2); + // latch --gfe2_reloadable_flag_quic_send_path_response. + bool send_path_response_ = GetQuicReloadableFlag(quic_send_path_response2); bool use_path_validator_ = send_path_response_ && @@ -2130,6 +2249,9 @@ class QUIC_EXPORT_PRIVATE QuicConnection // True after the first 1-RTT packet has successfully decrypted. bool have_decrypted_first_one_rtt_packet_ = false; + // True if we are currently processing OnRetransmissionTimeout. + bool in_on_retransmission_time_out_ = false; + const bool encrypted_control_frames_; const bool use_encryption_level_context_; @@ -2163,6 +2285,23 @@ class QUIC_EXPORT_PRIVATE QuicConnection const bool donot_write_mid_packet_processing_ = GetQuicReloadableFlag(quic_donot_write_mid_packet_processing); + + bool use_connection_id_on_default_path_ = + GetQuicReloadableFlag(quic_use_connection_id_on_default_path_v2); + + // Indicates whether we should proactively validate peer address on a + // PATH_CHALLENGE received. + bool should_proactively_validate_peer_address_on_path_challenge_ = false; + + // Enable this via reloadable flag once this feature is complete. + bool connection_migration_use_new_cid_ = false; + + const bool group_path_response_and_challenge_sending_closer_ = + GetQuicReloadableFlag( + quic_group_path_response_and_challenge_sending_closer); + + const bool quic_deprecate_incoming_connection_ids_ = + GetQuicReloadableFlag(quic_deprecate_incoming_connection_ids); }; } // 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 303db8f2069..a8cb4c0f377 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 @@ -18,7 +18,6 @@ #include "quic/platform/api/quic_flag_utils.h" #include "quic/platform/api/quic_flags.h" #include "quic/platform/api/quic_logging.h" -#include "common/platform/api/quiche_text_utils.h" #include "common/quiche_endian.h" namespace quic { diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_connection_id_manager.cc b/chromium/net/third_party/quiche/src/quic/core/quic_connection_id_manager.cc index a8e8c542f5f..f7089b7ebfd 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_connection_id_manager.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_connection_id_manager.cc @@ -199,6 +199,22 @@ void QuicPeerIssuedConnectionIdManager::PrepareToRetireActiveConnectionId( } } +void QuicPeerIssuedConnectionIdManager::MaybeRetireUnusedConnectionIds( + const std::vector<QuicConnectionId>& active_connection_ids_on_path) { + std::vector<QuicConnectionId> cids_to_retire; + for (const auto& cid_data : active_connection_id_data_) { + if (std::find(active_connection_ids_on_path.begin(), + active_connection_ids_on_path.end(), + cid_data.connection_id) == + active_connection_ids_on_path.end()) { + cids_to_retire.push_back(cid_data.connection_id); + } + } + for (const auto& cid : cids_to_retire) { + PrepareToRetireActiveConnectionId(cid); + } +} + bool QuicPeerIssuedConnectionIdManager::IsConnectionIdActive( const QuicConnectionId& cid) const { return FindConnectionIdData(active_connection_id_data_, cid) != @@ -263,7 +279,8 @@ QuicSelfIssuedConnectionIdManager::QuicSelfIssuedConnectionIdManager( retire_connection_id_alarm_(alarm_factory->CreateAlarm( new RetireSelfIssuedConnectionIdAlarmDelegate(this))), last_connection_id_(initial_connection_id), - next_connection_id_sequence_number_(1u) { + next_connection_id_sequence_number_(1u), + last_connection_id_consumed_by_self_sequence_number_(0u) { active_connection_ids_.emplace_back(initial_connection_id, 0u); } @@ -386,4 +403,45 @@ void QuicSelfIssuedConnectionIdManager::MaybeSendNewConnectionIds() { } } +bool QuicSelfIssuedConnectionIdManager::HasConnectionIdToConsume() const { + for (const auto& active_cid_data : active_connection_ids_) { + if (active_cid_data.second > + last_connection_id_consumed_by_self_sequence_number_) { + return true; + } + } + return false; +} + +absl::optional<QuicConnectionId> +QuicSelfIssuedConnectionIdManager::ConsumeOneConnectionId() { + for (const auto& active_cid_data : active_connection_ids_) { + if (active_cid_data.second > + last_connection_id_consumed_by_self_sequence_number_) { + // Since connection IDs in active_connection_ids_ has monotonically + // increasing sequence numbers, the returned connection ID has the + // smallest sequence number among all unconsumed active connection IDs. + last_connection_id_consumed_by_self_sequence_number_ = + active_cid_data.second; + return active_cid_data.first; + } + } + return absl::nullopt; +} + +bool QuicSelfIssuedConnectionIdManager::IsConnectionIdInUse( + const QuicConnectionId& cid) const { + for (const auto& active_cid_data : active_connection_ids_) { + if (active_cid_data.first == cid) { + return true; + } + } + for (const auto& to_be_retired_cid_data : to_be_retired_connection_ids_) { + if (to_be_retired_cid_data.first == cid) { + return true; + } + } + return false; +} + } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_connection_id_manager.h b/chromium/net/third_party/quiche/src/quic/core/quic_connection_id_manager.h index b933a69f158..5e7fc8ccf72 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_connection_id_manager.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_connection_id_manager.h @@ -13,6 +13,7 @@ #include <cstddef> #include <memory> +#include "absl/types/optional.h" #include "quic/core/frames/quic_new_connection_id_frame.h" #include "quic/core/frames/quic_retire_connection_id_frame.h" #include "quic/core/quic_alarm.h" @@ -68,13 +69,19 @@ class QUIC_EXPORT_PRIVATE QuicPeerIssuedConnectionIdManager { QuicErrorCode OnNewConnectionIdFrame(const QuicNewConnectionIdFrame& frame, std::string* error_detail); + bool HasUnusedConnectionId() const { + return !unused_connection_id_data_.empty(); + } + // Returns the data associated with an unused connection Id. After the call, // the Id is marked as used. Returns nullptr if there is no unused connection // Id. const QuicConnectionIdData* ConsumeOneUnusedConnectionId(); - // Add the connection Id to the pending retirement connection Id list. - void PrepareToRetireActiveConnectionId(const QuicConnectionId& cid); + // Add each active connection Id that is no longer on path to the pending + // retirement connection Id list. + void MaybeRetireUnusedConnectionIds( + const std::vector<QuicConnectionId>& active_connection_ids_on_path); bool IsConnectionIdActive(const QuicConnectionId& cid) const; @@ -90,6 +97,10 @@ class QUIC_EXPORT_PRIVATE QuicPeerIssuedConnectionIdManager { private: friend class test::QuicConnectionIdManagerPeer; + // Add the connection Id to the pending retirement connection Id list and + // schedule an alarm if needed. + void PrepareToRetireActiveConnectionId(const QuicConnectionId& cid); + bool IsConnectionIdNew(const QuicNewConnectionIdFrame& frame); void PrepareToRetireConnectionIdPriorTo( @@ -135,6 +146,17 @@ class QUIC_EXPORT_PRIVATE QuicSelfIssuedConnectionIdManager { // Sends new connection IDs if more can be sent. void MaybeSendNewConnectionIds(); + // The two functions are called on the client side to associate a client + // connection ID with a new probing/migration path when client uses + // non-empty connection ID. + bool HasConnectionIdToConsume() const; + absl::optional<QuicConnectionId> ConsumeOneConnectionId(); + + // Returns true if the given connection ID is issued by the + // QuicSelfIssuedConnectionIdManager and not retired locally yet. Called to + // tell if a received packet has a valid connection ID. + bool IsConnectionIdInUse(const QuicConnectionId& cid) const; + virtual QuicConnectionId GenerateNewConnectionId( const QuicConnectionId& old_connection_id) const; @@ -162,6 +184,8 @@ class QUIC_EXPORT_PRIVATE QuicSelfIssuedConnectionIdManager { // State of the last issued connection Id. QuicConnectionId last_connection_id_; uint64_t next_connection_id_sequence_number_; + // The sequence number of last connection ID consumed. + uint64_t last_connection_id_consumed_by_self_sequence_number_; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_connection_id_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_connection_id_manager_test.cc index 9c7daf0db5e..7baeb2b247e 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_connection_id_manager_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_connection_id_manager_test.cc @@ -126,8 +126,8 @@ TEST_F(QuicPeerIssuedConnectionIdManagerTest, frame.stateless_reset_token); // Connection migration succeed. Prepares to retire CID #0. - peer_issued_cid_manager_.PrepareToRetireActiveConnectionId( - TestConnectionId(0)); + peer_issued_cid_manager_.MaybeRetireUnusedConnectionIds( + {TestConnectionId(1)}); cid_manager_visitor_.SetCurrentPeerConnectionId(TestConnectionId(1)); ASSERT_TRUE(retire_peer_issued_cid_alarm_->IsSet()); alarm_factory_.FireAlarm(retire_peer_issued_cid_alarm_); @@ -150,8 +150,8 @@ TEST_F(QuicPeerIssuedConnectionIdManagerTest, // Start to use CID #2 for alternative path. peer_issued_cid_manager_.ConsumeOneUnusedConnectionId(); // Connection migration succeed. Prepares to retire CID #1. - peer_issued_cid_manager_.PrepareToRetireActiveConnectionId( - TestConnectionId(1)); + peer_issued_cid_manager_.MaybeRetireUnusedConnectionIds( + {TestConnectionId(2)}); cid_manager_visitor_.SetCurrentPeerConnectionId(TestConnectionId(2)); ASSERT_TRUE(retire_peer_issued_cid_alarm_->IsSet()); alarm_factory_.FireAlarm(retire_peer_issued_cid_alarm_); @@ -174,8 +174,8 @@ TEST_F(QuicPeerIssuedConnectionIdManagerTest, // Start to use CID #3 for alternative path. peer_issued_cid_manager_.ConsumeOneUnusedConnectionId(); // Connection migration succeed. Prepares to retire CID #2. - peer_issued_cid_manager_.PrepareToRetireActiveConnectionId( - TestConnectionId(2)); + peer_issued_cid_manager_.MaybeRetireUnusedConnectionIds( + {TestConnectionId(3)}); cid_manager_visitor_.SetCurrentPeerConnectionId(TestConnectionId(3)); ASSERT_TRUE(retire_peer_issued_cid_alarm_->IsSet()); alarm_factory_.FireAlarm(retire_peer_issued_cid_alarm_); @@ -214,8 +214,8 @@ TEST_F(QuicPeerIssuedConnectionIdManagerTest, // Start to use CID #1 for alternative path. peer_issued_cid_manager_.ConsumeOneUnusedConnectionId(); // Connection migration fails. Prepares to retire CID #1. - peer_issued_cid_manager_.PrepareToRetireActiveConnectionId( - TestConnectionId(1)); + peer_issued_cid_manager_.MaybeRetireUnusedConnectionIds( + {initial_connection_id_}); // Actually retires CID #1. ASSERT_TRUE(retire_peer_issued_cid_alarm_->IsSet()); alarm_factory_.FireAlarm(retire_peer_issued_cid_alarm_); @@ -238,8 +238,8 @@ TEST_F(QuicPeerIssuedConnectionIdManagerTest, // Start to use CID #2 for alternative path. peer_issued_cid_manager_.ConsumeOneUnusedConnectionId(); // Connection migration fails again. Prepares to retire CID #2. - peer_issued_cid_manager_.PrepareToRetireActiveConnectionId( - TestConnectionId(2)); + peer_issued_cid_manager_.MaybeRetireUnusedConnectionIds( + {initial_connection_id_}); // Actually retires CID #2. ASSERT_TRUE(retire_peer_issued_cid_alarm_->IsSet()); alarm_factory_.FireAlarm(retire_peer_issued_cid_alarm_); @@ -262,8 +262,8 @@ TEST_F(QuicPeerIssuedConnectionIdManagerTest, // Start to use CID #3 for alternative path. peer_issued_cid_manager_.ConsumeOneUnusedConnectionId(); // Connection migration succeed. Prepares to retire CID #0. - peer_issued_cid_manager_.PrepareToRetireActiveConnectionId( - TestConnectionId(0)); + peer_issued_cid_manager_.MaybeRetireUnusedConnectionIds( + {TestConnectionId(3)}); // After CID #3 is default (i.e., when there is no pending frame to write // associated with CID #0), #0 can actually be retired. cid_manager_visitor_.SetCurrentPeerConnectionId(TestConnectionId(3)); @@ -374,8 +374,8 @@ TEST_F(QuicPeerIssuedConnectionIdManagerTest, // Outcome: (active: #0 #1 unused: None) peer_issued_cid_manager_.ConsumeOneUnusedConnectionId(); // Prepare to retire CID #1 as path validation fails. - peer_issued_cid_manager_.PrepareToRetireActiveConnectionId( - TestConnectionId(1)); + peer_issued_cid_manager_.MaybeRetireUnusedConnectionIds( + {initial_connection_id_}); // Actually retires CID #1. ASSERT_TRUE(retire_peer_issued_cid_alarm_->IsSet()); alarm_factory_.FireAlarm(retire_peer_issued_cid_alarm_); @@ -845,20 +845,36 @@ TEST_F(QuicSelfIssuedConnectionIdManagerTest, QuicConnectionId cid1 = cid_manager_.GenerateNewConnectionId(cid0); QuicConnectionId cid2 = cid_manager_.GenerateNewConnectionId(cid1); QuicConnectionId cid3 = cid_manager_.GenerateNewConnectionId(cid2); + QuicConnectionId cid; EXPECT_CALL(cid_manager_visitor_, OnNewConnectionIdIssued(_)).Times(3); EXPECT_CALL(cid_manager_visitor_, SendNewConnectionId(_)) .Times(3) .WillRepeatedly(Return(true)); QuicTime::Delta connection_id_expire_timeout = 3 * pto_delay_; QuicRetireConnectionIdFrame retire_cid_frame; + EXPECT_TRUE(cid_manager_.IsConnectionIdInUse(cid0)); + EXPECT_FALSE(cid_manager_.HasConnectionIdToConsume()); + EXPECT_FALSE(cid_manager_.ConsumeOneConnectionId().has_value()); // CID #1 is sent to peer. cid_manager_.MaybeSendNewConnectionIds(); + EXPECT_TRUE(cid_manager_.IsConnectionIdInUse(cid1)); + EXPECT_TRUE(cid_manager_.HasConnectionIdToConsume()); + cid = *cid_manager_.ConsumeOneConnectionId(); + EXPECT_EQ(cid1, cid); + EXPECT_FALSE(cid_manager_.HasConnectionIdToConsume()); // CID #0's retirement is scheduled and CID #2 is sent to peer. retire_cid_frame.sequence_number = 0u; cid_manager_.OnRetireConnectionIdFrame(retire_cid_frame, pto_delay_, &error_details_); + EXPECT_TRUE(cid_manager_.IsConnectionIdInUse(cid0)); + EXPECT_TRUE(cid_manager_.IsConnectionIdInUse(cid1)); + EXPECT_TRUE(cid_manager_.IsConnectionIdInUse(cid2)); + EXPECT_TRUE(cid_manager_.HasConnectionIdToConsume()); + cid = *cid_manager_.ConsumeOneConnectionId(); + EXPECT_EQ(cid2, cid); + EXPECT_FALSE(cid_manager_.HasConnectionIdToConsume()); clock_.AdvanceTime(connection_id_expire_timeout * 0.1); @@ -874,6 +890,9 @@ TEST_F(QuicSelfIssuedConnectionIdManagerTest, EXPECT_CALL(cid_manager_visitor_, OnSelfIssuedConnectionIdRetired(cid0)); EXPECT_CALL(cid_manager_visitor_, OnSelfIssuedConnectionIdRetired(cid1)); alarm_factory_.FireAlarm(retire_self_issued_cid_alarm_); + EXPECT_FALSE(cid_manager_.IsConnectionIdInUse(cid0)); + EXPECT_FALSE(cid_manager_.IsConnectionIdInUse(cid1)); + EXPECT_TRUE(cid_manager_.IsConnectionIdInUse(cid2)); EXPECT_THAT(cid_manager_.GetUnretiredConnectionIds(), ElementsAre(cid2, cid3)); EXPECT_FALSE(retire_self_issued_cid_alarm_->IsSet()); 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 3d1b3c422a8..fbaa20abd94 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,8 +34,9 @@ std::ostream& operator<<(std::ostream& os, const QuicConnectionStats& s) { 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; - os << " max_received_packet_size: " << s.max_received_packet_size; + os << " egress_mtu: " << s.egress_mtu; + os << " max_egress_mtu: " << s.max_egress_mtu; + os << " ingress_mtu: " << s.ingress_mtu; os << " estimated_bandwidth: " << s.estimated_bandwidth; os << " packets_reordered: " << s.packets_reordered; os << " max_sequence_reordering: " << s.max_sequence_reordering; 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 06b7f5868bd..39fd5b087a6 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 @@ -103,8 +103,14 @@ struct QUIC_EXPORT_PRIVATE QuicConnectionStats { int64_t min_rtt_us = 0; // Minimum RTT in microseconds. int64_t srtt_us = 0; // Smoothed RTT in microseconds. int64_t cwnd_bootstrapping_rtt_us = 0; // RTT used in cwnd_bootstrapping. - QuicByteCount max_packet_size = 0; - QuicByteCount max_received_packet_size = 0; + // The connection's |long_term_mtu_| used for sending packets, populated by + // QuicConnection::GetStats(). + QuicByteCount egress_mtu = 0; + // The maximum |long_term_mtu_| the connection ever used. + QuicByteCount max_egress_mtu = 0; + // Size of the largest packet received from the peer, populated by + // QuicConnection::GetStats(). + QuicByteCount ingress_mtu = 0; QuicBandwidth estimated_bandwidth = QuicBandwidth::Zero(); // Reordering stats for received packets. @@ -209,6 +215,10 @@ struct QUIC_EXPORT_PRIVATE QuicConnectionStats { // which was canceled because the peer migrated again. Such migration is also // counted as invalid peer migration. size_t num_peer_migration_while_validating_default_path = 0; + // Number of NEW_CONNECTION_ID frames sent. + size_t num_new_connection_id_sent = 0; + // Number of RETIRE_CONNECTION_ID frames sent. + size_t num_retire_connection_id_sent = 0; struct QUIC_NO_EXPORT TlsServerOperationStats { bool success = false; 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 e2fba5b8325..fe2ff6cab6e 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 @@ -21,10 +21,12 @@ #include "quic/core/crypto/quic_decrypter.h" #include "quic/core/crypto/quic_encrypter.h" #include "quic/core/frames/quic_connection_close_frame.h" +#include "quic/core/frames/quic_new_connection_id_frame.h" #include "quic/core/frames/quic_path_response_frame.h" #include "quic/core/quic_connection_id.h" #include "quic/core/quic_constants.h" #include "quic/core/quic_error_codes.h" +#include "quic/core/quic_packet_creator.h" #include "quic/core/quic_packets.h" #include "quic/core/quic_path_validator.h" #include "quic/core/quic_simple_buffer_allocator.h" @@ -33,6 +35,7 @@ #include "quic/core/quic_versions.h" #include "quic/platform/api/quic_expect_bug.h" #include "quic/platform/api/quic_flags.h" +#include "quic/platform/api/quic_ip_address.h" #include "quic/platform/api/quic_logging.h" #include "quic/platform/api/quic_reference_counted.h" #include "quic/platform/api/quic_socket_address.h" @@ -764,6 +767,12 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> { void use_tagging_decrypter() { writer_->use_tagging_decrypter(); } + void SetClientConnectionId(const QuicConnectionId& client_connection_id) { + connection_.set_client_connection_id(client_connection_id); + writer_->framer()->framer()->SetExpectedClientConnectionIdLength( + client_connection_id.length()); + } + void SetDecrypter(EncryptionLevel level, std::unique_ptr<QuicDecrypter> decrypter) { if (connection_.version().KnowsWhichDecrypterToUse()) { @@ -1190,8 +1199,7 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> { EncryptionLevel level) { QuicPacketHeader header = ConstructPacketHeader(number, level); QuicFrames frames; - if (GetQuicReloadableFlag(quic_reject_unexpected_ietf_frame_types) && - VersionHasIetfQuicFrames(version().transport_version) && + if (VersionHasIetfQuicFrames(version().transport_version) && (level == ENCRYPTION_INITIAL || level == ENCRYPTION_HANDSHAKE)) { frames.push_back(QuicFrame(QuicPingFrame())); frames.push_back(QuicFrame(QuicPaddingFrame(100))); @@ -1420,8 +1428,10 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> { EXPECT_TRUE(connection_.connected()); } - void PathProbeTestInit(Perspective perspective) { + void PathProbeTestInit(Perspective perspective, + bool receive_new_server_connection_id = true) { set_perspective(perspective); + connection_.CreateConnectionIdManager(); EXPECT_EQ(connection_.perspective(), perspective); if (perspective == Perspective::IS_SERVER) { QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false); @@ -1453,6 +1463,17 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> { kPeerAddress, ENCRYPTION_FORWARD_SECURE); EXPECT_EQ(kPeerAddress, connection_.peer_address()); EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); + if (perspective == Perspective::IS_CLIENT && + receive_new_server_connection_id) { + QuicNewConnectionIdFrame frame; + frame.connection_id = TestConnectionId(1234); + ASSERT_NE(frame.connection_id, connection_.connection_id()); + frame.stateless_reset_token = + QuicUtils::GenerateStatelessResetToken(frame.connection_id); + frame.retire_prior_to = 0u; + frame.sequence_number = 1u; + connection_.OnNewConnectionIdFrame(frame); + } } void TestClientRetryHandling(bool invalid_retry_tag, @@ -1691,13 +1712,8 @@ TEST_P(QuicConnectionTest, PeerPortChangeAtServer) { EXPECT_CALL(visitor_, OnStreamFrame(_)) .WillOnce(Invoke( [=]() { EXPECT_EQ(kPeerAddress, connection_.peer_address()); })) - .WillOnce(Invoke([=]() { - EXPECT_EQ((GetQuicReloadableFlag(quic_start_peer_migration_earlier) || - !GetParam().version.HasIetfQuicFrames() - ? kNewPeerAddress - : kPeerAddress), - connection_.peer_address()); - })); + .WillOnce(Invoke( + [=]() { EXPECT_EQ(kNewPeerAddress, connection_.peer_address()); })); QuicFrames frames; frames.push_back(QuicFrame(frame1_)); ProcessFramesPacketWithAddresses(frames, kSelfAddress, kPeerAddress, @@ -1765,13 +1781,8 @@ TEST_P(QuicConnectionTest, PeerIpAddressChangeAtServer) { EXPECT_CALL(visitor_, OnStreamFrame(_)) .WillOnce(Invoke( [=]() { EXPECT_EQ(kPeerAddress, connection_.peer_address()); })) - .WillOnce(Invoke([=]() { - EXPECT_EQ((GetQuicReloadableFlag(quic_start_peer_migration_earlier) || - !GetParam().version.HasIetfQuicFrames() - ? kNewPeerAddress - : kPeerAddress), - connection_.peer_address()); - })); + .WillOnce(Invoke( + [=]() { EXPECT_EQ(kNewPeerAddress, connection_.peer_address()); })); QuicFrames frames; frames.push_back(QuicFrame(frame1_)); ProcessFramesPacketWithAddresses(frames, kSelfAddress, kPeerAddress, @@ -1866,6 +1877,83 @@ TEST_P(QuicConnectionTest, PeerIpAddressChangeAtServer) { EXPECT_EQ(1u, connection_.GetStats().num_validated_peer_migration); } +TEST_P(QuicConnectionTest, PeerIpAddressChangeAtServerWithMissingConnectionId) { + set_perspective(Perspective::IS_SERVER); + if (!connection_.connection_migration_use_new_cid()) { + return; + } + QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false); + EXPECT_EQ(Perspective::IS_SERVER, connection_.perspective()); + + QuicConnectionId client_cid0 = TestConnectionId(1); + QuicConnectionId client_cid1 = TestConnectionId(3); + QuicConnectionId server_cid1; + SetClientConnectionId(client_cid0); + connection_.CreateConnectionIdManager(); + connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); + // Prevent packets from being coalesced. + EXPECT_CALL(visitor_, GetHandshakeState()) + .WillRepeatedly(Return(HANDSHAKE_CONFIRMED)); + QuicConnectionPeer::SetAddressValidated(&connection_); + + // Sends new server CID to client. + EXPECT_CALL(visitor_, OnServerConnectionIdIssued(_)) + .WillOnce( + Invoke([&](const QuicConnectionId& cid) { server_cid1 = cid; })); + EXPECT_CALL(visitor_, SendNewConnectionId(_)); + connection_.OnHandshakeComplete(); + + // Clear direct_peer_address. + QuicConnectionPeer::SetDirectPeerAddress(&connection_, QuicSocketAddress()); + // Clear effective_peer_address, it is the same as direct_peer_address for + // this test. + QuicConnectionPeer::SetEffectivePeerAddress(&connection_, + QuicSocketAddress()); + EXPECT_FALSE(connection_.effective_peer_address().IsInitialized()); + + const QuicSocketAddress kNewPeerAddress = + QuicSocketAddress(QuicIpAddress::Loopback4(), /*port=*/23456); + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(2); + QuicFrames frames; + frames.push_back(QuicFrame(frame1_)); + ProcessFramesPacketWithAddresses(frames, kSelfAddress, kPeerAddress, + ENCRYPTION_FORWARD_SECURE); + EXPECT_EQ(kPeerAddress, connection_.peer_address()); + EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); + + // Send some data to make connection has packets in flight. + connection_.SendStreamData3(); + EXPECT_EQ(1u, writer_->packets_write_attempts()); + + // Process another packet with a different peer address on server side will + // start connection migration. + peer_creator_.SetServerConnectionId(server_cid1); + EXPECT_CALL(visitor_, OnConnectionMigration(IPV6_TO_IPV4_CHANGE)).Times(1); + // Do not propagate OnCanWrite() to session notifier. + EXPECT_CALL(visitor_, OnCanWrite()).Times(AtLeast(1u)); + + QuicFrames frames2; + frames2.push_back(QuicFrame(frame2_)); + ProcessFramesPacketWithAddresses(frames2, kSelfAddress, kNewPeerAddress, + ENCRYPTION_FORWARD_SECURE); + EXPECT_EQ(kNewPeerAddress, connection_.peer_address()); + EXPECT_EQ(kNewPeerAddress, connection_.effective_peer_address()); + + // Writing path response & reverse path challenge is blocked due to missing + // client connection ID, i.e., packets_write_attempts is unchanged. + EXPECT_EQ(1u, writer_->packets_write_attempts()); + + // Receives new client CID from client would unblock write. + QuicNewConnectionIdFrame new_cid_frame; + new_cid_frame.connection_id = client_cid1; + new_cid_frame.sequence_number = 1u; + new_cid_frame.retire_prior_to = 0u; + connection_.OnNewConnectionIdFrame(new_cid_frame); + connection_.SendStreamData3(); + + EXPECT_EQ(2u, writer_->packets_write_attempts()); +} + TEST_P(QuicConnectionTest, EffectivePeerAddressChangeAtServer) { set_perspective(Perspective::IS_SERVER); QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false); @@ -1983,17 +2071,38 @@ TEST_P(QuicConnectionTest, EffectivePeerAddressChangeAtServer) { TEST_P(QuicConnectionTest, ReversePathValidationFailureAtServer) { set_perspective(Perspective::IS_SERVER); - if (!connection_.validate_client_address()) { + if (!connection_.connection_migration_use_new_cid()) { return; } QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false); EXPECT_EQ(Perspective::IS_SERVER, connection_.perspective()); + SetClientConnectionId(TestConnectionId(1)); + connection_.CreateConnectionIdManager(); connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); // Prevent packets from being coalesced. EXPECT_CALL(visitor_, GetHandshakeState()) .WillRepeatedly(Return(HANDSHAKE_CONFIRMED)); QuicConnectionPeer::SetAddressValidated(&connection_); + + QuicConnectionId client_cid0 = connection_.client_connection_id(); + QuicConnectionId client_cid1 = TestConnectionId(2); + QuicConnectionId server_cid0 = connection_.connection_id(); + QuicConnectionId server_cid1; + // Sends new server CID to client. + EXPECT_CALL(visitor_, OnServerConnectionIdIssued(_)) + .WillOnce( + Invoke([&](const QuicConnectionId& cid) { server_cid1 = cid; })); + EXPECT_CALL(visitor_, SendNewConnectionId(_)); connection_.OnHandshakeComplete(); + // Receives new client CID from client. + QuicNewConnectionIdFrame new_cid_frame; + new_cid_frame.connection_id = client_cid1; + new_cid_frame.sequence_number = 1u; + new_cid_frame.retire_prior_to = 0u; + connection_.OnNewConnectionIdFrame(new_cid_frame); + auto* packet_creator = QuicConnectionPeer::GetPacketCreator(&connection_); + ASSERT_EQ(packet_creator->GetDestinationConnectionId(), client_cid0); + ASSERT_EQ(packet_creator->GetSourceConnectionId(), server_cid0); // Clear direct_peer_address. QuicConnectionPeer::SetDirectPeerAddress(&connection_, QuicSocketAddress()); @@ -2008,13 +2117,8 @@ TEST_P(QuicConnectionTest, ReversePathValidationFailureAtServer) { EXPECT_CALL(visitor_, OnStreamFrame(_)) .WillOnce(Invoke( [=]() { EXPECT_EQ(kPeerAddress, connection_.peer_address()); })) - .WillOnce(Invoke([=]() { - EXPECT_EQ((GetQuicReloadableFlag(quic_start_peer_migration_earlier) || - !GetParam().version.HasIetfQuicFrames() - ? kNewPeerAddress - : kPeerAddress), - connection_.peer_address()); - })); + .WillOnce(Invoke( + [=]() { EXPECT_EQ(kNewPeerAddress, connection_.peer_address()); })); QuicFrames frames; frames.push_back(QuicFrame(frame1_)); ProcessFramesPacketWithAddresses(frames, kSelfAddress, kPeerAddress, @@ -2033,6 +2137,7 @@ TEST_P(QuicConnectionTest, ReversePathValidationFailureAtServer) { frames2.push_back(QuicFrame(frame2_)); QuicPaddingFrame padding; frames2.push_back(QuicFrame(padding)); + peer_creator_.SetServerConnectionId(server_cid1); ProcessFramesPacketWithAddresses(frames2, kSelfAddress, kNewPeerAddress, ENCRYPTION_FORWARD_SECURE); EXPECT_EQ(kNewPeerAddress, connection_.peer_address()); @@ -2046,6 +2151,15 @@ TEST_P(QuicConnectionTest, ReversePathValidationFailureAtServer) { EXPECT_EQ(kNewPeerAddress, writer_->last_write_peer_address()); EXPECT_EQ(kNewPeerAddress, connection_.peer_address()); EXPECT_EQ(kNewPeerAddress, connection_.effective_peer_address()); + const auto* default_path = QuicConnectionPeer::GetDefaultPath(&connection_); + const auto* alternative_path = + QuicConnectionPeer::GetAlternativePath(&connection_); + EXPECT_EQ(default_path->client_connection_id, client_cid1); + EXPECT_EQ(default_path->server_connection_id, server_cid1); + EXPECT_EQ(alternative_path->client_connection_id, client_cid0); + EXPECT_EQ(alternative_path->server_connection_id, server_cid0); + EXPECT_EQ(packet_creator->GetDestinationConnectionId(), client_cid1); + EXPECT_EQ(packet_creator->GetSourceConnectionId(), server_cid1); for (size_t i = 0; i < QuicPathValidator::kMaxRetryTimes; ++i) { clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(3 * kInitialRttMs)); @@ -2072,6 +2186,19 @@ TEST_P(QuicConnectionTest, ReversePathValidationFailureAtServer) { EXPECT_EQ(connection_.sent_packet_manager().GetSendAlgorithm(), send_algorithm_); EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet()); + + // Verify that default_path_ is reverted and alternative_path_ is cleared. + EXPECT_EQ(default_path->client_connection_id, client_cid0); + EXPECT_EQ(default_path->server_connection_id, server_cid0); + EXPECT_TRUE(alternative_path->server_connection_id.IsEmpty()); + EXPECT_FALSE(alternative_path->stateless_reset_token_received); + auto* retire_peer_issued_cid_alarm = + connection_.GetRetirePeerIssuedConnectionIdAlarm(); + ASSERT_TRUE(retire_peer_issued_cid_alarm->IsSet()); + EXPECT_CALL(visitor_, SendRetireConnectionId(/*sequence_number=*/1u)); + retire_peer_issued_cid_alarm->Fire(); + EXPECT_EQ(packet_creator->GetDestinationConnectionId(), client_cid0); + EXPECT_EQ(packet_creator->GetSourceConnectionId(), server_cid0); } TEST_P(QuicConnectionTest, ReceivePathProbeWithNoAddressChangeAtServer) { @@ -2184,10 +2311,12 @@ class TestQuicPathValidationContext : public QuicPathValidationContext { class TestValidationResultDelegate : public QuicPathValidator::ResultDelegate { public: - TestValidationResultDelegate(const QuicSocketAddress& expected_self_address, + TestValidationResultDelegate(QuicConnection* connection, + const QuicSocketAddress& expected_self_address, const QuicSocketAddress& expected_peer_address, bool* success) : QuicPathValidator::ResultDelegate(), + connection_(connection), expected_self_address_(expected_self_address), expected_peer_address_(expected_peer_address), success_(success) {} @@ -2202,10 +2331,14 @@ class TestValidationResultDelegate : public QuicPathValidator::ResultDelegate { std::unique_ptr<QuicPathValidationContext> context) override { EXPECT_EQ(expected_self_address_, context->self_address()); EXPECT_EQ(expected_peer_address_, context->peer_address()); + if (connection_->perspective() == Perspective::IS_CLIENT) { + connection_->OnPathValidationFailureAtClient(); + } *success_ = false; } private: + QuicConnection* connection_; QuicSocketAddress expected_self_address_; QuicSocketAddress expected_peer_address_; bool* success_; @@ -2291,7 +2424,8 @@ TEST_P(QuicConnectionTest, ReceivePathProbingAtServer) { std::make_unique<TestQuicPathValidationContext>( connection_.self_address(), kNewPeerAddress, writer_.get()), std::make_unique<TestValidationResultDelegate>( - connection_.self_address(), kNewPeerAddress, &success)); + &connection_, connection_.self_address(), kNewPeerAddress, + &success)); } EXPECT_EQ((connection_.validate_client_address() ? 2 : 3) * bytes_sent, QuicConnectionPeer::BytesSentOnAlternativePath(&connection_)); @@ -2836,8 +2970,7 @@ TEST_P(QuicConnectionTest, PacketsOutOfOrderWithAdditionsAndLeastAwaiting) { TEST_P(QuicConnectionTest, RejectUnencryptedStreamData) { // EXPECT_QUIC_BUG tests are expensive so only run one instance of them. if (!IsDefaultTestConfiguration() || - (GetQuicReloadableFlag(quic_reject_unexpected_ietf_frame_types) && - VersionHasIetfQuicFrames(version().transport_version))) { + VersionHasIetfQuicFrames(version().transport_version)) { return; } @@ -3169,20 +3302,6 @@ TEST_P(QuicConnectionTest, TooManySentPackets) { ProcessFramePacket(QuicFrame(QuicPingFrame())); - if (!GetQuicReloadableFlag( - quic_close_connection_with_too_many_outstanding_packets)) { - // When the flag is false, the ping packet processed above shouldn't cause - // the connection to close. But the ack packet below will. - EXPECT_TRUE(connection_.connected()); - - // Ack packet 1, which leaves more than the limit outstanding. - EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _)); - - // Nack the first packet and ack the rest, leaving a huge gap. - QuicAckFrame frame1 = ConstructAckFrame(num_packets, 1); - ProcessAckPacket(&frame1); - } - TestConnectionCloseQuicErrorCode(QUIC_TOO_MANY_OUTSTANDING_SENT_PACKETS); } @@ -3390,15 +3509,15 @@ TEST_P(QuicConnectionTest, FramePackingNonCryptoThenCrypto) { EXPECT_EQ(0u, connection_.NumQueuedPackets()); EXPECT_FALSE(connection_.HasQueuedData()); - // Parse the last packet and ensure it's the crypto stream frame. - EXPECT_EQ(2u, writer_->frame_count()); - ASSERT_EQ(1u, writer_->padding_frames().size()); + // Parse the last packet and ensure it contains a crypto stream frame. + EXPECT_LE(2u, writer_->frame_count()); + ASSERT_LE(1u, writer_->padding_frames().size()); if (!QuicVersionUsesCryptoFrames(connection_.transport_version())) { ASSERT_EQ(1u, writer_->stream_frames().size()); EXPECT_EQ(QuicUtils::GetCryptoStreamId(connection_.transport_version()), writer_->stream_frames()[0]->stream_id); } else { - EXPECT_EQ(1u, writer_->crypto_frames().size()); + EXPECT_LE(1u, writer_->crypto_frames().size()); } } @@ -7081,7 +7200,7 @@ TEST_P(QuicConnectionTest, CheckSendStats) { stats.bytes_retransmitted); EXPECT_EQ(3u, stats.packets_retransmitted); EXPECT_EQ(1u, stats.rto_count); - EXPECT_EQ(kDefaultMaxPacketSize, stats.max_packet_size); + EXPECT_EQ(kDefaultMaxPacketSize, stats.egress_mtu); } TEST_P(QuicConnectionTest, ProcessFramesIfPacketClosedConnection) { @@ -7787,8 +7906,7 @@ TEST_P(QuicConnectionTest, ServerReceivesChloOnNonCryptoStream) { EXPECT_CALL(visitor_, OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF)); ForceProcessFramePacket(QuicFrame(frame1_)); - if (GetQuicReloadableFlag(quic_reject_unexpected_ietf_frame_types) && - VersionHasIetfQuicFrames(version().transport_version)) { + if (VersionHasIetfQuicFrames(version().transport_version)) { // INITIAL packet should not contain STREAM frame. TestConnectionCloseQuicErrorCode(IETF_QUIC_PROTOCOL_VIOLATION); } else { @@ -7810,8 +7928,7 @@ TEST_P(QuicConnectionTest, ClientReceivesRejOnNonCryptoStream) { EXPECT_CALL(visitor_, OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF)); ForceProcessFramePacket(QuicFrame(frame1_)); - if (GetQuicReloadableFlag(quic_reject_unexpected_ietf_frame_types) && - VersionHasIetfQuicFrames(version().transport_version)) { + if (VersionHasIetfQuicFrames(version().transport_version)) { // INITIAL packet should not contain STREAM frame. TestConnectionCloseQuicErrorCode(IETF_QUIC_PROTOCOL_VIOLATION); } else { @@ -8899,7 +9016,7 @@ TEST_P(QuicConnectionTest, ClientResponseToPathChallengeOnAlternativeSocket) { std::make_unique<TestQuicPathValidationContext>( kNewSelfAddress, connection_.peer_address(), &new_writer), std::make_unique<TestValidationResultDelegate>( - kNewSelfAddress, connection_.peer_address(), &success)); + &connection_, kNewSelfAddress, connection_.peer_address(), &success)); // Receiving a PATH_CHALLENGE on the alternative path. Response to this // PATH_CHALLENGE should be sent via the alternative writer. @@ -9300,7 +9417,7 @@ TEST_P(QuicConnectionTest, ValidClientConnectionId) { return; } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - connection_.set_client_connection_id(TestConnectionId(0x33)); + SetClientConnectionId(TestConnectionId(0x33)); QuicPacketHeader header = ConstructPacketHeader(1, ENCRYPTION_FORWARD_SECURE); header.destination_connection_id = TestConnectionId(0x33); header.destination_connection_id_included = CONNECTION_ID_PRESENT; @@ -9328,7 +9445,7 @@ TEST_P(QuicConnectionTest, InvalidClientConnectionId) { if (!framer_.version().SupportsClientConnectionIds()) { return; } - connection_.set_client_connection_id(TestConnectionId(0x33)); + SetClientConnectionId(TestConnectionId(0x33)); QuicPacketHeader header = ConstructPacketHeader(1, ENCRYPTION_FORWARD_SECURE); header.destination_connection_id = TestConnectionId(0xbad); header.destination_connection_id_included = CONNECTION_ID_PRESENT; @@ -11162,8 +11279,7 @@ TEST_P(QuicConnectionTest, ProcessUndecryptablePacketsBasedOnEncryptionLevel) { std::make_unique<TaggingEncrypter>(0x01)); connection_.SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE); // Verify all ENCRYPTION_HANDSHAKE packets get processed. - if (!GetQuicReloadableFlag(quic_reject_unexpected_ietf_frame_types) || - !VersionHasIetfQuicFrames(version().transport_version)) { + if (!VersionHasIetfQuicFrames(version().transport_version)) { EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(6); } connection_.GetProcessUndecryptablePacketsAlarm()->Fire(); @@ -11750,7 +11866,7 @@ TEST_P(QuicConnectionTest, PathValidationOnNewSocketSuccess) { std::make_unique<TestQuicPathValidationContext>( kNewSelfAddress, connection_.peer_address(), &new_writer), std::make_unique<TestValidationResultDelegate>( - kNewSelfAddress, connection_.peer_address(), &success)); + &connection_, kNewSelfAddress, connection_.peer_address(), &success)); EXPECT_EQ(0u, writer_->packets_write_attempts()); QuicFrames frames; @@ -11784,30 +11900,39 @@ TEST_P(QuicConnectionTest, NewPathValidationCancelsPreviousOne) { std::make_unique<TestQuicPathValidationContext>( kNewSelfAddress, connection_.peer_address(), &new_writer), std::make_unique<TestValidationResultDelegate>( - kNewSelfAddress, connection_.peer_address(), &success)); + &connection_, kNewSelfAddress, connection_.peer_address(), &success)); EXPECT_EQ(0u, writer_->packets_write_attempts()); // Start another path validation request. const QuicSocketAddress kNewSelfAddress2(QuicIpAddress::Any4(), 12346); EXPECT_NE(kNewSelfAddress2, connection_.self_address()); TestPacketWriter new_writer2(version(), &clock_, Perspective::IS_CLIENT); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)) - .Times(AtLeast(1u)) - .WillOnce(Invoke([&]() { - EXPECT_EQ(1u, new_writer2.packets_write_attempts()); - EXPECT_EQ(1u, new_writer2.path_challenge_frames().size()); - EXPECT_EQ(1u, new_writer2.padding_frames().size()); - EXPECT_EQ(kNewSelfAddress2.host(), - new_writer2.last_write_source_address()); - })); + if (!connection_.connection_migration_use_new_cid()) { + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)) + .Times(AtLeast(1u)) + .WillOnce(Invoke([&]() { + EXPECT_EQ(1u, new_writer2.packets_write_attempts()); + EXPECT_EQ(1u, new_writer2.path_challenge_frames().size()); + EXPECT_EQ(1u, new_writer2.padding_frames().size()); + EXPECT_EQ(kNewSelfAddress2.host(), + new_writer2.last_write_source_address()); + })); + } bool success2 = false; connection_.ValidatePath( std::make_unique<TestQuicPathValidationContext>( kNewSelfAddress2, connection_.peer_address(), &new_writer2), std::make_unique<TestValidationResultDelegate>( - kNewSelfAddress2, connection_.peer_address(), &success2)); + &connection_, kNewSelfAddress2, connection_.peer_address(), + &success2)); EXPECT_FALSE(success); - EXPECT_TRUE(connection_.HasPendingPathValidation()); + if (connection_.connection_migration_use_new_cid()) { + // There is no pening path validation as there is no available connection + // ID. + EXPECT_FALSE(connection_.HasPendingPathValidation()); + } else { + EXPECT_TRUE(connection_.HasPendingPathValidation()); + } } // Regression test for b/182571515. @@ -11825,12 +11950,12 @@ TEST_P(QuicConnectionTest, PathValidationRetry) { EXPECT_EQ(1u, writer_->padding_frames().size()); })); bool success = true; - connection_.ValidatePath( - std::make_unique<TestQuicPathValidationContext>( - connection_.self_address(), connection_.peer_address(), - writer_.get()), - std::make_unique<TestValidationResultDelegate>( - connection_.self_address(), connection_.peer_address(), &success)); + connection_.ValidatePath(std::make_unique<TestQuicPathValidationContext>( + connection_.self_address(), + connection_.peer_address(), writer_.get()), + std::make_unique<TestValidationResultDelegate>( + &connection_, connection_.self_address(), + connection_.peer_address(), &success)); EXPECT_EQ(1u, writer_->packets_write_attempts()); EXPECT_TRUE(connection_.HasPendingPathValidation()); @@ -11872,7 +11997,7 @@ TEST_P(QuicConnectionTest, PathValidationReceivesStatelessReset) { std::make_unique<TestQuicPathValidationContext>( kNewSelfAddress, connection_.peer_address(), &new_writer), std::make_unique<TestValidationResultDelegate>( - kNewSelfAddress, connection_.peer_address(), &success)); + &connection_, kNewSelfAddress, connection_.peer_address(), &success)); EXPECT_EQ(0u, writer_->packets_write_attempts()); EXPECT_TRUE(connection_.HasPendingPathValidation()); @@ -11916,7 +12041,7 @@ TEST_P(QuicConnectionTest, SendPathChallengeUsingBlockedNewSocket) { std::make_unique<TestQuicPathValidationContext>( kNewSelfAddress, connection_.peer_address(), &new_writer), std::make_unique<TestValidationResultDelegate>( - kNewSelfAddress, connection_.peer_address(), &success)); + &connection_, kNewSelfAddress, connection_.peer_address(), &success)); EXPECT_EQ(0u, writer_->packets_write_attempts()); new_writer.SetWritable(); @@ -11976,7 +12101,8 @@ TEST_P(QuicConnectionTest, SendPathChallengeUsingBlockedDefaultSocket) { std::make_unique<TestQuicPathValidationContext>( connection_.self_address(), kNewPeerAddress, writer_.get()), std::make_unique<TestValidationResultDelegate>( - connection_.self_address(), kNewPeerAddress, &success)); + &connection_, connection_.self_address(), kNewPeerAddress, + &success)); } EXPECT_EQ(1u, writer_->packets_write_attempts()); @@ -12020,7 +12146,7 @@ TEST_P(QuicConnectionTest, SendPathChallengeFailOnNewSocket) { std::make_unique<TestQuicPathValidationContext>( kNewSelfAddress, connection_.peer_address(), &new_writer), std::make_unique<TestValidationResultDelegate>( - kNewSelfAddress, connection_.peer_address(), &success)); + &connection_, kNewSelfAddress, connection_.peer_address(), &success)); EXPECT_EQ(1u, new_writer.packets_write_attempts()); EXPECT_EQ(1u, new_writer.path_challenge_frames().size()); EXPECT_EQ(1u, new_writer.padding_frames().size()); @@ -12052,12 +12178,12 @@ TEST_P(QuicConnectionTest, SendPathChallengeFailOnDefaultPath) { // packet creator. bool success = false; QuicConnection::ScopedPacketFlusher flusher(&connection_); - connection_.ValidatePath( - std::make_unique<TestQuicPathValidationContext>( - connection_.self_address(), connection_.peer_address(), - writer_.get()), - std::make_unique<TestValidationResultDelegate>( - connection_.self_address(), connection_.peer_address(), &success)); + connection_.ValidatePath(std::make_unique<TestQuicPathValidationContext>( + connection_.self_address(), + connection_.peer_address(), writer_.get()), + std::make_unique<TestValidationResultDelegate>( + &connection_, connection_.self_address(), + connection_.peer_address(), &success)); } EXPECT_EQ(1u, writer_->packets_write_attempts()); EXPECT_EQ(1u, writer_->path_challenge_frames().size()); @@ -12089,7 +12215,7 @@ TEST_P(QuicConnectionTest, SendPathChallengeFailOnAlternativePeerAddress) { std::make_unique<TestQuicPathValidationContext>( connection_.self_address(), kNewPeerAddress, writer_.get()), std::make_unique<TestValidationResultDelegate>( - connection_.self_address(), kNewPeerAddress, &success)); + &connection_, connection_.self_address(), kNewPeerAddress, &success)); EXPECT_EQ(1u, writer_->packets_write_attempts()); EXPECT_FALSE(connection_.HasPendingPathValidation()); @@ -12120,7 +12246,7 @@ TEST_P(QuicConnectionTest, std::make_unique<TestQuicPathValidationContext>( connection_.self_address(), kNewPeerAddress, writer_.get()), std::make_unique<TestValidationResultDelegate>( - connection_.self_address(), kNewPeerAddress, &success)); + &connection_, connection_.self_address(), kNewPeerAddress, &success)); EXPECT_TRUE(connection_.HasPendingPathValidation()); // Connection shouldn't be closed. EXPECT_TRUE(connection_.connected()); @@ -12391,7 +12517,12 @@ TEST_P(QuicConnectionTest, FailToWritePathResponse) { ProcessFramesPacketWithAddresses(frames, kSelfAddress, kNewPeerAddress, ENCRYPTION_FORWARD_SECURE); - EXPECT_EQ( + if (GetQuicReloadableFlag(quic_drop_unsent_path_response)) { + EXPECT_EQ(0u, QuicConnectionPeer::NumPendingPathChallengesToResponse( + &connection_)); + return; + } + ASSERT_EQ( 1u, QuicConnectionPeer::NumPendingPathChallengesToResponse(&connection_)); EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(1)); @@ -13444,6 +13575,9 @@ TEST_P(QuicConnectionTest, ServerHelloGetsReordered) { } TEST_P(QuicConnectionTest, MigratePath) { + EXPECT_CALL(visitor_, GetHandshakeState()) + .Times(testing::AtMost(1)) + .WillOnce(Return(HANDSHAKE_CONFIRMED)); EXPECT_CALL(visitor_, OnPathDegrading()); connection_.OnPathDegradingDetected(); const QuicSocketAddress kNewSelfAddress(QuicIpAddress::Any4(), 12345); @@ -13472,7 +13606,7 @@ TEST_P(QuicConnectionTest, MigrateToNewPathDuringProbing) { std::make_unique<TestQuicPathValidationContext>( kNewSelfAddress, connection_.peer_address(), &new_writer), std::make_unique<TestValidationResultDelegate>( - kNewSelfAddress, connection_.peer_address(), &success)); + &connection_, kNewSelfAddress, connection_.peer_address(), &success)); EXPECT_TRUE(connection_.HasPendingPathValidation()); EXPECT_TRUE(QuicConnectionPeer::IsAlternativePath( &connection_, kNewSelfAddress, connection_.peer_address())); @@ -13568,7 +13702,6 @@ TEST_P(QuicConnectionTest, NewTokenFrameInstigateAcks) { if (!version().HasIetfQuicFrames()) { return; } - SetQuicReloadableFlag(quic_enable_token_based_address_validation, true); EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); QuicNewTokenFrame* new_token = new QuicNewTokenFrame(); @@ -13583,7 +13716,6 @@ TEST_P(QuicConnectionTest, ServerClosesConnectionOnNewTokenFrame) { if (!version().HasIetfQuicFrames()) { return; } - SetQuicReloadableFlag(quic_enable_token_based_address_validation, true); set_perspective(Perspective::IS_SERVER); QuicNewTokenFrame* new_token = new QuicNewTokenFrame(); EXPECT_CALL(visitor_, OnNewTokenReceived(_)).Times(0); @@ -13686,8 +13818,7 @@ TEST_P(QuicConnectionTest, // Regression test for b/177312785 TEST_P(QuicConnectionTest, PeerMigrateBeforeHandshakeConfirm) { - if (!VersionHasIetfQuicFrames(version().transport_version) || - !GetQuicReloadableFlag(quic_start_peer_migration_earlier)) { + if (!VersionHasIetfQuicFrames(version().transport_version)) { return; } set_perspective(Perspective::IS_SERVER); @@ -13755,11 +13886,34 @@ TEST_P(QuicConnectionTest, TryToFlushAckWithAckQueued) { TEST_P(QuicConnectionTest, PathChallengeBeforePeerIpAddressChangeAtServer) { set_perspective(Perspective::IS_SERVER); - if (!connection_.validate_client_address()) { + if (!connection_.connection_migration_use_new_cid()) { return; } PathProbeTestInit(Perspective::IS_SERVER); + SetClientConnectionId(TestConnectionId(1)); + connection_.CreateConnectionIdManager(); + QuicConnectionId server_cid0 = connection_.connection_id(); + QuicConnectionId client_cid0 = connection_.client_connection_id(); + QuicConnectionId client_cid1 = TestConnectionId(2); + QuicConnectionId server_cid1; + // Sends new server CID to client. + EXPECT_CALL(visitor_, OnServerConnectionIdIssued(_)) + .WillOnce( + Invoke([&](const QuicConnectionId& cid) { server_cid1 = cid; })); + EXPECT_CALL(visitor_, SendNewConnectionId(_)); + connection_.MaybeSendConnectionIdToClient(); + // Receives new client CID from client. + QuicNewConnectionIdFrame new_cid_frame; + new_cid_frame.connection_id = client_cid1; + new_cid_frame.sequence_number = 1u; + new_cid_frame.retire_prior_to = 0u; + connection_.OnNewConnectionIdFrame(new_cid_frame); + auto* packet_creator = QuicConnectionPeer::GetPacketCreator(&connection_); + ASSERT_EQ(packet_creator->GetDestinationConnectionId(), client_cid0); + ASSERT_EQ(packet_creator->GetSourceConnectionId(), server_cid0); + + peer_creator_.SetServerConnectionId(server_cid1); const QuicSocketAddress kNewPeerAddress = QuicSocketAddress(QuicIpAddress::Loopback4(), /*port=*/23456); QuicPathFrameBuffer path_challenge_payload{0, 1, 2, 3, 4, 5, 6, 7}; @@ -13783,6 +13937,15 @@ TEST_P(QuicConnectionTest, PathChallengeBeforePeerIpAddressChangeAtServer) { EXPECT_EQ(kPeerAddress, connection_.peer_address()); EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); EXPECT_TRUE(connection_.HasPendingPathValidation()); + const auto* default_path = QuicConnectionPeer::GetDefaultPath(&connection_); + const auto* alternative_path = + QuicConnectionPeer::GetAlternativePath(&connection_); + EXPECT_EQ(default_path->client_connection_id, client_cid0); + EXPECT_EQ(default_path->server_connection_id, server_cid0); + EXPECT_EQ(alternative_path->client_connection_id, client_cid1); + EXPECT_EQ(alternative_path->server_connection_id, server_cid1); + EXPECT_EQ(packet_creator->GetDestinationConnectionId(), client_cid0); + EXPECT_EQ(packet_creator->GetSourceConnectionId(), server_cid0); // Process another packet with a different peer address on server side will // start connection migration. @@ -13819,6 +13982,14 @@ TEST_P(QuicConnectionTest, PathChallengeBeforePeerIpAddressChangeAtServer) { EXPECT_CALL(*send_algorithm_, InRecovery()).Times(AnyNumber()); EXPECT_CALL(*send_algorithm_, PopulateConnectionStats(_)).Times(AnyNumber()); connection_.SetSendAlgorithm(send_algorithm_); + EXPECT_EQ(default_path->client_connection_id, client_cid1); + EXPECT_EQ(default_path->server_connection_id, server_cid1); + // The previous default path is kept as alternative path before reverse path + // validation finishes. + EXPECT_EQ(alternative_path->client_connection_id, client_cid0); + EXPECT_EQ(alternative_path->server_connection_id, server_cid0); + EXPECT_EQ(packet_creator->GetDestinationConnectionId(), client_cid1); + EXPECT_EQ(packet_creator->GetSourceConnectionId(), server_cid1); EXPECT_EQ(kNewPeerAddress, connection_.peer_address()); EXPECT_EQ(kNewPeerAddress, connection_.effective_peer_address()); @@ -13842,6 +14013,15 @@ TEST_P(QuicConnectionTest, PathChallengeBeforePeerIpAddressChangeAtServer) { ProcessFramesPacketWithAddresses(frames3, kSelfAddress, kNewPeerAddress, ENCRYPTION_FORWARD_SECURE); EXPECT_EQ(NO_CHANGE, connection_.active_effective_peer_migration_type()); + // Verify that alternative_path_ is cleared and the peer CID is retired. + EXPECT_TRUE(alternative_path->client_connection_id.IsEmpty()); + EXPECT_TRUE(alternative_path->server_connection_id.IsEmpty()); + EXPECT_FALSE(alternative_path->stateless_reset_token_received); + auto* retire_peer_issued_cid_alarm = + connection_.GetRetirePeerIssuedConnectionIdAlarm(); + ASSERT_TRUE(retire_peer_issued_cid_alarm->IsSet()); + EXPECT_CALL(visitor_, SendRetireConnectionId(/*sequence_number=*/0u)); + retire_peer_issued_cid_alarm->Fire(); // Verify the anti-amplification limit is lifted by sending a packet larger // than the anti-amplification limit. @@ -13853,12 +14033,25 @@ TEST_P(QuicConnectionTest, PathChallengeBeforePeerIpAddressChangeAtServer) { TEST_P(QuicConnectionTest, PathValidationSucceedsBeforePeerIpAddressChangeAtServer) { set_perspective(Perspective::IS_SERVER); - if (!connection_.validate_client_address()) { + if (!connection_.connection_migration_use_new_cid()) { return; } PathProbeTestInit(Perspective::IS_SERVER); + connection_.CreateConnectionIdManager(); + + QuicConnectionId server_cid0 = connection_.connection_id(); + QuicConnectionId server_cid1; + // Sends new server CID to client. + EXPECT_CALL(visitor_, OnServerConnectionIdIssued(_)) + .WillOnce( + Invoke([&](const QuicConnectionId& cid) { server_cid1 = cid; })); + EXPECT_CALL(visitor_, SendNewConnectionId(_)); + connection_.MaybeSendConnectionIdToClient(); + auto* packet_creator = QuicConnectionPeer::GetPacketCreator(&connection_); + ASSERT_EQ(packet_creator->GetSourceConnectionId(), server_cid0); // Receive probing packet with new peer address. + peer_creator_.SetServerConnectionId(server_cid1); const QuicSocketAddress kNewPeerAddress(QuicIpAddress::Loopback4(), /*port=*/23456); QuicPathFrameBuffer payload; @@ -13883,6 +14076,12 @@ TEST_P(QuicConnectionTest, ProcessFramesPacketWithAddresses(frames1, kSelfAddress, kNewPeerAddress, ENCRYPTION_FORWARD_SECURE); EXPECT_TRUE(connection_.HasPendingPathValidation()); + const auto* default_path = QuicConnectionPeer::GetDefaultPath(&connection_); + const auto* alternative_path = + QuicConnectionPeer::GetAlternativePath(&connection_); + EXPECT_EQ(default_path->server_connection_id, server_cid0); + EXPECT_EQ(alternative_path->server_connection_id, server_cid1); + EXPECT_EQ(packet_creator->GetSourceConnectionId(), server_cid0); // Receive PATH_RESPONSE should mark the new peer address validated. QuicFrames frames3; @@ -13920,6 +14119,12 @@ TEST_P(QuicConnectionTest, EXPECT_NE(connection_.sent_packet_manager().GetSendAlgorithm(), send_algorithm_); + EXPECT_EQ(default_path->server_connection_id, server_cid1); + EXPECT_EQ(packet_creator->GetSourceConnectionId(), server_cid1); + // Verify that alternative_path_ is cleared. + EXPECT_TRUE(alternative_path->server_connection_id.IsEmpty()); + EXPECT_FALSE(alternative_path->stateless_reset_token_received); + // Switch to use the mock send algorithm. send_algorithm_ = new StrictMock<MockSendAlgorithm>(); EXPECT_CALL(*send_algorithm_, CanSend(_)).WillRepeatedly(Return(true)); @@ -14005,6 +14210,255 @@ TEST_P(QuicConnectionTest, } TEST_P(QuicConnectionTest, + PathValidationFailedOnClientDueToLackOfServerConnectionId) { + QuicConfig config; + config.SetConnectionOptionsToSend({kRVCM}); + EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); + connection_.SetFromConfig(config); + if (!connection_.connection_migration_use_new_cid()) { + return; + } + PathProbeTestInit(Perspective::IS_CLIENT, + /*receive_new_server_connection_id=*/false); + + const QuicSocketAddress kNewSelfAddress(QuicIpAddress::Loopback4(), + /*port=*/34567); + + bool success; + connection_.ValidatePath( + std::make_unique<TestQuicPathValidationContext>( + kNewSelfAddress, connection_.peer_address(), writer_.get()), + std::make_unique<TestValidationResultDelegate>( + &connection_, kNewSelfAddress, connection_.peer_address(), &success)); + + EXPECT_FALSE(success); +} + +TEST_P(QuicConnectionTest, + PathValidationFailedOnClientDueToLackOfClientConnectionIdTheSecondTime) { + QuicConfig config; + config.SetConnectionOptionsToSend({kRVCM}); + EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); + connection_.SetFromConfig(config); + if (!connection_.connection_migration_use_new_cid()) { + return; + } + PathProbeTestInit(Perspective::IS_CLIENT, + /*receive_new_server_connection_id=*/false); + SetClientConnectionId(TestConnectionId(1)); + + // Make sure server connection ID is available for the 1st validation. + QuicConnectionId server_cid0 = connection_.connection_id(); + QuicConnectionId server_cid1 = TestConnectionId(2); + QuicConnectionId server_cid2 = TestConnectionId(4); + QuicConnectionId client_cid1; + QuicNewConnectionIdFrame frame1; + frame1.connection_id = server_cid1; + frame1.sequence_number = 1u; + frame1.retire_prior_to = 0u; + frame1.stateless_reset_token = + QuicUtils::GenerateStatelessResetToken(frame1.connection_id); + connection_.OnNewConnectionIdFrame(frame1); + const auto* packet_creator = + QuicConnectionPeer::GetPacketCreator(&connection_); + ASSERT_EQ(packet_creator->GetDestinationConnectionId(), server_cid0); + + // Client will issue a new client connection ID to server. + EXPECT_CALL(visitor_, SendNewConnectionId(_)) + .WillOnce(Invoke([&](const QuicNewConnectionIdFrame& frame) { + client_cid1 = frame.connection_id; + })); + + const QuicSocketAddress kSelfAddress1(QuicIpAddress::Any4(), 12345); + ASSERT_NE(kSelfAddress1, connection_.self_address()); + bool success1; + connection_.ValidatePath( + std::make_unique<TestQuicPathValidationContext>( + kSelfAddress1, connection_.peer_address(), writer_.get()), + std::make_unique<TestValidationResultDelegate>( + &connection_, kSelfAddress1, connection_.peer_address(), &success1)); + + // Migrate upon 1st validation success. + TestPacketWriter new_writer(version(), &clock_, Perspective::IS_CLIENT); + ASSERT_TRUE(connection_.MigratePath(kSelfAddress1, connection_.peer_address(), + &new_writer, /*owns_writer=*/false)); + QuicConnectionPeer::RetirePeerIssuedConnectionIdsNoLongerOnPath(&connection_); + const auto* default_path = QuicConnectionPeer::GetDefaultPath(&connection_); + EXPECT_EQ(default_path->client_connection_id, client_cid1); + EXPECT_EQ(default_path->server_connection_id, server_cid1); + EXPECT_EQ(default_path->stateless_reset_token, frame1.stateless_reset_token); + EXPECT_TRUE(default_path->stateless_reset_token_received); + const auto* alternative_path = + QuicConnectionPeer::GetAlternativePath(&connection_); + EXPECT_TRUE(alternative_path->client_connection_id.IsEmpty()); + EXPECT_TRUE(alternative_path->server_connection_id.IsEmpty()); + EXPECT_FALSE(alternative_path->stateless_reset_token_received); + ASSERT_EQ(packet_creator->GetDestinationConnectionId(), server_cid1); + + // Client will retire server connection ID on old default_path. + auto* retire_peer_issued_cid_alarm = + connection_.GetRetirePeerIssuedConnectionIdAlarm(); + ASSERT_TRUE(retire_peer_issued_cid_alarm->IsSet()); + EXPECT_CALL(visitor_, SendRetireConnectionId(/*sequence_number=*/0u)); + retire_peer_issued_cid_alarm->Fire(); + + // Another server connection ID is available to client. + QuicNewConnectionIdFrame frame2; + frame2.connection_id = server_cid2; + frame2.sequence_number = 2u; + frame2.retire_prior_to = 1u; + frame2.stateless_reset_token = + QuicUtils::GenerateStatelessResetToken(frame2.connection_id); + connection_.OnNewConnectionIdFrame(frame2); + + const QuicSocketAddress kSelfAddress2(QuicIpAddress::Loopback4(), + /*port=*/45678); + bool success2; + connection_.ValidatePath( + std::make_unique<TestQuicPathValidationContext>( + kSelfAddress2, connection_.peer_address(), writer_.get()), + std::make_unique<TestValidationResultDelegate>( + &connection_, kSelfAddress2, connection_.peer_address(), &success2)); + // Since server does not retire any client connection ID yet, 2nd validation + // would fail due to lack of client connection ID. + EXPECT_FALSE(success2); +} + +TEST_P(QuicConnectionTest, ServerConnectionIdRetiredUponPathValidationFailure) { + QuicConfig config; + config.SetConnectionOptionsToSend({kRVCM}); + EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); + connection_.SetFromConfig(config); + if (!connection_.connection_migration_use_new_cid()) { + return; + } + PathProbeTestInit(Perspective::IS_CLIENT); + + // Make sure server connection ID is available for validation. + QuicNewConnectionIdFrame frame; + frame.connection_id = TestConnectionId(2); + frame.sequence_number = 1u; + frame.retire_prior_to = 0u; + frame.stateless_reset_token = + QuicUtils::GenerateStatelessResetToken(frame.connection_id); + connection_.OnNewConnectionIdFrame(frame); + + const QuicSocketAddress kNewSelfAddress(QuicIpAddress::Loopback4(), + /*port=*/34567); + bool success; + connection_.ValidatePath( + std::make_unique<TestQuicPathValidationContext>( + kNewSelfAddress, connection_.peer_address(), writer_.get()), + std::make_unique<TestValidationResultDelegate>( + &connection_, kNewSelfAddress, connection_.peer_address(), &success)); + + auto* path_validator = QuicConnectionPeer::path_validator(&connection_); + path_validator->CancelPathValidation(); + QuicConnectionPeer::RetirePeerIssuedConnectionIdsNoLongerOnPath(&connection_); + EXPECT_FALSE(success); + const auto* alternative_path = + QuicConnectionPeer::GetAlternativePath(&connection_); + EXPECT_TRUE(alternative_path->client_connection_id.IsEmpty()); + EXPECT_TRUE(alternative_path->server_connection_id.IsEmpty()); + EXPECT_FALSE(alternative_path->stateless_reset_token_received); + + // Client will retire server connection ID on alternative_path. + auto* retire_peer_issued_cid_alarm = + connection_.GetRetirePeerIssuedConnectionIdAlarm(); + ASSERT_TRUE(retire_peer_issued_cid_alarm->IsSet()); + EXPECT_CALL(visitor_, SendRetireConnectionId(/*sequence_number=*/1u)); + retire_peer_issued_cid_alarm->Fire(); +} + +TEST_P(QuicConnectionTest, + MigratePathDirectlyFailedDueToLackOfServerConnectionId) { + QuicConfig config; + config.SetConnectionOptionsToSend({kRVCM}); + EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); + connection_.SetFromConfig(config); + if (!connection_.connection_migration_use_new_cid()) { + return; + } + PathProbeTestInit(Perspective::IS_CLIENT, + /*receive_new_server_connection_id=*/false); + const QuicSocketAddress kSelfAddress1(QuicIpAddress::Any4(), 12345); + ASSERT_NE(kSelfAddress1, connection_.self_address()); + + TestPacketWriter new_writer(version(), &clock_, Perspective::IS_CLIENT); + ASSERT_FALSE(connection_.MigratePath(kSelfAddress1, + connection_.peer_address(), &new_writer, + /*owns_writer=*/false)); +} + +TEST_P(QuicConnectionTest, + MigratePathDirectlyFailedDueToLackOfClientConnectionIdTheSecondTime) { + QuicConfig config; + config.SetConnectionOptionsToSend({kRVCM}); + EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); + connection_.SetFromConfig(config); + if (!connection_.connection_migration_use_new_cid()) { + return; + } + PathProbeTestInit(Perspective::IS_CLIENT, + /*receive_new_server_connection_id=*/false); + SetClientConnectionId(TestConnectionId(1)); + + // Make sure server connection ID is available for the 1st migration. + QuicNewConnectionIdFrame frame1; + frame1.connection_id = TestConnectionId(2); + frame1.sequence_number = 1u; + frame1.retire_prior_to = 0u; + frame1.stateless_reset_token = + QuicUtils::GenerateStatelessResetToken(frame1.connection_id); + connection_.OnNewConnectionIdFrame(frame1); + + // Client will issue a new client connection ID to server. + QuicConnectionId new_client_connection_id; + EXPECT_CALL(visitor_, SendNewConnectionId(_)) + .WillOnce(Invoke([&](const QuicNewConnectionIdFrame& frame) { + new_client_connection_id = frame.connection_id; + })); + + // 1st migration is successful. + const QuicSocketAddress kSelfAddress1(QuicIpAddress::Any4(), 12345); + ASSERT_NE(kSelfAddress1, connection_.self_address()); + TestPacketWriter new_writer(version(), &clock_, Perspective::IS_CLIENT); + ASSERT_TRUE(connection_.MigratePath(kSelfAddress1, connection_.peer_address(), + &new_writer, + /*owns_writer=*/false)); + QuicConnectionPeer::RetirePeerIssuedConnectionIdsNoLongerOnPath(&connection_); + const auto* default_path = QuicConnectionPeer::GetDefaultPath(&connection_); + EXPECT_EQ(default_path->client_connection_id, new_client_connection_id); + EXPECT_EQ(default_path->server_connection_id, frame1.connection_id); + EXPECT_EQ(default_path->stateless_reset_token, frame1.stateless_reset_token); + EXPECT_TRUE(default_path->stateless_reset_token_received); + + // Client will retire server connection ID on old default_path. + auto* retire_peer_issued_cid_alarm = + connection_.GetRetirePeerIssuedConnectionIdAlarm(); + ASSERT_TRUE(retire_peer_issued_cid_alarm->IsSet()); + EXPECT_CALL(visitor_, SendRetireConnectionId(/*sequence_number=*/0u)); + retire_peer_issued_cid_alarm->Fire(); + + // Another server connection ID is available to client. + QuicNewConnectionIdFrame frame2; + frame2.connection_id = TestConnectionId(4); + frame2.sequence_number = 2u; + frame2.retire_prior_to = 1u; + frame2.stateless_reset_token = + QuicUtils::GenerateStatelessResetToken(frame2.connection_id); + connection_.OnNewConnectionIdFrame(frame2); + + // Since server does not retire any client connection ID yet, 2nd migration + // would fail due to lack of client connection ID. + const QuicSocketAddress kSelfAddress2(QuicIpAddress::Loopback4(), + /*port=*/45678); + ASSERT_FALSE(connection_.MigratePath(kSelfAddress2, + connection_.peer_address(), &new_writer, + /*owns_writer=*/false)); +} + +TEST_P(QuicConnectionTest, CloseConnectionAfterReceiveNewConnectionIdFromPeerUsingEmptyCID) { if (!version().HasIetfQuicFrames()) { return; @@ -14098,7 +14552,7 @@ TEST_P(QuicConnectionTest, } QuicConnectionPeer::EnableMultipleConnectionIdSupport(&connection_); set_perspective(Perspective::IS_SERVER); - connection_.set_client_connection_id(TestConnectionId(0)); + SetClientConnectionId(TestConnectionId(0)); QuicNewConnectionIdFrame frame; frame.sequence_number = 1u; @@ -14129,9 +14583,71 @@ TEST_P(QuicConnectionTest, TestConnectionId(2)); } +TEST_P( + QuicConnectionTest, + ReplacePeerIssuedConnectionIdOnBothPathsTriggeredByNewConnectionIdFrame) { + if (!version().HasIetfQuicFrames() || !connection_.use_path_validator() || + !connection_.use_connection_id_on_default_path() || + !connection_.count_bytes_on_alternative_path_separately()) { + return; + } + QuicConnectionPeer::EnableMultipleConnectionIdSupport(&connection_); + PathProbeTestInit(Perspective::IS_SERVER); + SetClientConnectionId(TestConnectionId(0)); + + // Populate alternative_path_ with probing packet. + std::unique_ptr<SerializedPacket> probing_packet = ConstructProbingPacket(); + + std::unique_ptr<QuicReceivedPacket> received(ConstructReceivedPacket( + QuicEncryptedPacket(probing_packet->encrypted_buffer, + probing_packet->encrypted_length), + clock_.Now())); + QuicIpAddress new_host; + new_host.FromString("1.1.1.1"); + ProcessReceivedPacket(kSelfAddress, + QuicSocketAddress(new_host, /*port=*/23456), *received); + + EXPECT_EQ( + TestConnectionId(0), + QuicConnectionPeer::GetClientConnectionIdOnAlternativePath(&connection_)); + + QuicNewConnectionIdFrame frame; + frame.sequence_number = 1u; + frame.connection_id = TestConnectionId(1); + frame.stateless_reset_token = + QuicUtils::GenerateStatelessResetToken(frame.connection_id); + frame.retire_prior_to = 0u; + + EXPECT_TRUE(connection_.OnNewConnectionIdFrame(frame)); + auto* retire_peer_issued_cid_alarm = + connection_.GetRetirePeerIssuedConnectionIdAlarm(); + ASSERT_FALSE(retire_peer_issued_cid_alarm->IsSet()); + + frame.sequence_number = 2u; + frame.connection_id = TestConnectionId(2); + frame.stateless_reset_token = + QuicUtils::GenerateStatelessResetToken(frame.connection_id); + frame.retire_prior_to = 1u; // CID associated with #1 will be retired. + + EXPECT_TRUE(connection_.OnNewConnectionIdFrame(frame)); + ASSERT_TRUE(retire_peer_issued_cid_alarm->IsSet()); + EXPECT_EQ(connection_.client_connection_id(), TestConnectionId(0)); + + EXPECT_CALL(visitor_, SendRetireConnectionId(/*sequence_number=*/0u)); + retire_peer_issued_cid_alarm->Fire(); + EXPECT_EQ(connection_.client_connection_id(), TestConnectionId(2)); + EXPECT_EQ(connection_.packet_creator().GetDestinationConnectionId(), + TestConnectionId(2)); + // Clean up alternative path connection ID. + EXPECT_EQ( + TestConnectionId(2), + QuicConnectionPeer::GetClientConnectionIdOnAlternativePath(&connection_)); +} + TEST_P(QuicConnectionTest, CloseConnectionAfterReceiveRetireConnectionIdWhenNoCIDIssued) { - if (!version().HasIetfQuicFrames()) { + if (!version().HasIetfQuicFrames() || + GetQuicReloadableFlag(quic_use_connection_id_on_default_path_v2)) { return; } QuicConnectionPeer::EnableMultipleConnectionIdSupport(&connection_); @@ -14151,7 +14667,8 @@ TEST_P(QuicConnectionTest, } TEST_P(QuicConnectionTest, RetireConnectionIdFrameResultsInError) { - if (!version().HasIetfQuicFrames()) { + if (!version().HasIetfQuicFrames() || + GetQuicReloadableFlag(quic_use_connection_id_on_default_path_v2)) { return; } QuicConnectionPeer::EnableMultipleConnectionIdSupport(&connection_); @@ -14175,8 +14692,40 @@ TEST_P(QuicConnectionTest, RetireConnectionIdFrameResultsInError) { IsError(IETF_QUIC_PROTOCOL_VIOLATION)); } +TEST_P(QuicConnectionTest, + ServerRetireSelfIssuedConnectionIdWithoutSendingNewConnectionIdBefore) { + if (!connection_.support_multiple_connection_ids()) { + return; + } + QuicConnectionPeer::EnableMultipleConnectionIdSupport(&connection_); + set_perspective(Perspective::IS_SERVER); + connection_.CreateConnectionIdManager(); + + auto* retire_self_issued_cid_alarm = + connection_.GetRetireSelfIssuedConnectionIdAlarm(); + ASSERT_FALSE(retire_self_issued_cid_alarm->IsSet()); + + QuicConnectionId cid0 = connection_id_; + QuicRetireConnectionIdFrame frame; + frame.sequence_number = 0u; + if (!GetQuicReloadableFlag(quic_use_connection_id_on_default_path_v2) || + connection_.connection_migration_use_new_cid()) { + EXPECT_CALL(visitor_, OnServerConnectionIdIssued(_)).Times(2); + EXPECT_CALL(visitor_, SendNewConnectionId(_)).Times(2); + } + EXPECT_TRUE(connection_.OnRetireConnectionIdFrame(frame)); + if (!GetQuicReloadableFlag(quic_use_connection_id_on_default_path_v2)) { + ASSERT_TRUE(retire_self_issued_cid_alarm->IsSet()); + // cid0 is retired when the retire CID alarm fires. + if (!GetQuicReloadableFlag(quic_use_connection_id_on_default_path_v2)) + EXPECT_CALL(visitor_, OnServerConnectionIdRetired(cid0)); + retire_self_issued_cid_alarm->Fire(); + } +} + TEST_P(QuicConnectionTest, ServerRetireSelfIssuedConnectionId) { - if (!version().HasIetfQuicFrames()) { + if (!version().HasIetfQuicFrames() || + GetQuicReloadableFlag(quic_use_connection_id_on_default_path_v2)) { return; } QuicConnectionPeer::EnableMultipleConnectionIdSupport(&connection_); @@ -14219,6 +14768,121 @@ TEST_P(QuicConnectionTest, ServerRetireSelfIssuedConnectionId) { ElementsAre(cid1, cid2)); } +TEST_P(QuicConnectionTest, PatchMissingClientConnectionIdOntoAlternativePath) { + if (!version().HasIetfQuicFrames() || + !connection_.support_multiple_connection_ids() || + !connection_.use_connection_id_on_default_path()) { + return; + } + set_perspective(Perspective::IS_SERVER); + connection_.CreateConnectionIdManager(); + connection_.set_client_connection_id(TestConnectionId(1)); + + // Set up the state after path probing. + const auto* default_path = QuicConnectionPeer::GetDefaultPath(&connection_); + auto* alternative_path = QuicConnectionPeer::GetAlternativePath(&connection_); + QuicIpAddress new_host; + new_host.FromString("12.12.12.12"); + alternative_path->self_address = default_path->self_address; + alternative_path->peer_address = QuicSocketAddress(new_host, 12345); + alternative_path->server_connection_id = TestConnectionId(3); + ASSERT_TRUE(alternative_path->client_connection_id.IsEmpty()); + ASSERT_FALSE(alternative_path->stateless_reset_token_received); + + QuicNewConnectionIdFrame frame; + frame.sequence_number = 1u; + frame.connection_id = TestConnectionId(5); + frame.stateless_reset_token = + QuicUtils::GenerateStatelessResetToken(frame.connection_id); + frame.retire_prior_to = 0u; + // New ID is patched onto the alternative path when the needed + // NEW_CONNECTION_ID frame is received after PATH_CHALLENGE frame. + connection_.OnNewConnectionIdFrame(frame); + + ASSERT_EQ(alternative_path->client_connection_id, frame.connection_id); + ASSERT_EQ(alternative_path->stateless_reset_token, + frame.stateless_reset_token); + ASSERT_TRUE(alternative_path->stateless_reset_token_received); +} + +TEST_P(QuicConnectionTest, PatchMissingClientConnectionIdOntoDefaultPath) { + if (!version().HasIetfQuicFrames() || + !connection_.support_multiple_connection_ids() || + !connection_.use_connection_id_on_default_path()) { + return; + } + set_perspective(Perspective::IS_SERVER); + connection_.CreateConnectionIdManager(); + connection_.set_client_connection_id(TestConnectionId(1)); + + // Set up the state after peer migration without probing. + auto* default_path = QuicConnectionPeer::GetDefaultPath(&connection_); + auto* alternative_path = QuicConnectionPeer::GetAlternativePath(&connection_); + auto* packet_creator = QuicConnectionPeer::GetPacketCreator(&connection_); + *alternative_path = std::move(*default_path); + QuicIpAddress new_host; + new_host.FromString("12.12.12.12"); + default_path->self_address = default_path->self_address; + default_path->peer_address = QuicSocketAddress(new_host, 12345); + default_path->server_connection_id = TestConnectionId(3); + packet_creator->SetDefaultPeerAddress(default_path->peer_address); + packet_creator->SetServerConnectionId(default_path->server_connection_id); + packet_creator->SetClientConnectionId(default_path->client_connection_id); + + ASSERT_FALSE(default_path->validated); + ASSERT_TRUE(default_path->client_connection_id.IsEmpty()); + ASSERT_FALSE(default_path->stateless_reset_token_received); + + QuicNewConnectionIdFrame frame; + frame.sequence_number = 1u; + frame.connection_id = TestConnectionId(5); + frame.stateless_reset_token = + QuicUtils::GenerateStatelessResetToken(frame.connection_id); + frame.retire_prior_to = 0u; + // New ID is patched onto the default path when the needed + // NEW_CONNECTION_ID frame is received after PATH_CHALLENGE frame. + connection_.OnNewConnectionIdFrame(frame); + + ASSERT_EQ(default_path->client_connection_id, frame.connection_id); + ASSERT_EQ(default_path->stateless_reset_token, frame.stateless_reset_token); + ASSERT_TRUE(default_path->stateless_reset_token_received); + ASSERT_EQ(packet_creator->GetDestinationConnectionId(), frame.connection_id); +} + +TEST_P(QuicConnectionTest, ShouldGeneratePacketBlockedByMissingConnectionId) { + if (!version().HasIetfQuicFrames() || + !connection_.support_multiple_connection_ids()) { + return; + } + set_perspective(Perspective::IS_SERVER); + connection_.set_client_connection_id(TestConnectionId(1)); + connection_.CreateConnectionIdManager(); + if (version().SupportsAntiAmplificationLimit()) { + QuicConnectionPeer::SetAddressValidated(&connection_); + } + + ASSERT_TRUE( + connection_.ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA, NOT_HANDSHAKE)); + + QuicPacketCreator* packet_creator = + QuicConnectionPeer::GetPacketCreator(&connection_); + QuicIpAddress peer_host1; + peer_host1.FromString("12.12.12.12"); + QuicSocketAddress peer_address1(peer_host1, 1235); + + { + // No connection ID is available as context is created without any. + QuicPacketCreator::ScopedPeerAddressContext context( + packet_creator, peer_address1, EmptyQuicConnectionId(), + EmptyQuicConnectionId(), + /*update_connection_id=*/true); + ASSERT_FALSE(connection_.ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA, + NOT_HANDSHAKE)); + } + ASSERT_TRUE( + connection_.ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA, NOT_HANDSHAKE)); +} + // Regression test for b/182571515 TEST_P(QuicConnectionTest, LostDataThenGetAcknowledged) { set_perspective(Perspective::IS_SERVER); @@ -14278,6 +14942,53 @@ TEST_P(QuicConnectionTest, LostDataThenGetAcknowledged) { } } +TEST_P(QuicConnectionTest, PtoSendStreamData) { + if (!connection_.SupportsMultiplePacketNumberSpaces()) { + return; + } + set_perspective(Perspective::IS_SERVER); + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); + } + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); + use_tagging_decrypter(); + ProcessCryptoPacketAtLevel(1, ENCRYPTION_INITIAL); + EXPECT_TRUE(connection_.HasPendingAcks()); + + connection_.SetEncrypter(ENCRYPTION_INITIAL, + std::make_unique<TaggingEncrypter>(0x01)); + connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); + // Send INITIAL 1. + connection_.SendCryptoDataWithString("foo", 0, ENCRYPTION_INITIAL); + + connection_.SetEncrypter(ENCRYPTION_HANDSHAKE, + std::make_unique<TaggingEncrypter>(0x02)); + connection_.SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE); + SetDecrypter(ENCRYPTION_HANDSHAKE, + std::make_unique<StrictTaggingDecrypter>(0x02)); + // Send HANDSHAKE packets. + EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1); + connection_.SendCryptoDataWithString("foo", 0, ENCRYPTION_HANDSHAKE); + + connection_.SetEncrypter(ENCRYPTION_FORWARD_SECURE, + std::make_unique<TaggingEncrypter>(0x03)); + connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); + + // Send half RTT packet with congestion control blocked. + EXPECT_CALL(*send_algorithm_, CanSend(_)).WillRepeatedly(Return(false)); + connection_.SendStreamDataWithString(2, std::string(1500, 'a'), 0, NO_FIN); + + ASSERT_TRUE(connection_.GetRetransmissionAlarm()->IsSet()); + connection_.GetRetransmissionAlarm()->Fire(); + if (GetQuicReloadableFlag(quic_donot_pto_half_rtt_data)) { + // Verify INITIAL and HANDSHAKE get retransmitted. + EXPECT_EQ(0x02020202u, writer_->final_bytes_of_last_packet()); + } else { + // Application data preempts handshake data when PTO fires. + EXPECT_EQ(0x03030303u, writer_->final_bytes_of_last_packet()); + } +} + } // namespace } // namespace test } // namespace quic 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 1bb37035912..48d228bff31 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 @@ -8,10 +8,11 @@ #include <cstdint> #include <string> +#include "absl/container/flat_hash_map.h" #include "quic/core/frames/quic_frame.h" -#include "quic/core/quic_circular_deque.h" #include "quic/core/quic_connection_id.h" #include "quic/core/quic_types.h" +#include "common/quiche_circular_deque.h" namespace quic { @@ -163,7 +164,7 @@ class QUIC_EXPORT_PRIVATE QuicControlFrameManager { // frame. void WriteOrBufferQuicFrame(QuicFrame frame); - QuicCircularDeque<QuicFrame> control_frames_; + quiche::QuicheCircularDeque<QuicFrame> control_frames_; // Id of latest saved control frame. 0 if no control frame has been saved. QuicControlFrameId last_control_frame_id_; @@ -182,7 +183,7 @@ class QUIC_EXPORT_PRIVATE QuicControlFrameManager { DelegateInterface* delegate_; // Last sent window update frame for each stream. - QuicSmallMap<QuicStreamId, QuicControlFrameId, 10> window_update_frames_; + absl::flat_hash_map<QuicStreamId, QuicControlFrameId> window_update_frames_; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.cc index fc9be1764a2..1dd68995e2f 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 @@ -11,7 +11,7 @@ #include "absl/strings/string_view.h" #include "third_party/boringssl/src/include/openssl/sha.h" #include "quic/platform/api/quic_flag_utils.h" -#include "common/platform/api/quiche_text_utils.h" +#include "common/quiche_text_utils.h" namespace quic { 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 88fdda9d6c2..4e07f34b616 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 @@ -354,8 +354,7 @@ class QuicCryptoServerStreamTestWithFakeProofSource }; // Regression test for b/35422225, in which multiple CHLOs arriving on the same -// connection in close succession could cause a crash, especially when the use -// of Mentat signing meant that it took a while for each CHLO to be processed. +// connection in close succession could cause a crash. TEST_F(QuicCryptoServerStreamTestWithFakeProofSource, MultipleChlo) { Initialize(); GetFakeProofSource()->Activate(); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_datagram_queue.h b/chromium/net/third_party/quiche/src/quic/core/quic_datagram_queue.h index 286aeae6bf8..4d3aa2f17f3 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_datagram_queue.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_datagram_queue.h @@ -8,10 +8,10 @@ #include <memory> #include "absl/types/optional.h" -#include "quic/core/quic_circular_deque.h" #include "quic/core/quic_time.h" #include "quic/core/quic_types.h" #include "quic/platform/api/quic_mem_slice.h" +#include "common/quiche_circular_deque.h" namespace quic { @@ -80,7 +80,7 @@ class QUIC_EXPORT_PRIVATE QuicDatagramQueue { const QuicClock* clock_; QuicTime::Delta max_time_in_queue_ = QuicTime::Delta::Zero(); - QuicCircularDeque<Datagram> queue_; + quiche::QuicheCircularDeque<Datagram> queue_; std::unique_ptr<Observer> observer_; }; 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 0ed002a6850..e1a999c706a 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 @@ -26,7 +26,7 @@ #include "quic/platform/api/quic_flags.h" #include "quic/platform/api/quic_logging.h" #include "quic/platform/api/quic_stack_trace.h" -#include "common/platform/api/quiche_text_utils.h" +#include "common/quiche_text_utils.h" namespace quic { @@ -331,9 +331,6 @@ QuicDispatcher::QuicDispatcher( expected_server_connection_id_length_( expected_server_connection_id_length), should_update_expected_server_connection_id_length_(false) { - if (use_reference_counted_session_map_) { - QUIC_RESTART_FLAG_COUNT(quic_use_reference_counted_sesssion_map); - } QUIC_BUG_IF(quic_bug_12724_1, GetSupportedVersions().empty()) << "Trying to create dispatcher without any supported versions"; QUIC_DLOG(INFO) << "Created QuicDispatcher with versions: " @@ -341,15 +338,10 @@ QuicDispatcher::QuicDispatcher( } QuicDispatcher::~QuicDispatcher() { - if (use_reference_counted_session_map_) { - reference_counted_session_map_.clear(); - closed_ref_counted_session_list_.clear(); - if (support_multiple_cid_per_connection_) { - num_sessions_in_session_map_ = 0; - } - } else { - session_map_.clear(); - closed_session_list_.clear(); + reference_counted_session_map_.clear(); + closed_ref_counted_session_list_.clear(); + if (support_multiple_cid_per_connection_) { + num_sessions_in_session_map_ = 0; } } @@ -510,60 +502,45 @@ bool QuicDispatcher::MaybeDispatchPacket( return true; } + if (GetQuicReloadableFlag(quic_discard_packets_with_invalid_cid)) { + QUIC_RELOADABLE_FLAG_COUNT(quic_discard_packets_with_invalid_cid); + if (packet_info.version_flag && packet_info.version.IsKnown() && + !QuicUtils::IsConnectionIdLengthValidForVersion( + server_connection_id.length(), + packet_info.version.transport_version)) { + QUIC_DLOG(INFO) << "Packet with destination connection ID " + << server_connection_id << " is invalid with version " + << packet_info.version; + // Drop the packet silently. + QUIC_CODE_COUNT(quic_dropped_invalid_initial_connection_id); + return true; + } + } + // Packets with connection IDs for active connections are processed // immediately. - if (use_reference_counted_session_map_) { - auto it = reference_counted_session_map_.find(server_connection_id); - if (it != reference_counted_session_map_.end()) { - QUICHE_DCHECK( - !buffered_packets_.HasBufferedPackets(server_connection_id)); - if (packet_info.version_flag && - packet_info.version != it->second->version() && - packet_info.version == LegacyVersionForEncapsulation()) { - // This packet is using the Legacy Version Encapsulation version but the - // corresponding session isn't, attempt extraction of inner packet. - ChloAlpnSniExtractor alpn_extractor; - if (ChloExtractor::Extract(packet_info.packet, packet_info.version, - config_->create_session_tag_indicators(), - &alpn_extractor, - server_connection_id.length())) { - if (MaybeHandleLegacyVersionEncapsulation(this, &alpn_extractor, - packet_info)) { - return true; - } + auto it = reference_counted_session_map_.find(server_connection_id); + if (it != reference_counted_session_map_.end()) { + QUICHE_DCHECK(!buffered_packets_.HasBufferedPackets(server_connection_id)); + if (packet_info.version_flag && + packet_info.version != it->second->version() && + packet_info.version == LegacyVersionForEncapsulation()) { + // This packet is using the Legacy Version Encapsulation version but the + // corresponding session isn't, attempt extraction of inner packet. + ChloAlpnSniExtractor alpn_extractor; + if (ChloExtractor::Extract(packet_info.packet, packet_info.version, + config_->create_session_tag_indicators(), + &alpn_extractor, + server_connection_id.length())) { + if (MaybeHandleLegacyVersionEncapsulation(this, &alpn_extractor, + packet_info)) { + return true; } } - it->second->ProcessUdpPacket(packet_info.self_address, - packet_info.peer_address, - packet_info.packet); - return true; - } - } else { - auto it = session_map_.find(server_connection_id); - if (it != session_map_.end()) { - QUICHE_DCHECK( - !buffered_packets_.HasBufferedPackets(server_connection_id)); - if (packet_info.version_flag && - packet_info.version != it->second->version() && - packet_info.version == LegacyVersionForEncapsulation()) { - // This packet is using the Legacy Version Encapsulation version but the - // corresponding session isn't, attempt extraction of inner packet. - ChloAlpnSniExtractor alpn_extractor; - if (ChloExtractor::Extract(packet_info.packet, packet_info.version, - config_->create_session_tag_indicators(), - &alpn_extractor, - server_connection_id.length())) { - if (MaybeHandleLegacyVersionEncapsulation(this, &alpn_extractor, - packet_info)) { - return true; - } - } - } - it->second->ProcessUdpPacket(packet_info.self_address, - packet_info.peer_address, - packet_info.packet); - return true; } + it->second->ProcessUdpPacket(packet_info.self_address, + packet_info.peer_address, packet_info.packet); + return true; } if (packet_info.version.IsKnown()) { // We did not find the connection ID, check if we've replaced it. @@ -575,28 +552,15 @@ bool QuicDispatcher::MaybeDispatchPacket( QuicConnectionId replaced_connection_id = MaybeReplaceServerConnectionId( server_connection_id, packet_info.version); if (replaced_connection_id != server_connection_id) { - if (use_reference_counted_session_map_) { - // Search for the replacement. - auto it2 = reference_counted_session_map_.find(replaced_connection_id); - if (it2 != reference_counted_session_map_.end()) { - QUICHE_DCHECK( - !buffered_packets_.HasBufferedPackets(replaced_connection_id)); - it2->second->ProcessUdpPacket(packet_info.self_address, - packet_info.peer_address, - packet_info.packet); - return true; - } - } else { - // Search for the replacement. - auto it2 = session_map_.find(replaced_connection_id); - if (it2 != session_map_.end()) { - QUICHE_DCHECK( - !buffered_packets_.HasBufferedPackets(replaced_connection_id)); - it2->second->ProcessUdpPacket(packet_info.self_address, - packet_info.peer_address, - packet_info.packet); - return true; - } + // Search for the replacement. + auto it2 = reference_counted_session_map_.find(replaced_connection_id); + if (it2 != reference_counted_session_map_.end()) { + QUICHE_DCHECK( + !buffered_packets_.HasBufferedPackets(replaced_connection_id)); + it2->second->ProcessUdpPacket(packet_info.self_address, + packet_info.peer_address, + packet_info.packet); + return true; } } } @@ -812,9 +776,9 @@ QuicDispatcher::QuicPacketFate QuicDispatcher::ValidityChecks( void QuicDispatcher::CleanUpSession(QuicConnectionId server_connection_id, QuicConnection* connection, - QuicErrorCode error, - const std::string& error_details, - ConnectionCloseSource source) { + QuicErrorCode /*error*/, + const std::string& /*error_details*/, + ConnectionCloseSource /*source*/) { write_blocked_list_.erase(connection); QuicTimeWaitListManager::TimeWaitAction action = QuicTimeWaitListManager::SEND_STATELESS_RESET; @@ -823,14 +787,8 @@ void QuicDispatcher::CleanUpSession(QuicConnectionId server_connection_id, action = QuicTimeWaitListManager::SEND_CONNECTION_CLOSE_PACKETS; } else { if (!connection->IsHandshakeComplete()) { - const bool fix_dispatcher_sent_error_code = - GetQuicReloadableFlag(quic_fix_dispatcher_sent_error_code) && - source == ConnectionCloseSource::FROM_SELF; // TODO(fayang): Do not serialize connection close packet if the // connection is closed by the client. - if (fix_dispatcher_sent_error_code) { - QUIC_RELOADABLE_FLAG_COUNT(quic_fix_dispatcher_sent_error_code); - } if (!connection->version().HasIetfInvariantHeader()) { QUIC_CODE_COUNT(gquic_add_to_time_wait_list_with_handshake_failed); } else { @@ -845,10 +803,8 @@ void QuicDispatcher::CleanUpSession(QuicConnectionId server_connection_id, server_connection_id, connection->version(), helper_.get(), time_wait_list_manager_.get()); terminator.CloseConnection( - fix_dispatcher_sent_error_code ? error : QUIC_HANDSHAKE_FAILED, - fix_dispatcher_sent_error_code - ? error_details - : "Connection is closed by server before handshake confirmed", + QUIC_HANDSHAKE_FAILED, + "Connection is closed by server before handshake confirmed", connection->version().HasIetfInvariantHeader(), connection->GetActiveServerConnectionIds()); } else { @@ -862,11 +818,8 @@ void QuicDispatcher::CleanUpSession(QuicConnectionId server_connection_id, : GOOGLE_QUIC_PACKET, /*version_flag=*/true, connection->version().HasLengthPrefixedConnectionIds(), - connection->version(), - fix_dispatcher_sent_error_code ? error : QUIC_HANDSHAKE_FAILED, - fix_dispatcher_sent_error_code - ? error_details - : "Connection is closed by server before handshake confirmed", + 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 // StatelesslyTerminateConnection(). @@ -898,18 +851,12 @@ void QuicDispatcher::StopAcceptingNewConnections() { void QuicDispatcher::PerformActionOnActiveSessions( std::function<void(QuicSession*)> operation) const { - if (use_reference_counted_session_map_) { - absl::flat_hash_set<QuicSession*> visited_session; - visited_session.reserve(reference_counted_session_map_.size()); - for (auto const& kv : reference_counted_session_map_) { - QuicSession* session = kv.second.get(); - if (visited_session.insert(session).second) { - operation(session); - } - } - } else { - for (auto const& kv : session_map_) { - operation(kv.second.get()); + absl::flat_hash_set<QuicSession*> visited_session; + visited_session.reserve(reference_counted_session_map_.size()); + for (auto const& kv : reference_counted_session_map_) { + QuicSession* session = kv.second.get(); + if (visited_session.insert(session).second) { + operation(session); } } } @@ -917,7 +864,6 @@ void QuicDispatcher::PerformActionOnActiveSessions( // Get a snapshot of all sessions. std::vector<std::shared_ptr<QuicSession>> QuicDispatcher::GetSessionsSnapshot() const { - QUICHE_DCHECK(use_reference_counted_session_map_); std::vector<std::shared_ptr<QuicSession>> snapshot; snapshot.reserve(reference_counted_session_map_.size()); absl::flat_hash_set<QuicSession*> visited_session; @@ -937,29 +883,16 @@ std::unique_ptr<QuicPerPacketContext> QuicDispatcher::GetPerPacketContext() } void QuicDispatcher::DeleteSessions() { - if (use_reference_counted_session_map_) { - if (!write_blocked_list_.empty()) { - for (const auto& session : closed_ref_counted_session_list_) { - if (write_blocked_list_.erase(session->connection()) != 0) { - QUIC_BUG(quic_bug_12724_2) - << "QuicConnection was in WriteBlockedList before destruction " - << session->connection()->connection_id(); - } + if (!write_blocked_list_.empty()) { + for (const auto& session : closed_ref_counted_session_list_) { + if (write_blocked_list_.erase(session->connection()) != 0) { + QUIC_BUG(quic_bug_12724_2) + << "QuicConnection was in WriteBlockedList before destruction " + << session->connection()->connection_id(); } } - closed_ref_counted_session_list_.clear(); - } else { - if (!write_blocked_list_.empty()) { - for (const std::unique_ptr<QuicSession>& session : closed_session_list_) { - if (write_blocked_list_.erase(session->connection()) != 0) { - QUIC_BUG(quic_bug_12724_3) - << "QuicConnection was in WriteBlockedList before destruction " - << session->connection()->connection_id(); - } - } - } - closed_session_list_.clear(); } + closed_ref_counted_session_list_.clear(); } void QuicDispatcher::OnCanWrite() { @@ -995,28 +928,15 @@ bool QuicDispatcher::HasPendingWrites() const { } void QuicDispatcher::Shutdown() { - if (use_reference_counted_session_map_) { - while (!reference_counted_session_map_.empty()) { - QuicSession* session = - reference_counted_session_map_.begin()->second.get(); - session->connection()->CloseConnection( - QUIC_PEER_GOING_AWAY, "Server shutdown imminent", - ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); - // Validate that the session removes itself from the session map on close. - QUICHE_DCHECK(reference_counted_session_map_.empty() || - reference_counted_session_map_.begin()->second.get() != - session); - } - } else { - while (!session_map_.empty()) { - QuicSession* session = session_map_.begin()->second.get(); - session->connection()->CloseConnection( - QUIC_PEER_GOING_AWAY, "Server shutdown imminent", - ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); - // Validate that the session removes itself from the session map on close. - QUICHE_DCHECK(session_map_.empty() || - session_map_.begin()->second.get() != session); - } + while (!reference_counted_session_map_.empty()) { + QuicSession* session = reference_counted_session_map_.begin()->second.get(); + session->connection()->CloseConnection( + QUIC_PEER_GOING_AWAY, "Server shutdown imminent", + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + // Validate that the session removes itself from the session map on close. + QUICHE_DCHECK(reference_counted_session_map_.empty() || + reference_counted_session_map_.begin()->second.get() != + session); } DeleteSessions(); } @@ -1025,72 +945,41 @@ void QuicDispatcher::OnConnectionClosed(QuicConnectionId server_connection_id, QuicErrorCode error, const std::string& error_details, ConnectionCloseSource source) { - if (use_reference_counted_session_map_) { - auto it = reference_counted_session_map_.find(server_connection_id); - if (it == reference_counted_session_map_.end()) { - QUIC_BUG(quic_bug_10287_3) - << "ConnectionId " << server_connection_id - << " does not exist in the session map. Error: " - << QuicErrorCodeToString(error); - QUIC_BUG(quic_bug_10287_4) << QuicStackTrace(); - return; - } + auto it = reference_counted_session_map_.find(server_connection_id); + if (it == reference_counted_session_map_.end()) { + QUIC_BUG(quic_bug_10287_3) << "ConnectionId " << server_connection_id + << " does not exist in the session map. Error: " + << QuicErrorCodeToString(error); + QUIC_BUG(quic_bug_10287_4) << QuicStackTrace(); + return; + } - QUIC_DLOG_IF(INFO, error != QUIC_NO_ERROR) - << "Closing connection (" << server_connection_id - << ") due to error: " << QuicErrorCodeToString(error) - << ", with details: " << error_details; - - QuicConnection* connection = it->second->connection(); - if (ShouldDestroySessionAsynchronously()) { - // Set up alarm to fire immediately to bring destruction of this session - // out of current call stack. - if (closed_ref_counted_session_list_.empty()) { - delete_sessions_alarm_->Update(helper()->GetClock()->ApproximateNow(), - QuicTime::Delta::Zero()); - } - closed_ref_counted_session_list_.push_back(std::move(it->second)); + QUIC_DLOG_IF(INFO, error != QUIC_NO_ERROR) + << "Closing connection (" << server_connection_id + << ") due to error: " << QuicErrorCodeToString(error) + << ", with details: " << error_details; + + QuicConnection* connection = it->second->connection(); + if (ShouldDestroySessionAsynchronously()) { + // Set up alarm to fire immediately to bring destruction of this session + // out of current call stack. + if (closed_ref_counted_session_list_.empty()) { + delete_sessions_alarm_->Update(helper()->GetClock()->ApproximateNow(), + QuicTime::Delta::Zero()); } - CleanUpSession(it->first, connection, error, error_details, source); - if (support_multiple_cid_per_connection_) { - QUIC_RESTART_FLAG_COUNT_N( - quic_dispatcher_support_multiple_cid_per_connection_v2, 1, 2); - for (const QuicConnectionId& cid : - connection->GetActiveServerConnectionIds()) { - reference_counted_session_map_.erase(cid); - } - --num_sessions_in_session_map_; - } else { - reference_counted_session_map_.erase(it); + closed_ref_counted_session_list_.push_back(std::move(it->second)); + } + CleanUpSession(it->first, connection, error, error_details, source); + if (support_multiple_cid_per_connection_) { + QUIC_RESTART_FLAG_COUNT_N( + quic_dispatcher_support_multiple_cid_per_connection_v2, 1, 2); + for (const QuicConnectionId& cid : + connection->GetActiveServerConnectionIds()) { + reference_counted_session_map_.erase(cid); } + --num_sessions_in_session_map_; } else { - auto it = session_map_.find(server_connection_id); - if (it == session_map_.end()) { - QUIC_BUG(quic_bug_10287_5) - << "ConnectionId " << server_connection_id - << " does not exist in the session map. Error: " - << QuicErrorCodeToString(error); - QUIC_BUG(quic_bug_10287_6) << QuicStackTrace(); - return; - } - - QUIC_DLOG_IF(INFO, error != QUIC_NO_ERROR) - << "Closing connection (" << server_connection_id - << ") due to error: " << QuicErrorCodeToString(error) - << ", with details: " << error_details; - - QuicConnection* connection = it->second->connection(); - if (ShouldDestroySessionAsynchronously()) { - // Set up alarm to fire immediately to bring destruction of this session - // out of current call stack. - if (closed_session_list_.empty()) { - delete_sessions_alarm_->Update(helper()->GetClock()->ApproximateNow(), - QuicTime::Delta::Zero()); - } - closed_session_list_.push_back(std::move(it->second)); - } - CleanUpSession(it->first, connection, error, error_details, source); - session_map_.erase(it); + reference_counted_session_map_.erase(it); } } @@ -1126,6 +1015,7 @@ void QuicDispatcher::OnNewConnectionIdSent( << server_connection_id << " new_connection_id: " << new_connection_id; return; } + QUIC_RELOADABLE_FLAG_COUNT_N(quic_connection_migration_use_new_cid_v2, 5, 5); auto insertion_result = reference_counted_session_map_.insert( std::make_pair(new_connection_id, it->second)); QUICHE_DCHECK(insertion_result.second); @@ -1250,28 +1140,18 @@ void QuicDispatcher::ProcessBufferedChlos(size_t max_connections_to_create) { } QUIC_DLOG(INFO) << "Created new session for " << server_connection_id; - if (use_reference_counted_session_map_) { - auto insertion_result = reference_counted_session_map_.insert( - std::make_pair(server_connection_id, - std::shared_ptr<QuicSession>(std::move(session)))); - if (!insertion_result.second) { - QUIC_BUG(quic_bug_12724_5) - << "Tried to add a session to session_map with existing connection " - "id: " - << server_connection_id; - } else if (support_multiple_cid_per_connection_) { - ++num_sessions_in_session_map_; - } - DeliverPacketsToSession(packets, insertion_result.first->second.get()); - } else { - auto insertion_result = session_map_.insert( - std::make_pair(server_connection_id, std::move(session))); - QUIC_BUG_IF(quic_bug_12724_6, !insertion_result.second) + auto insertion_result = reference_counted_session_map_.insert( + std::make_pair(server_connection_id, + std::shared_ptr<QuicSession>(std::move(session)))); + if (!insertion_result.second) { + QUIC_BUG(quic_bug_12724_5) << "Tried to add a session to session_map with existing connection " "id: " << server_connection_id; - DeliverPacketsToSession(packets, insertion_result.first->second.get()); + } else if (support_multiple_cid_per_connection_) { + ++num_sessions_in_session_map_; } + DeliverPacketsToSession(packets, insertion_result.first->second.get()); } } @@ -1370,28 +1250,18 @@ void QuicDispatcher::ProcessChlo(const std::vector<std::string>& alpns, << packet_info->destination_connection_id; QuicSession* session_ptr; - if (use_reference_counted_session_map_) { - auto insertion_result = - reference_counted_session_map_.insert(std::make_pair( - packet_info->destination_connection_id, - std::shared_ptr<QuicSession>(std::move(session.release())))); - if (!insertion_result.second) { - QUIC_BUG(quic_bug_10287_9) - << "Tried to add a session to session_map with existing " - "connection id: " - << packet_info->destination_connection_id; - } else if (support_multiple_cid_per_connection_) { - ++num_sessions_in_session_map_; - } - session_ptr = insertion_result.first->second.get(); - } else { - auto insertion_result = session_map_.insert(std::make_pair( - packet_info->destination_connection_id, std::move(session))); - QUIC_BUG_IF(quic_bug_12724_8, !insertion_result.second) - << "Tried to add a session to session_map with existing connection id: " + auto insertion_result = reference_counted_session_map_.insert(std::make_pair( + packet_info->destination_connection_id, + std::shared_ptr<QuicSession>(std::move(session.release())))); + if (!insertion_result.second) { + QUIC_BUG(quic_bug_10287_9) + << "Tried to add a session to session_map with existing " + "connection id: " << packet_info->destination_connection_id; - session_ptr = insertion_result.first->second.get(); + } else if (support_multiple_cid_per_connection_) { + ++num_sessions_in_session_map_; } + session_ptr = insertion_result.first->second.get(); std::list<BufferedPacket> packets = buffered_packets_.DeliverPackets(packet_info->destination_connection_id) .buffered_packets; @@ -1449,7 +1319,7 @@ bool QuicDispatcher::IsSupportedVersion(const ParsedQuicVersion version) { void QuicDispatcher::MaybeResetPacketsWithNoVersion( const ReceivedPacketInfo& packet_info) { QUICHE_DCHECK(!packet_info.version_flag); - if (GetQuicReloadableFlag(quic_fix_stateless_reset) && + if (GetQuicRestartFlag(quic_fix_stateless_reset2) && packet_info.form != GOOGLE_QUIC_PACKET) { // Drop IETF packets smaller than the minimal stateless reset length. if (packet_info.packet.length() <= @@ -1481,9 +1351,7 @@ size_t QuicDispatcher::NumSessions() const { if (support_multiple_cid_per_connection_) { return num_sessions_in_session_map_; } - return use_reference_counted_session_map_ - ? reference_counted_session_map_.size() - : session_map_.size(); + return reference_counted_session_map_.size(); } } // namespace quic 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 81749543d4d..053f856da98 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 @@ -166,10 +166,6 @@ class QUIC_NO_EXPORT QuicDispatcher bool accept_new_connections() const { return accept_new_connections_; } - bool use_reference_counted_session_map() const { - return use_reference_counted_session_map_; - } - bool support_multiple_cid_per_connection() const { return support_multiple_cid_per_connection_; } @@ -457,10 +453,7 @@ class QUIC_NO_EXPORT QuicDispatcher // destination connection ID length of all IETF long headers. bool should_update_expected_server_connection_id_length_; - const bool use_reference_counted_session_map_ = - GetQuicRestartFlag(quic_use_reference_counted_sesssion_map); const bool support_multiple_cid_per_connection_ = - use_reference_counted_session_map_ && GetQuicRestartFlag(quic_time_wait_list_support_multiple_cid_v2) && GetQuicRestartFlag( quic_dispatcher_support_multiple_cid_per_connection_v2); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher_test.cc index 3df8a76965d..5a7a709f91b 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 @@ -167,6 +167,7 @@ class TestDispatcher : public QuicDispatcher { std::string custom_packet_context_; + using QuicDispatcher::MaybeDispatchPacket; using QuicDispatcher::SetAllowShortInitialServerConnectionIds; using QuicDispatcher::writer; @@ -1101,6 +1102,31 @@ TEST_P(QuicDispatcherTestAllVersions, ProcessFirstFlight(client_address, EmptyQuicConnectionId()); } +TEST_P(QuicDispatcherTestAllVersions, + DropPacketWithKnownVersionAndInvalidInitialConnectionId) { + SetQuicReloadableFlag(quic_discard_packets_with_invalid_cid, true); + CreateTimeWaitListManager(); + + QuicSocketAddress server_address; + QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); + + // dispatcher_ should drop this packet with invalid connection ID. + EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _, _, _)).Times(0); + EXPECT_CALL(*time_wait_list_manager_, ProcessPacket(_, _, _, _, _, _)) + .Times(0); + EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _, _)) + .Times(0); + absl::string_view cid_str = "123456789abcdefg123456789abcdefg"; + QuicConnectionId invalid_connection_id(cid_str.data(), cid_str.length()); + QuicReceivedPacket packet("packet", 6, QuicTime::Zero()); + ReceivedPacketInfo packet_info(server_address, client_address, packet); + packet_info.version_flag = true; + packet_info.version = version_; + packet_info.destination_connection_id = invalid_connection_id; + + ASSERT_TRUE(dispatcher_->MaybeDispatchPacket(packet_info)); +} + void QuicDispatcherTestBase:: TestVersionNegotiationForUnknownVersionInvalidShortInitialConnectionId( const QuicConnectionId& server_connection_id, @@ -1976,7 +2002,6 @@ class QuicDispatcherSupportMultipleConnectionIdPerConnectionTest public: QuicDispatcherSupportMultipleConnectionIdPerConnectionTest() : QuicDispatcherTestBase(crypto_test_utils::ProofSourceForTesting()) { - SetQuicRestartFlag(quic_use_reference_counted_sesssion_map, true); SetQuicRestartFlag(quic_time_wait_list_support_multiple_cid_v2, true); SetQuicRestartFlag(quic_dispatcher_support_multiple_cid_per_connection_v2, true); 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 32816b869cf..9fa422f578c 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 @@ -459,8 +459,12 @@ enum QuicErrorCode { // Received multiple close offset. QUIC_STREAM_MULTIPLE_OFFSET = 130, - // Internal error codes for HTTP/3 errors. + // HTTP/3 errors. + + // Frame payload larger than what HttpDecoder is willing to buffer. QUIC_HTTP_FRAME_TOO_LARGE = 131, + // Malformed HTTP/3 frame, or PUSH_PROMISE or CANCEL_PUSH received (which is + // an error because MAX_PUSH_ID is never sent). QUIC_HTTP_FRAME_ERROR = 132, // A frame that is never allowed on a request stream is received. QUIC_HTTP_FRAME_UNEXPECTED_ON_SPDY_STREAM = 133, diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_flags_list.h b/chromium/net/third_party/quiche/src/quic/core/quic_flags_list.h index 910db544eff..df0df50f3fc 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_flags_list.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_flags_list.h @@ -4,77 +4,135 @@ // This file is autogenerated by the QUICHE Copybara export script. -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_abort_qpack_on_stream_reset, true) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_accept_empty_stream_frame_with_no_fin, true) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_ack_delay_alarm_granularity, true) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_add_stream_info_to_idle_close_detail, true) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_allocate_stream_sequencer_buffer_blocks_on_demand, false) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_allow_client_enabled_bbr_v2, false) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_alps_include_scheme_in_origin, true) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_and_tls_allow_sni_without_dots, false) +#ifdef QUIC_FLAG + +QUIC_FLAG(FLAGS_quic_restart_flag_dont_fetch_quic_private_keys_from_leto, false) + +QUIC_FLAG(FLAGS_quic_restart_flag_quic_offload_pacing_to_usps2, false) +// A testonly reloadable flag that will always default to false. +QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_testonly_default_false, false) +// A testonly reloadable flag that will always default to true. +QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_testonly_default_true, true) +// A testonly restart flag that will always default to false. +QUIC_FLAG(FLAGS_quic_restart_flag_quic_testonly_default_false, false) +// A testonly restart flag that will always default to true. +QUIC_FLAG(FLAGS_quic_restart_flag_quic_testonly_default_true, true) +// Fix QUIC BBRv2\'s bandwidth_lo modes to better approximate packet conservation. +QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_bbr2_fix_bw_lo_mode2, false) +// If true, GFE will consider SNI values which do not contain dots (instead of throwing them away - see b/176998377). +QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_and_tls_allow_sni_without_dots, true) +// If true, QUIC BBRv2\'s PROBE_BW mode will not reduce cwnd below BDP+ack_height. QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_bbr2_avoid_too_low_probe_bw_cwnd, false) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_bbr2_fix_bw_lo_mode, false) +// If true, QUIC will default enable MTU discovery at server, with a target of 1450 bytes. +QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_enable_mtu_discovery_at_server, false) +// If true, QuicBatchWriterBase will mark the writer as blocked when the write status is WRITE_STATUS_BLOCKED_DATA_BUFFERED. +QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_batch_writer_fix_write_blocked, true) +// If true, QuicGsoBatchWriter will support release time if it is available and the process has the permission to do so. +QUIC_FLAG(FLAGS_quic_restart_flag_quic_support_release_time_for_gso, false) +// If true, TlsHandshaker::AdvanceHandshake will retry SSL_do_handshake when entered early data. +QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_tls_retry_handshake_on_early_data, true) +// If true, TlsServerHandshaker will install a packet flusher when async operation completes. +QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_add_packet_flusher_on_async_op_done, true) +// If true, TlsServerHandshaker will use handshake hints(if present) to speed up handshakes. +QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_tls_server_use_handshake_hints, true) +// If true, abort async QPACK header decompression in QuicSpdyStream::Reset() and in QuicSpdyStream::OnStreamReset(). +QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_abort_qpack_on_stream_reset, true) +// If true, ack frequency frame can be sent from server to client. QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_can_send_ack_frequency, true) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_close_connection_with_too_many_outstanding_packets, true) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_connection_support_multiple_cids_v2, false) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_conservative_bursts, false) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_conservative_cwnd_and_pacing_gains, false) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_count_bytes_on_alternative_path_seperately, true) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_crypto_postpone_cert_validate_for_server, true) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_default_enable_5rto_blackhole_detection2, true) +// If true, allow client to enable BBRv2 on server via connection option \'B2ON\'. +QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_allow_client_enabled_bbr_v2, false) +// If true, close read side but not write side in QuicSpdyStream::OnStreamReset(). +QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_fix_on_stream_reset, true) +// If true, default on PTO which unifies TLP + RTO loss recovery. QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_default_on_pto, false) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_default_to_bbr, false) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_default_to_bbr_v2, false) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_delay_initial_ack, true) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_disable_server_blackhole_detection, false) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_disable_version_draft_29, false) +// If true, default-enable 5RTO blachole detection. +QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_default_enable_5rto_blackhole_detection2, true) +// If true, determine stateless reset packet length based on the received packet length. +QUIC_FLAG(FLAGS_quic_restart_flag_quic_fix_stateless_reset2, false) +// If true, disable QUIC version Q043. QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_disable_version_q043, false) +// If true, disable QUIC version Q046. QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_disable_version_q046, false) +// If true, disable QUIC version Q050. QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_disable_version_q050, false) +// If true, disable QUIC version h3-29. +QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_disable_version_draft_29, false) +// If true, disable QUIC version h3-T051. QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_disable_version_t051, false) +// If true, disable blackhole detection on server side. +QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_disable_server_blackhole_detection, false) +// If true, discard INITIAL packet if the key has been dropped. QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_discard_initial_packet_with_key_dropped, true) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_do_not_synthesize_source_cid_for_short_header, true) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_donot_reset_ideal_next_packet_send_time, false) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_donot_write_mid_packet_processing, false) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_enable_alps_client, true) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_enable_alps_server, true) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_enable_mtu_discovery_at_server, false) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_enable_server_on_wire_ping, true) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_enable_token_based_address_validation, true) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_enable_version_rfcv1, false) +// If true, do not bundle 2nd ACK with connection close if there is an ACK queued. +QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_single_ack_in_packet2, false) +// If true, do not count bytes sent/received on the alternative path into the bytes sent/received on the default path. +QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_count_bytes_on_alternative_path_seperately, true) +// If true, do not send control frames before encryption is established. QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_encrypted_control_frames, false) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_encrypted_goaway, true) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_fix_dispatcher_sent_error_code, false) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_fix_key_update_on_first_packet, true) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_fix_on_stream_reset, true) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_fix_stateless_reset, true) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_fix_willing_and_able_to_write2, true) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_h3_datagram, false) +// If true, do not send stream data when PTO fires. +QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_donot_pto_half_rtt_data, true) +// If true, do not write stream data and control frames in the middle of packet processing. +QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_donot_write_mid_packet_processing, true) +// If true, drop unsent PATH_RESPONSEs and rely on peer\'s retry. +QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_drop_unsent_path_response, true) +// If true, enable QUIC version h3 (RFCv1). +QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_enable_version_rfcv1, false) +// If true, enable server retransmittable on wire PING. +QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_enable_server_on_wire_ping, true) +// If true, include stream information in idle timeout connection close detail. +QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_add_stream_info_to_idle_close_detail, true) +// If true, increase the size of stream sequencer buffer block container on demand. +QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_allocate_stream_sequencer_buffer_blocks_on_demand, false) +// If true, pass the received PATH_RESPONSE payload to path validator to move forward the path validation. QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_pass_path_response_to_validator, false) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_preempt_stream_data_with_handshake_packet, true) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_reject_unexpected_ietf_frame_types, true) +// If true, quic connection sends/recieives NewConnectionId & RetireConnectionId frames. +QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_connection_support_multiple_cids_v4, true) +// If true, quic dispatcher discards packets with invalid server connection ID. +QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_discard_packets_with_invalid_cid, false) +// If true, quic dispatcher supports one connection to use multiple connection IDs. +QUIC_FLAG(FLAGS_quic_restart_flag_quic_dispatcher_support_multiple_cid_per_connection_v2, true) +// If true, require handshake confirmation for QUIC connections, functionally disabling 0-rtt handshakes. QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_require_handshake_confirmation, false) +// If true, send PATH_RESPONSE upon receiving PATH_CHALLENGE regardless of perspective. --gfe2_reloadable_flag_quic_start_peer_migration_earlier has to be true before turn on this flag. QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_send_path_response2, true) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_send_timestamps, false) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_send_tls_crypto_error_code, true) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_server_reverse_validate_new_path3, false) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_single_ack_in_packet2, false) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_start_peer_migration_earlier, true) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_testonly_default_false, false) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_testonly_default_true, true) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_tls_use_normalized_sni_for_cert_selectioon, true) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_tls_use_per_handshaker_proof_source, true) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_tls_retry_handshake_on_early_data, true) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_unified_iw_options, false) -QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_unify_stop_sending, true) +// If true, set burst token to 2 in cwnd bootstrapping experiment. +QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_conservative_bursts, false) +// If true, signal error in HttpDecoder upon receiving a PUSH_PROMISE or CANCEL_PUSH frame. +QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_error_on_http3_push, true) +// If true, stop resetting ideal_next_packet_send_time_ in pacing sender. +QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_donot_reset_ideal_next_packet_send_time, false) +// If true, time_wait_list can support multiple connection IDs. +QUIC_FLAG(FLAGS_quic_restart_flag_quic_time_wait_list_support_multiple_cid_v2, true) +// If true, treat old (pre-draft02) PRIORITY_UPDATE frame as unknown frame. +QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_ignore_old_priority_update_frame, true) +// If true, upon receiving path challenge, send path response and reverse path challenge in the same function. +QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_group_path_response_and_challenge_sending_closer, false) +// If true, use BBRv2 as the default congestion controller. Takes precedence over --quic_default_to_bbr. +QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_default_to_bbr_v2, false) +// If true, use ScopedEncryptionLevelContext when sending data. QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_use_encryption_level_context, true) +// If true, use WriteOrBufferDataAtLevel to send crypto data. Existing WriteOrBufferData is used to send application data. QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_use_write_or_buffer_data_at_level, false) -QUIC_FLAG(FLAGS_quic_restart_flag_dont_fetch_quic_private_keys_from_leto, false) -QUIC_FLAG(FLAGS_quic_restart_flag_quic_dispatcher_support_multiple_cid_per_connection_v2, true) -QUIC_FLAG(FLAGS_quic_restart_flag_quic_offload_pacing_to_usps2, false) -QUIC_FLAG(FLAGS_quic_restart_flag_quic_session_tickets_always_enabled, true) -QUIC_FLAG(FLAGS_quic_restart_flag_quic_support_release_time_for_gso, false) -QUIC_FLAG(FLAGS_quic_restart_flag_quic_testonly_default_false, false) -QUIC_FLAG(FLAGS_quic_restart_flag_quic_testonly_default_true, true) -QUIC_FLAG(FLAGS_quic_restart_flag_quic_time_wait_list_support_multiple_cid_v2, true) -QUIC_FLAG(FLAGS_quic_restart_flag_quic_use_reference_counted_sesssion_map, true) +// If true, use new connection ID in connection migration. +QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_connection_migration_use_new_cid_v2, false) +// If true, use the connection ID and stateless reset token on default PathState. +QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_use_connection_id_on_default_path_v2, true) +// If true, uses conservative cwnd gain and pacing gain when cwnd gets bootstrapped. +QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_conservative_cwnd_and_pacing_gains, false) +// If true, validate that peer owns the new address once the server detects peer migration or is probed from that address, and also apply anti-amplification limit while sending to that address. +QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_server_reverse_validate_new_path3, false) +// If ture, replace the incoming_connection_ids check with original_destination_connection_id check. +QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_deprecate_incoming_connection_ids, true) +// When the STMP connection option is sent by the client, timestamps in the QUIC ACK frame are sent and processed. +QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_send_timestamps, false) +// When true, QuicSpdySession supports draft-ietf-masque-h3-datagram. +QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_h3_datagram, false) +// When true, defaults to BBR congestion control instead of Cubic. +QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_default_to_bbr, false) +// When true, makes the QUIC BBRv2 bw_lo modes more similar to standard BBRv2. +QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_bbr2_fix_bw_lo_mode, true) +// When true, set the initial congestion control window from connection options in QuicSentPacketManager rather than TcpCubicSenderBytes. +QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_unified_iw_options, false) + +#endif + diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_framer.cc b/chromium/net/third_party/quiche/src/quic/core/quic_framer.cc index c5de97be541..e186ce33ecb 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 @@ -49,7 +49,7 @@ #include "quic/platform/api/quic_logging.h" #include "quic/platform/api/quic_map_util.h" #include "quic/platform/api/quic_stack_trace.h" -#include "common/platform/api/quiche_text_utils.h" +#include "common/quiche_text_utils.h" namespace quic { @@ -435,10 +435,6 @@ QuicFramer::QuicFramer(const ParsedQuicVersionVector& supported_versions, version_ = supported_versions_[0]; QUICHE_DCHECK(version_.IsKnown()) << ParsedQuicVersionVectorToString(supported_versions_); - if (do_not_synthesize_source_cid_for_short_header_) { - QUIC_RELOADABLE_FLAG_COUNT_N( - quic_do_not_synthesize_source_cid_for_short_header, 1, 3); - } } QuicFramer::~QuicFramer() {} @@ -1309,9 +1305,9 @@ std::unique_ptr<QuicEncryptedPacket> QuicFramer::BuildIetfStatelessResetPacket( size_t received_packet_length, StatelessResetToken stateless_reset_token) { QUIC_DVLOG(1) << "Building IETF stateless reset packet."; - if (GetQuicReloadableFlag(quic_fix_stateless_reset)) { + if (GetQuicRestartFlag(quic_fix_stateless_reset2)) { if (received_packet_length <= GetMinStatelessResetPacketLength()) { - QUIC_BUG(362045737_1) + QUICHE_DLOG(ERROR) << "Tried to build stateless reset packet with received packet " "length " << received_packet_length; @@ -1344,7 +1340,7 @@ std::unique_ptr<QuicEncryptedPacket> QuicFramer::BuildIetfStatelessResetPacket( QUIC_BUG(362045737_3) << "Failed to write stateless reset token"; return nullptr; } - QUIC_RELOADABLE_FLAG_COUNT(quic_fix_stateless_reset); + QUIC_RESTART_FLAG_COUNT(quic_fix_stateless_reset2); return std::make_unique<QuicEncryptedPacket>(buffer.release(), len, /*owns_buffer=*/true); } @@ -2774,7 +2770,6 @@ bool QuicFramer::ProcessAndValidateIetfConnectionIdLength( bool QuicFramer::ValidateReceivedConnectionIds(const QuicPacketHeader& header) { bool skip_server_connection_id_validation = - do_not_synthesize_source_cid_for_short_header_ && perspective_ == Perspective::IS_CLIENT && header.form == IETF_QUIC_SHORT_HEADER_PACKET; if (!skip_server_connection_id_validation && @@ -2786,13 +2781,8 @@ bool QuicFramer::ValidateReceivedConnectionIds(const QuicPacketHeader& header) { } bool skip_client_connection_id_validation = - do_not_synthesize_source_cid_for_short_header_ && perspective_ == Perspective::IS_SERVER && header.form == IETF_QUIC_SHORT_HEADER_PACKET; - if (skip_client_connection_id_validation) { - QUIC_RELOADABLE_FLAG_COUNT_N( - quic_do_not_synthesize_source_cid_for_short_header, 2, 3); - } if (!skip_client_connection_id_validation && version_.SupportsClientConnectionIds() && !QuicUtils::IsConnectionIdValidForVersion( @@ -2829,15 +2819,6 @@ bool QuicFramer::ProcessIetfPacketHeader(QuicDataReader* reader, header->destination_connection_id_included = CONNECTION_ID_PRESENT; header->source_connection_id_included = header->version_flag ? CONNECTION_ID_PRESENT : CONNECTION_ID_ABSENT; - if (!do_not_synthesize_source_cid_for_short_header_ && - header->source_connection_id_included == CONNECTION_ID_ABSENT) { - QUICHE_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; @@ -2925,13 +2906,6 @@ bool QuicFramer::ProcessIetfPacketHeader(QuicDataReader* reader, set_detailed_error("Client connection ID not supported in this version."); return false; } - if (!do_not_synthesize_source_cid_for_short_header_) { - 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 ValidateReceivedConnectionIds(*header); @@ -3232,20 +3206,14 @@ bool QuicFramer::ProcessIetfFrameData(QuicDataReader* reader, set_detailed_error("Unable to read frame type."); return RaiseError(QUIC_INVALID_FRAME_DATA); } - if (reject_unexpected_ietf_frame_types_) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_reject_unexpected_ietf_frame_types, 1, - 2); - if (!IsIetfFrameTypeExpectedForEncryptionLevel(frame_type, - decrypted_level)) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_reject_unexpected_ietf_frame_types, 2, - 2); - set_detailed_error(absl::StrCat( - "IETF frame type ", - QuicIetfFrameTypeString(static_cast<QuicIetfFrameType>(frame_type)), - " is unexpected at encryption level ", - EncryptionLevelToString(decrypted_level))); - return RaiseError(IETF_QUIC_PROTOCOL_VIOLATION); - } + if (!IsIetfFrameTypeExpectedForEncryptionLevel(frame_type, + decrypted_level)) { + set_detailed_error(absl::StrCat( + "IETF frame type ", + QuicIetfFrameTypeString(static_cast<QuicIetfFrameType>(frame_type)), + " is unexpected at encryption level ", + EncryptionLevelToString(decrypted_level))); + return RaiseError(IETF_QUIC_PROTOCOL_VIOLATION); } current_received_frame_type_ = frame_type; @@ -4872,10 +4840,8 @@ bool QuicFramer::DecryptPayload(size_t udp_packet_length, if ((current_key_phase_first_received_packet_number_.IsInitialized() && header.packet_number > current_key_phase_first_received_packet_number_) || - (GetQuicReloadableFlag(quic_fix_key_update_on_first_packet) && - !current_key_phase_first_received_packet_number_.IsInitialized() && + (!current_key_phase_first_received_packet_number_.IsInitialized() && !key_update_performed_)) { - QUIC_RELOADABLE_FLAG_COUNT(quic_fix_key_update_on_first_packet); if (!next_decrypter_) { next_decrypter_ = visitor_->AdvanceKeysAndCreateCurrentOneRttDecrypter(); 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 e27c7f0727e..2920db351c4 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 @@ -634,6 +634,8 @@ class QUIC_EXPORT_PRIVATE QuicFramer { Perspective perspective() const { return perspective_; } + QuicStreamFrameDataProducer* data_producer() const { return data_producer_; } + void set_data_producer(QuicStreamFrameDataProducer* data_producer) { data_producer_ = data_producer; } @@ -714,10 +716,6 @@ class QUIC_EXPORT_PRIVATE QuicFramer { drop_incoming_retry_packets_ = drop_incoming_retry_packets; } - bool do_not_synthesize_source_cid_for_short_header() const { - return do_not_synthesize_source_cid_for_short_header_; - } - private: friend class test::QuicFramerPeer; @@ -1174,14 +1172,6 @@ class QUIC_EXPORT_PRIVATE QuicFramer { // Indicates whether received RETRY packets should be dropped. bool drop_incoming_retry_packets_ = false; - bool reject_unexpected_ietf_frame_types_ = - GetQuicReloadableFlag(quic_reject_unexpected_ietf_frame_types); - - // Indicates whether source connection ID should be synthesized when read - // short header packet. - const bool do_not_synthesize_source_cid_for_short_header_ = - GetQuicReloadableFlag(quic_do_not_synthesize_source_cid_for_short_header); - // The length in bytes of the last packet number written to an IETF-framed // packet. size_t last_written_packet_number_length_; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_framer_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_framer_test.cc index 048a4b72ffb..63a1ad5ed4f 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 @@ -34,7 +34,6 @@ #include "quic/test_tools/quic_framer_peer.h" #include "quic/test_tools/quic_test_utils.h" #include "quic/test_tools/simple_data_producer.h" -#include "common/platform/api/quiche_text_utils.h" #include "common/test_tools/quiche_test_utils.h" using testing::_; @@ -1479,9 +1478,6 @@ TEST_P(QuicFramerTest, ClientConnectionIdFromShortHeaderToClient) { ASSERT_TRUE(visitor_.header_.get()); EXPECT_EQ(FramerTestConnectionId(), visitor_.header_->destination_connection_id); - if (!framer_.do_not_synthesize_source_cid_for_short_header()) { - EXPECT_EQ(TestConnectionId(0x33), visitor_.header_->source_connection_id); - } } // In short header packets from client to server, the client connection ID @@ -1515,9 +1511,6 @@ TEST_P(QuicFramerTest, ClientConnectionIdFromShortHeaderToServer) { ASSERT_TRUE(visitor_.header_.get()); EXPECT_EQ(FramerTestConnectionId(), visitor_.header_->destination_connection_id); - if (!framer_.do_not_synthesize_source_cid_for_short_header()) { - EXPECT_EQ(TestConnectionId(0x33), visitor_.header_->source_connection_id); - } } TEST_P(QuicFramerTest, PacketHeaderWith0ByteConnectionId) { @@ -1567,9 +1560,6 @@ TEST_P(QuicFramerTest, PacketHeaderWith0ByteConnectionId) { EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); EXPECT_THAT(framer_.error(), IsError(QUIC_MISSING_PAYLOAD)); ASSERT_TRUE(visitor_.header_.get()); - if (!framer_.do_not_synthesize_source_cid_for_short_header()) { - 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); @@ -9248,7 +9238,7 @@ TEST_P(QuicFramerTest, BuildPublicResetPacketWithEndpointId) { } TEST_P(QuicFramerTest, BuildIetfStatelessResetPacket) { - if (GetQuicReloadableFlag(quic_fix_stateless_reset)) { + if (GetQuicRestartFlag(quic_fix_stateless_reset2)) { // clang-format off unsigned char packet[] = { // 1st byte 01XX XXXX @@ -9282,13 +9272,12 @@ TEST_P(QuicFramerTest, BuildIetfStatelessResetPacket) { // Packets with length <= minimal stateless reset does not trigger stateless // reset. - EXPECT_QUIC_BUG( - std::unique_ptr<QuicEncryptedPacket> data2( - framer_.BuildIetfStatelessResetPacket( - FramerTestConnectionId(), - QuicFramer::GetMinStatelessResetPacketLength(), - kTestStatelessResetToken)), - "Tried to build stateless reset packet with received packet length"); + std::unique_ptr<QuicEncryptedPacket> data2( + framer_.BuildIetfStatelessResetPacket( + FramerTestConnectionId(), + QuicFramer::GetMinStatelessResetPacketLength(), + kTestStatelessResetToken)); + ASSERT_FALSE(data2); // Do not send stateless reset >= minimal stateless reset + 1 + max // connection ID length. @@ -15230,7 +15219,6 @@ TEST_P(QuicFramerTest, KeyUpdateOnFirstReceivedPacket) { // Key update is only used in QUIC+TLS. return; } - SetQuicReloadableFlag(quic_fix_key_update_on_first_packet, true); ASSERT_TRUE(framer_.version().KnowsWhichDecrypterToUse()); // Doesn't use SetDecrypterLevel since we want to use StrictTaggingDecrypter // instead of TestDecrypter. @@ -15262,8 +15250,7 @@ TEST_P(QuicFramerTest, KeyUpdateOnFirstReceivedPacket) { } TEST_P(QuicFramerTest, ErrorWhenUnexpectedFrameTypeEncountered) { - if (!GetQuicReloadableFlag(quic_reject_unexpected_ietf_frame_types) || - !VersionHasIetfQuicFrames(framer_.transport_version()) || + if (!VersionHasIetfQuicFrames(framer_.transport_version()) || !QuicVersionHasLongHeaderLengths(framer_.transport_version()) || !framer_.version().HasLongHeaderLengths()) { return; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_interval_deque.h b/chromium/net/third_party/quiche/src/quic/core/quic_interval_deque.h index ba27aa9d8f5..274c2e384df 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_interval_deque.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_interval_deque.h @@ -8,12 +8,12 @@ #include <algorithm> #include "absl/types/optional.h" -#include "quic/core/quic_circular_deque.h" #include "quic/core/quic_interval.h" #include "quic/core/quic_types.h" #include "quic/platform/api/quic_bug_tracker.h" #include "quic/platform/api/quic_export.h" #include "quic/platform/api/quic_logging.h" +#include "common/quiche_circular_deque.h" namespace quic { @@ -137,7 +137,7 @@ class QuicIntervalDequePeer; // // cached_index -> 1 // // container -> {{2, [25, 30)}, {3, [35, 50)}} -template <class T, class C = QUIC_NO_EXPORT QuicCircularDeque<T>> +template <class T, class C = QUIC_NO_EXPORT quiche::QuicheCircularDeque<T>> class QUIC_NO_EXPORT QuicIntervalDeque { public: class QUIC_NO_EXPORT Iterator { @@ -363,7 +363,7 @@ void QuicIntervalDeque<T, C>::PushBackUniversal(U&& item) { // Adding an empty interval is a bug. if (interval.Empty()) { QUIC_BUG(quic_bug_10862_3) - << "Trying to save empty interval to QuicCircularDeque."; + << "Trying to save empty interval to quiche::QuicheCircularDeque."; return; } container_.push_back(std::forward<U>(item)); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_legacy_version_encapsulator.cc b/chromium/net/third_party/quiche/src/quic/core/quic_legacy_version_encapsulator.cc index 27dbb9b48a8..11d2293bee5 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_legacy_version_encapsulator.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_legacy_version_encapsulator.cc @@ -7,7 +7,6 @@ #include "quic/core/crypto/crypto_protocol.h" #include "quic/core/quic_utils.h" #include "quic/platform/api/quic_bug_tracker.h" -#include "common/platform/api/quiche_text_utils.h" namespace quic { diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_legacy_version_encapsulator_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_legacy_version_encapsulator_test.cc index 1d855f2f55d..2f74d3ac7e7 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_legacy_version_encapsulator_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_legacy_version_encapsulator_test.cc @@ -9,7 +9,6 @@ #include "quic/platform/api/quic_expect_bug.h" #include "quic/platform/api/quic_test.h" #include "quic/test_tools/quic_test_utils.h" -#include "common/platform/api/quiche_text_utils.h" namespace quic { namespace test { diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_linux_socket_utils.h b/chromium/net/third_party/quiche/src/quic/core/quic_linux_socket_utils.h index 14c26dc8d73..5bbd875180b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_linux_socket_utils.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_linux_socket_utils.h @@ -148,7 +148,7 @@ struct QUIC_EXPORT_PRIVATE BufferedWrite { // multiple packets at once via ::sendmmsg. // // Example: -// QuicCircularDeque<BufferedWrite> buffered_writes; +// quiche::QuicheCircularDeque<BufferedWrite> buffered_writes; // ... (Populate buffered_writes) ... // // QuicMMsgHdr mhdr( diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_linux_socket_utils_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_linux_socket_utils_test.cc index 84259583063..588c2be8480 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_linux_socket_utils_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_linux_socket_utils_test.cc @@ -12,9 +12,9 @@ #include <string> -#include "quic/core/quic_circular_deque.h" #include "quic/platform/api/quic_test.h" #include "quic/test_tools/quic_mock_syscall_wrapper.h" +#include "common/quiche_circular_deque.h" using testing::_; using testing::InSequence; @@ -28,8 +28,8 @@ class QuicLinuxSocketUtilsTest : public QuicTest { protected: WriteResult TestWriteMultiplePackets( int fd, - const QuicCircularDeque<BufferedWrite>::const_iterator& first, - const QuicCircularDeque<BufferedWrite>::const_iterator& last, + const quiche::QuicheCircularDeque<BufferedWrite>::const_iterator& first, + const quiche::QuicheCircularDeque<BufferedWrite>::const_iterator& last, int* num_packets_sent) { QuicMMsgHdr mhdr( first, last, kCmsgSpaceForIp, @@ -171,7 +171,7 @@ TEST_F(QuicLinuxSocketUtilsTest, QuicMsgHdr) { } TEST_F(QuicLinuxSocketUtilsTest, QuicMMsgHdr) { - QuicCircularDeque<BufferedWrite> buffered_writes; + quiche::QuicheCircularDeque<BufferedWrite> buffered_writes; char packet_buf1[1024]; char packet_buf2[512]; buffered_writes.emplace_back( @@ -205,7 +205,7 @@ TEST_F(QuicLinuxSocketUtilsTest, QuicMMsgHdr) { TEST_F(QuicLinuxSocketUtilsTest, WriteMultiplePackets_NoPacketsToSend) { int num_packets_sent; - QuicCircularDeque<BufferedWrite> buffered_writes; + quiche::QuicheCircularDeque<BufferedWrite> buffered_writes; EXPECT_CALL(mock_syscalls_, Sendmmsg(_, _, _, _)).Times(0); @@ -216,7 +216,7 @@ TEST_F(QuicLinuxSocketUtilsTest, WriteMultiplePackets_NoPacketsToSend) { TEST_F(QuicLinuxSocketUtilsTest, WriteMultiplePackets_WriteBlocked) { int num_packets_sent; - QuicCircularDeque<BufferedWrite> buffered_writes; + quiche::QuicheCircularDeque<BufferedWrite> buffered_writes; buffered_writes.emplace_back(nullptr, 0, QuicIpAddress(), QuicSocketAddress(QuicIpAddress::Any4(), 0)); @@ -235,7 +235,7 @@ TEST_F(QuicLinuxSocketUtilsTest, WriteMultiplePackets_WriteBlocked) { TEST_F(QuicLinuxSocketUtilsTest, WriteMultiplePackets_WriteError) { int num_packets_sent; - QuicCircularDeque<BufferedWrite> buffered_writes; + quiche::QuicheCircularDeque<BufferedWrite> buffered_writes; buffered_writes.emplace_back(nullptr, 0, QuicIpAddress(), QuicSocketAddress(QuicIpAddress::Any4(), 0)); @@ -254,7 +254,7 @@ TEST_F(QuicLinuxSocketUtilsTest, WriteMultiplePackets_WriteError) { TEST_F(QuicLinuxSocketUtilsTest, WriteMultiplePackets_WriteSuccess) { int num_packets_sent; - QuicCircularDeque<BufferedWrite> buffered_writes; + quiche::QuicheCircularDeque<BufferedWrite> buffered_writes; const int kNumBufferedWrites = 10; static_assert(kNumBufferedWrites < 256, "Must be less than 256"); std::vector<std::string> buffer_holder; 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 42aebe5ce4b..cbca89dae55 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 @@ -15,10 +15,12 @@ #include "absl/base/optimization.h" #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" +#include "absl/types/optional.h" #include "quic/core/crypto/crypto_protocol.h" #include "quic/core/frames/quic_frame.h" #include "quic/core/frames/quic_path_challenge_frame.h" #include "quic/core/frames/quic_stream_frame.h" +#include "quic/core/quic_chaos_protector.h" #include "quic/core/quic_connection_id.h" #include "quic/core/quic_constants.h" #include "quic/core/quic_data_writer.h" @@ -32,7 +34,6 @@ #include "quic/platform/api/quic_flags.h" #include "quic/platform/api/quic_logging.h" #include "quic/platform/api/quic_server_stats.h" -#include "common/platform/api/quiche_text_utils.h" namespace quic { namespace { @@ -133,7 +134,8 @@ QuicPacketCreator::QuicPacketCreator(QuicConnectionId server_connection_id, flusher_attached_(false), fully_pad_crypto_handshake_packets_(true), latched_hard_max_packet_length_(0), - max_datagram_frame_size_(0) { + max_datagram_frame_size_(0), + chaos_protection_enabled_(false) { SetMaxPacketLength(kDefaultMaxPacketSize); if (!framer_->version().UsesTls()) { // QUIC+TLS negotiates the maximum datagram frame size via the @@ -159,21 +161,21 @@ bool QuicPacketCreator::CanSetMaxPacketLength() const { } void QuicPacketCreator::SetMaxPacketLength(QuicByteCount length) { - QUICHE_DCHECK(CanSetMaxPacketLength()); + QUICHE_DCHECK(CanSetMaxPacketLength()) << ENDPOINT; // Avoid recomputing |max_plaintext_size_| if the length does not actually // change. if (length == max_packet_length_) { return; } - QUIC_DVLOG(1) << "Updating packet creator max packet length from " + QUIC_DVLOG(1) << ENDPOINT << "Updating packet creator max packet length from " << max_packet_length_ << " to " << length; max_packet_length_ = length; max_plaintext_size_ = framer_->GetMaxPlaintextSize(max_packet_length_); QUIC_BUG_IF(quic_bug_12398_2, max_plaintext_size_ - PacketHeaderSize() < MinPlaintextPacketSize(framer_->version())) - << "Attempted to set max packet length too small"; + << ENDPOINT << "Attempted to set max packet length too small"; } void QuicPacketCreator::SetMaxDatagramFrameSize( @@ -192,7 +194,7 @@ void QuicPacketCreator::SetMaxDatagramFrameSize( } void QuicPacketCreator::SetSoftMaxPacketLength(QuicByteCount length) { - QUICHE_DCHECK(CanSetMaxPacketLength()); + QUICHE_DCHECK(CanSetMaxPacketLength()) << ENDPOINT; if (length > max_packet_length_) { QUIC_BUG(quic_bug_10752_2) << ENDPOINT @@ -204,11 +206,12 @@ void QuicPacketCreator::SetSoftMaxPacketLength(QuicByteCount length) { PacketHeaderSize() + MinPlaintextPacketSize(framer_->version())) { // Please note: this would not guarantee to fit next packet if the size of // packet header increases (e.g., encryption level changes). - QUIC_DLOG(INFO) << length << " is too small to fit packet header"; + QUIC_DLOG(INFO) << ENDPOINT << length + << " is too small to fit packet header"; RemoveSoftMaxPacketLength(); return; } - QUIC_DVLOG(1) << "Setting soft max packet length to: " << length; + QUIC_DVLOG(1) << ENDPOINT << "Setting soft max packet length to: " << length; latched_hard_max_packet_length_ = max_packet_length_; max_packet_length_ = length; max_plaintext_size_ = framer_->GetMaxPlaintextSize(length); @@ -218,18 +221,18 @@ void QuicPacketCreator::SetSoftMaxPacketLength(QuicByteCount length) { // A packet that is already open might send kQuicVersionSize bytes less than the // maximum packet size if we stop sending version before it is serialized. void QuicPacketCreator::StopSendingVersion() { - QUICHE_DCHECK(send_version_in_packet_); - QUICHE_DCHECK(!version().HasIetfInvariantHeader()); + QUICHE_DCHECK(send_version_in_packet_) << ENDPOINT; + QUICHE_DCHECK(!version().HasIetfInvariantHeader()) << ENDPOINT; send_version_in_packet_ = false; if (packet_size_ > 0) { - QUICHE_DCHECK_LT(kQuicVersionSize, packet_size_); + QUICHE_DCHECK_LT(kQuicVersionSize, packet_size_) << ENDPOINT; packet_size_ -= kQuicVersionSize; } } void QuicPacketCreator::SetDiversificationNonce( const DiversificationNonce& nonce) { - QUICHE_DCHECK(!have_diversification_nonce_); + QUICHE_DCHECK(!have_diversification_nonce_) << ENDPOINT; have_diversification_nonce_ = true; diversification_nonce_ = nonce; } @@ -240,14 +243,16 @@ void QuicPacketCreator::UpdatePacketNumberLength( if (!queued_frames_.empty()) { // Don't change creator state if there are frames queued. QUIC_BUG(quic_bug_10752_3) - << "Called UpdatePacketNumberLength with " << queued_frames_.size() + << ENDPOINT << "Called UpdatePacketNumberLength with " + << queued_frames_.size() << " queued_frames. First frame type:" << queued_frames_.front().type << " last frame type:" << queued_frames_.back().type; return; } const QuicPacketNumber next_packet_number = NextSendingPacketNumber(); - QUICHE_DCHECK_LE(least_packet_awaited_by_peer, next_packet_number); + QUICHE_DCHECK_LE(least_packet_awaited_by_peer, next_packet_number) + << ENDPOINT; const uint64_t current_delta = next_packet_number - least_packet_awaited_by_peer; const uint64_t delta = std::max(current_delta, max_packets_in_flight); @@ -273,7 +278,8 @@ void QuicPacketCreator::SkipNPacketNumbers( if (!queued_frames_.empty()) { // Don't change creator state if there are frames queued. QUIC_BUG(quic_bug_10752_4) - << "Called SkipNPacketNumbers with " << queued_frames_.size() + << ENDPOINT << "Called SkipNPacketNumbers with " + << queued_frames_.size() << " queued_frames. First frame type:" << queued_frames_.front().type << " last frame type:" << queued_frames_.back().type; return; @@ -281,7 +287,7 @@ void QuicPacketCreator::SkipNPacketNumbers( if (packet_.packet_number > packet_.packet_number + count) { // Skipping count packet numbers causes packet number wrapping around, // reject it. - QUIC_LOG(WARNING) << "Skipping " << count + QUIC_LOG(WARNING) << ENDPOINT << "Skipping " << count << " packet numbers causes packet number wrapping " "around, least_packet_awaited_by_peer: " << least_packet_awaited_by_peer @@ -300,7 +306,7 @@ bool QuicPacketCreator::ConsumeCryptoDataToFillCurrentPacket( bool needs_full_padding, TransmissionType transmission_type, QuicFrame* frame) { - QUIC_DVLOG(2) << "ConsumeCryptoDataToFillCurrentPacket " << level + QUIC_DVLOG(2) << ENDPOINT << "ConsumeCryptoDataToFillCurrentPacket " << level << " write_length " << write_length << " offset " << offset << (needs_full_padding ? " needs_full_padding" : "") << " " << transmission_type; @@ -338,7 +344,7 @@ bool QuicPacketCreator::ConsumeDataToFillCurrentPacket( const std::string error_details = "Client hello won't fit in a single packet."; QUIC_BUG(quic_bug_10752_5) - << error_details << " Constructed stream frame length: " + << ENDPOINT << error_details << " Constructed stream frame length: " << frame->stream_frame.data_length << " CHLO length: " << data_size; delegate_->OnUnrecoverableError(QUIC_CRYPTO_CHLO_TOO_LARGE, error_details); return false; @@ -422,16 +428,17 @@ void QuicPacketCreator::CreateStreamFrame(QuicStreamId id, GetSourceConnectionIdLength(), kIncludeVersion, IncludeNonceInPublicHeader(), PACKET_6BYTE_PACKET_NUMBER, GetRetryTokenLengthLength(), GetLengthLength(), offset) || - latched_hard_max_packet_length_ > 0); + latched_hard_max_packet_length_ > 0) + << ENDPOINT; QUIC_BUG_IF(quic_bug_12398_3, !HasRoomForStreamFrame(id, offset, data_size)) - << "No room for Stream frame, BytesFree: " << BytesFree() + << ENDPOINT << "No room for Stream frame, BytesFree: " << BytesFree() << " MinStreamFrameSize: " << QuicFramer::GetMinStreamFrameSize(framer_->transport_version(), id, offset, true, data_size); QUIC_BUG_IF(quic_bug_12398_4, data_size == 0 && !fin) - << "Creating a stream frame for stream ID:" << id + << ENDPOINT << "Creating a stream frame for stream ID:" << id << " with no data or fin."; size_t min_frame_size = QuicFramer::GetMinStreamFrameSize( framer_->transport_version(), id, offset, @@ -472,7 +479,7 @@ void QuicPacketCreator::FlushCurrentPacket() { external_buffer.release_buffer = nullptr; } - QUICHE_DCHECK_EQ(nullptr, packet_.encrypted_buffer); + QUICHE_DCHECK_EQ(nullptr, packet_.encrypted_buffer) << ENDPOINT; if (!SerializePacket(std::move(external_buffer), kMaxOutgoingPacketSize)) { return; } @@ -480,7 +487,8 @@ void QuicPacketCreator::FlushCurrentPacket() { } void QuicPacketCreator::OnSerializedPacket() { - QUIC_BUG_IF(quic_bug_12398_5, packet_.encrypted_buffer == nullptr); + QUIC_BUG_IF(quic_bug_12398_5, packet_.encrypted_buffer == nullptr) + << ENDPOINT; SerializedPacket packet(std::move(packet_)); ClearPacket(); @@ -499,10 +507,10 @@ void QuicPacketCreator::ClearPacket() { packet_.has_message = false; packet_.fate = SEND_TO_WRITER; QUIC_BUG_IF(quic_bug_12398_6, packet_.release_encrypted_buffer != nullptr) - << "packet_.release_encrypted_buffer should be empty"; + << ENDPOINT << "packet_.release_encrypted_buffer should be empty"; packet_.release_encrypted_buffer = nullptr; - QUICHE_DCHECK(packet_.retransmittable_frames.empty()); - QUICHE_DCHECK(packet_.nonretransmittable_frames.empty()); + QUICHE_DCHECK(packet_.retransmittable_frames.empty()) << ENDPOINT; + QUICHE_DCHECK(packet_.nonretransmittable_frames.empty()) << ENDPOINT; packet_.largest_acked.Clear(); needs_full_padding_ = false; } @@ -515,6 +523,7 @@ size_t QuicPacketCreator::ReserializeInitialPacketInCoalescedPacket( QUIC_BUG_IF(quic_bug_12398_7, packet.encryption_level != ENCRYPTION_INITIAL); QUIC_BUG_IF(quic_bug_12398_8, packet.nonretransmittable_frames.empty() && packet.retransmittable_frames.empty()) + << ENDPOINT << "Attempt to serialize empty ENCRYPTION_INITIAL packet in coalesced " "packet"; ScopedPacketContextSwitcher switcher( @@ -523,13 +532,15 @@ size_t QuicPacketCreator::ReserializeInitialPacketInCoalescedPacket( packet.packet_number_length, packet.encryption_level, &packet_); for (const QuicFrame& frame : packet.nonretransmittable_frames) { if (!AddFrame(frame, packet.transmission_type)) { - QUIC_BUG(quic_bug_10752_6) << "Failed to serialize frame: " << frame; + QUIC_BUG(quic_bug_10752_6) + << ENDPOINT << "Failed to serialize frame: " << frame; return 0; } } for (const QuicFrame& frame : packet.retransmittable_frames) { if (!AddFrame(frame, packet.transmission_type)) { - QUIC_BUG(quic_bug_10752_7) << "Failed to serialize frame: " << frame; + QUIC_BUG(quic_bug_10752_7) + << ENDPOINT << "Failed to serialize frame: " << frame; return 0; } } @@ -539,7 +550,7 @@ size_t QuicPacketCreator::ReserializeInitialPacketInCoalescedPacket( if (!AddFrame(QuicFrame(QuicPaddingFrame(padding_size)), packet.transmission_type)) { QUIC_BUG(quic_bug_10752_8) - << "Failed to add padding of size " << padding_size + << ENDPOINT << "Failed to add padding of size " << padding_size << " when serializing ENCRYPTION_INITIAL " "packet in coalesced packet"; return 0; @@ -566,8 +577,9 @@ void QuicPacketCreator::CreateAndSerializeStreamFrame( TransmissionType transmission_type, size_t* num_bytes_consumed) { // TODO(b/167222597): consider using ScopedSerializationFailureHandler. - QUICHE_DCHECK(queued_frames_.empty()); - QUICHE_DCHECK(!QuicUtils::IsCryptoStreamId(transport_version(), id)); + QUICHE_DCHECK(queued_frames_.empty()) << ENDPOINT; + QUICHE_DCHECK(!QuicUtils::IsCryptoStreamId(transport_version(), id)) + << ENDPOINT; // Write out the packet header QuicPacketHeader header; FillPacketHeader(&header); @@ -590,13 +602,13 @@ void QuicPacketCreator::CreateAndSerializeStreamFrame( QuicDataWriter writer(kMaxOutgoingPacketSize, encrypted_buffer); size_t length_field_offset = 0; if (!framer_->AppendPacketHeader(header, &writer, &length_field_offset)) { - QUIC_BUG(quic_bug_10752_9) << "AppendPacketHeader failed"; + QUIC_BUG(quic_bug_10752_9) << ENDPOINT << "AppendPacketHeader failed"; return; } // Create a Stream frame with the remaining space. QUIC_BUG_IF(quic_bug_12398_9, iov_offset == write_length && !fin) - << "Creating a stream frame with no data or fin."; + << ENDPOINT << "Creating a stream frame with no data or fin."; const size_t remaining_data_size = write_length - iov_offset; size_t min_frame_size = QuicFramer::GetMinStreamFrameSize( framer_->transport_version(), id, stream_offset, @@ -631,18 +643,18 @@ void QuicPacketCreator::CreateAndSerializeStreamFrame( // into one method that takes a QuicStreamFrame, if warranted. bool omit_frame_length = !needs_padding; if (!framer_->AppendTypeByte(QuicFrame(frame), omit_frame_length, &writer)) { - QUIC_BUG(quic_bug_10752_10) << "AppendTypeByte failed"; + QUIC_BUG(quic_bug_10752_10) << ENDPOINT << "AppendTypeByte failed"; return; } if (!framer_->AppendStreamFrame(frame, omit_frame_length, &writer)) { - QUIC_BUG(quic_bug_10752_11) << "AppendStreamFrame failed"; + QUIC_BUG(quic_bug_10752_11) << ENDPOINT << "AppendStreamFrame failed"; return; } if (needs_padding && plaintext_bytes_written < MinPlaintextPacketSize(framer_->version()) && !writer.WritePaddingBytes(MinPlaintextPacketSize(framer_->version()) - plaintext_bytes_written)) { - QUIC_BUG(quic_bug_10752_12) << "Unable to add padding bytes"; + QUIC_BUG(quic_bug_10752_12) << ENDPOINT << "Unable to add padding bytes"; return; } @@ -655,14 +667,15 @@ void QuicPacketCreator::CreateAndSerializeStreamFrame( QUICHE_DCHECK(packet_.encryption_level == ENCRYPTION_FORWARD_SECURE || packet_.encryption_level == ENCRYPTION_ZERO_RTT) - << packet_.encryption_level; + << ENDPOINT << packet_.encryption_level; size_t encrypted_length = framer_->EncryptInPlace( packet_.encryption_level, packet_.packet_number, GetStartOfEncryptedData(framer_->transport_version(), header), writer.length(), kMaxOutgoingPacketSize, encrypted_buffer); if (encrypted_length == 0) { QUIC_BUG(quic_bug_10752_13) - << "Failed to encrypt packet number " << header.packet_number; + << ENDPOINT << "Failed to encrypt packet number " + << header.packet_number; return; } // TODO(ianswett): Optimize the storage so RetransmitableFrames can be @@ -724,7 +737,6 @@ size_t QuicPacketCreator::ExpansionOnNewFrameWithLastFrame( } size_t QuicPacketCreator::BytesFree() const { - QUICHE_DCHECK_GE(max_plaintext_size_, PacketSize()); return max_plaintext_size_ - std::min(max_plaintext_size_, PacketSize() + ExpansionOnNewFrame()); } @@ -743,22 +755,51 @@ bool QuicPacketCreator::AddPaddedSavedFrame( return false; } +absl::optional<size_t> +QuicPacketCreator::MaybeBuildDataPacketWithChaosProtection( + const QuicPacketHeader& header, + char* buffer) { + if (!chaos_protection_enabled_ || + packet_.encryption_level != ENCRYPTION_INITIAL || + !framer_->version().UsesCryptoFrames() || queued_frames_.size() != 2u || + queued_frames_[0].type != CRYPTO_FRAME || + queued_frames_[1].type != PADDING_FRAME || + // Do not perform chaos protection if we do not have a known number of + // padding bytes to work with. + queued_frames_[1].padding_frame.num_padding_bytes <= 0 || + // Chaos protection relies on the framer using a crypto data producer, + // which is always the case in practice. + framer_->data_producer() == nullptr) { + return absl::nullopt; + } + const QuicCryptoFrame& crypto_frame = *queued_frames_[0].crypto_frame; + if (packet_.encryption_level != crypto_frame.level) { + QUIC_BUG(chaos frame level) + << ENDPOINT << packet_.encryption_level << " != " << crypto_frame.level; + return absl::nullopt; + } + QuicChaosProtector chaos_protector( + crypto_frame, queued_frames_[1].padding_frame.num_padding_bytes, + packet_size_, framer_, random_); + return chaos_protector.BuildDataPacket(header, buffer); +} + bool QuicPacketCreator::SerializePacket(QuicOwnedPacketBuffer encrypted_buffer, size_t encrypted_buffer_len) { if (packet_.encrypted_buffer != nullptr) { const std::string error_details = "Packet's encrypted buffer is not empty before serialization"; - QUIC_BUG(quic_bug_10752_14) << error_details; + QUIC_BUG(quic_bug_10752_14) << ENDPOINT << error_details; delegate_->OnUnrecoverableError(QUIC_FAILED_TO_SERIALIZE_PACKET, error_details); return false; } ScopedSerializationFailureHandler handler(this); - QUICHE_DCHECK_LT(0u, encrypted_buffer_len); + QUICHE_DCHECK_LT(0u, encrypted_buffer_len) << ENDPOINT; QUIC_BUG_IF(quic_bug_12398_10, queued_frames_.empty() && pending_padding_bytes_ == 0) - << "Attempt to serialize empty packet"; + << ENDPOINT << "Attempt to serialize empty packet"; QuicPacketHeader header; // FillPacketHeader increments packet_number_. FillPacketHeader(&header); @@ -789,15 +830,25 @@ bool QuicPacketCreator::SerializePacket(QuicOwnedPacketBuffer encrypted_buffer, return false; } - QUICHE_DCHECK_GE(max_plaintext_size_, packet_size_); + QUICHE_DCHECK_GE(max_plaintext_size_, packet_size_) << ENDPOINT; // Use the packet_size_ instead of the buffer size to ensure smaller // packet sizes are properly used. - size_t length = - framer_->BuildDataPacket(header, queued_frames_, encrypted_buffer.buffer, - packet_size_, packet_.encryption_level); + + size_t length; + absl::optional<size_t> length_with_chaos_protection = + MaybeBuildDataPacketWithChaosProtection(header, encrypted_buffer.buffer); + if (length_with_chaos_protection.has_value()) { + length = length_with_chaos_protection.value(); + } else { + length = framer_->BuildDataPacket(header, queued_frames_, + encrypted_buffer.buffer, packet_size_, + packet_.encryption_level); + } + if (length == 0) { QUIC_BUG(quic_bug_10752_16) - << "Failed to serialize " << QuicFramesToString(queued_frames_) + << ENDPOINT << "Failed to serialize " + << QuicFramesToString(queued_frames_) << " at encryption_level: " << packet_.encryption_level << ", needs_full_padding_: " << needs_full_padding_ << ", pending_padding_bytes_: " << pending_padding_bytes_ @@ -818,7 +869,7 @@ bool QuicPacketCreator::SerializePacket(QuicOwnedPacketBuffer encrypted_buffer, // Because of possible truncation, we can't be confident that our // packet size calculation worked correctly. if (!possibly_truncated_by_length) { - QUICHE_DCHECK_EQ(packet_size_, length); + QUICHE_DCHECK_EQ(packet_size_, length) << ENDPOINT; } const size_t encrypted_length = framer_->EncryptInPlace( packet_.encryption_level, packet_.packet_number, @@ -826,7 +877,8 @@ bool QuicPacketCreator::SerializePacket(QuicOwnedPacketBuffer encrypted_buffer, encrypted_buffer_len, encrypted_buffer.buffer); if (encrypted_length == 0) { QUIC_BUG(quic_bug_10752_17) - << "Failed to encrypt packet number " << packet_.packet_number; + << ENDPOINT << "Failed to encrypt packet number " + << packet_.packet_number; return false; } @@ -843,6 +895,7 @@ std::unique_ptr<SerializedPacket> QuicPacketCreator::SerializeConnectivityProbingPacket() { QUIC_BUG_IF(quic_bug_12398_11, VersionHasIetfQuicFrames(framer_->transport_version())) + << ENDPOINT << "Must not be version 99 to serialize padded ping connectivity probe"; RemoveSoftMaxPacketLength(); QuicPacketHeader header; @@ -855,14 +908,15 @@ QuicPacketCreator::SerializeConnectivityProbingPacket() { std::unique_ptr<char[]> buffer(new char[kMaxOutgoingPacketSize]); size_t length = BuildConnectivityProbingPacket( header, buffer.get(), max_plaintext_size_, packet_.encryption_level); - QUICHE_DCHECK(length); + QUICHE_DCHECK(length) << ENDPOINT; - QUICHE_DCHECK_EQ(packet_.encryption_level, ENCRYPTION_FORWARD_SECURE); + QUICHE_DCHECK_EQ(packet_.encryption_level, ENCRYPTION_FORWARD_SECURE) + << ENDPOINT; const size_t encrypted_length = framer_->EncryptInPlace( packet_.encryption_level, packet_.packet_number, GetStartOfEncryptedData(framer_->transport_version(), header), length, kMaxOutgoingPacketSize, buffer.get()); - QUICHE_DCHECK(encrypted_length); + QUICHE_DCHECK(encrypted_length) << ENDPOINT; std::unique_ptr<SerializedPacket> serialize_packet(new SerializedPacket( header.packet_number, header.packet_number_length, buffer.release(), @@ -882,6 +936,7 @@ QuicPacketCreator::SerializePathChallengeConnectivityProbingPacket( const QuicPathFrameBuffer& payload) { QUIC_BUG_IF(quic_bug_12398_12, !VersionHasIetfQuicFrames(framer_->transport_version())) + << ENDPOINT << "Must be version 99 to serialize path challenge connectivity probe, " "is version " << framer_->transport_version(); @@ -896,14 +951,15 @@ QuicPacketCreator::SerializePathChallengeConnectivityProbingPacket( size_t length = BuildPaddedPathChallengePacket(header, buffer.get(), max_plaintext_size_, payload, packet_.encryption_level); - QUICHE_DCHECK(length); + QUICHE_DCHECK(length) << ENDPOINT; - QUICHE_DCHECK_EQ(packet_.encryption_level, ENCRYPTION_FORWARD_SECURE); + QUICHE_DCHECK_EQ(packet_.encryption_level, ENCRYPTION_FORWARD_SECURE) + << ENDPOINT; const size_t encrypted_length = framer_->EncryptInPlace( packet_.encryption_level, packet_.packet_number, GetStartOfEncryptedData(framer_->transport_version(), header), length, kMaxOutgoingPacketSize, buffer.get()); - QUICHE_DCHECK(encrypted_length); + QUICHE_DCHECK(encrypted_length) << ENDPOINT; std::unique_ptr<SerializedPacket> serialize_packet( new SerializedPacket(header.packet_number, header.packet_number_length, @@ -921,10 +977,11 @@ QuicPacketCreator::SerializePathChallengeConnectivityProbingPacket( std::unique_ptr<SerializedPacket> QuicPacketCreator::SerializePathResponseConnectivityProbingPacket( - const QuicCircularDeque<QuicPathFrameBuffer>& payloads, + const quiche::QuicheCircularDeque<QuicPathFrameBuffer>& payloads, const bool is_padded) { QUIC_BUG_IF(quic_bug_12398_13, !VersionHasIetfQuicFrames(framer_->transport_version())) + << ENDPOINT << "Must be version 99 to serialize path response connectivity probe, is " "version " << framer_->transport_version(); @@ -939,14 +996,15 @@ QuicPacketCreator::SerializePathResponseConnectivityProbingPacket( size_t length = BuildPathResponsePacket(header, buffer.get(), max_plaintext_size_, payloads, is_padded, packet_.encryption_level); - QUICHE_DCHECK(length); + QUICHE_DCHECK(length) << ENDPOINT; - QUICHE_DCHECK_EQ(packet_.encryption_level, ENCRYPTION_FORWARD_SECURE); + QUICHE_DCHECK_EQ(packet_.encryption_level, ENCRYPTION_FORWARD_SECURE) + << ENDPOINT; const size_t encrypted_length = framer_->EncryptInPlace( packet_.encryption_level, packet_.packet_number, GetStartOfEncryptedData(framer_->transport_version(), header), length, kMaxOutgoingPacketSize, buffer.get()); - QUICHE_DCHECK(encrypted_length); + QUICHE_DCHECK(encrypted_length) << ENDPOINT; std::unique_ptr<SerializedPacket> serialize_packet( new SerializedPacket(header.packet_number, header.packet_number_length, @@ -968,7 +1026,8 @@ size_t QuicPacketCreator::BuildPaddedPathChallengePacket( size_t packet_length, const QuicPathFrameBuffer& payload, EncryptionLevel level) { - QUICHE_DCHECK(VersionHasIetfQuicFrames(framer_->transport_version())); + QUICHE_DCHECK(VersionHasIetfQuicFrames(framer_->transport_version())) + << ENDPOINT; QuicFrames frames; // Write a PATH_CHALLENGE frame, which has a random 8-byte payload @@ -991,15 +1050,17 @@ size_t QuicPacketCreator::BuildPathResponsePacket( const QuicPacketHeader& header, char* buffer, size_t packet_length, - const QuicCircularDeque<QuicPathFrameBuffer>& payloads, + const quiche::QuicheCircularDeque<QuicPathFrameBuffer>& payloads, const bool is_padded, EncryptionLevel level) { if (payloads.empty()) { QUIC_BUG(quic_bug_12398_14) + << ENDPOINT << "Attempt to generate connectivity response with no request payloads"; return 0; } - QUICHE_DCHECK(VersionHasIetfQuicFrames(framer_->transport_version())); + QUICHE_DCHECK(VersionHasIetfQuicFrames(framer_->transport_version())) + << ENDPOINT; std::vector<std::unique_ptr<QuicPathResponseFrame>> path_response_frames; for (const QuicPathFrameBuffer& payload : payloads) { @@ -1052,12 +1113,12 @@ size_t QuicPacketCreator::SerializeCoalescedPacket( size_t buffer_len) { if (HasPendingFrames()) { QUIC_BUG(quic_bug_10752_18) - << "Try to serialize coalesced packet with pending frames"; + << ENDPOINT << "Try to serialize coalesced packet with pending frames"; return 0; } RemoveSoftMaxPacketLength(); QUIC_BUG_IF(quic_bug_12398_15, coalesced.length() == 0) - << "Attempt to serialize empty coalesced packet"; + << ENDPOINT << "Attempt to serialize empty coalesced packet"; size_t packet_length = 0; if (coalesced.initial_packet() != nullptr) { // Padding coalesced packet containing initial packet to full. @@ -1073,6 +1134,7 @@ size_t QuicPacketCreator::SerializeCoalescedPacket( *coalesced.initial_packet(), padding_size, buffer, buffer_len); if (initial_length == 0) { QUIC_BUG(quic_bug_10752_19) + << ENDPOINT << "Failed to reserialize ENCRYPTION_INITIAL packet in " "coalesced packet"; return 0; @@ -1141,7 +1203,8 @@ QuicConnectionIdIncluded QuicPacketCreator::GetSourceConnectionIdIncluded() QuicConnectionIdLength QuicPacketCreator::GetDestinationConnectionIdLength() const { QUICHE_DCHECK(QuicUtils::IsConnectionIdValidForVersion(server_connection_id_, - transport_version())); + transport_version())) + << ENDPOINT; return GetDestinationConnectionIdIncluded() == CONNECTION_ID_PRESENT ? static_cast<QuicConnectionIdLength>( GetDestinationConnectionId().length()) @@ -1150,7 +1213,8 @@ QuicConnectionIdLength QuicPacketCreator::GetDestinationConnectionIdLength() QuicConnectionIdLength QuicPacketCreator::GetSourceConnectionIdLength() const { QUICHE_DCHECK(QuicUtils::IsConnectionIdValidForVersion(server_connection_id_, - transport_version())); + transport_version())) + << ENDPOINT; return GetSourceConnectionIdIncluded() == CONNECTION_ID_PRESENT ? static_cast<QuicConnectionIdLength>( GetSourceConnectionId().length()) @@ -1201,8 +1265,10 @@ bool QuicPacketCreator::ConsumeRetransmittableControlFrame( QUIC_BUG_IF(quic_bug_12398_16, IsControlFrame(frame.type) && !GetControlFrameId(frame) && frame.type != PING_FRAME) + << ENDPOINT << "Adding a control frame with no control frame id: " << frame; - QUICHE_DCHECK(QuicUtils::IsRetransmittableFrame(frame.type)) << frame; + QUICHE_DCHECK(QuicUtils::IsRetransmittableFrame(frame.type)) + << ENDPOINT << frame; MaybeBundleAckOpportunistically(); if (HasPendingFrames()) { if (AddFrame(frame, next_transmission_type_)) { @@ -1210,7 +1276,7 @@ bool QuicPacketCreator::ConsumeRetransmittableControlFrame( return true; } } - QUICHE_DCHECK(!HasPendingFrames()); + QUICHE_DCHECK(!HasPendingFrames()) << ENDPOINT; if (frame.type != PING_FRAME && frame.type != CONNECTION_CLOSE_FRAME && !delegate_->ShouldGeneratePacket(HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE)) { @@ -1219,7 +1285,7 @@ bool QuicPacketCreator::ConsumeRetransmittableControlFrame( } const bool success = AddFrame(frame, next_transmission_type_); QUIC_BUG_IF(quic_bug_10752_20, !success) - << "Failed to add frame:" << frame + << ENDPOINT << "Failed to add frame:" << frame << " transmission_type:" << next_transmission_type_; return success; } @@ -1229,13 +1295,14 @@ QuicConsumedData QuicPacketCreator::ConsumeData(QuicStreamId id, QuicStreamOffset offset, StreamSendingState state) { QUIC_BUG_IF(quic_bug_10752_21, !flusher_attached_) + << ENDPOINT << "Packet flusher is not attached when " "generator tries to write stream data."; bool has_handshake = QuicUtils::IsCryptoStreamId(transport_version(), id); MaybeBundleAckOpportunistically(); bool fin = state != NO_FIN; QUIC_BUG_IF(quic_bug_12398_17, has_handshake && fin) - << "Handshake packets should never send a fin"; + << ENDPOINT << "Handshake packets should never send a fin"; // To make reasoning about crypto frames easier, we don't combine them with // other retransmittable frames in a single packet. if (has_handshake && HasPendingRetransmittableFrames()) { @@ -1250,7 +1317,8 @@ QuicConsumedData QuicPacketCreator::ConsumeData(QuicStreamId id, } if (!fin && (write_length == 0)) { - QUIC_BUG(quic_bug_10752_22) << "Attempt to consume empty data without FIN."; + QUIC_BUG(quic_bug_10752_22) + << ENDPOINT << "Attempt to consume empty data without FIN."; return QuicConsumedData(0, false); } // We determine if we can enter the fast path before executing @@ -1273,7 +1341,8 @@ QuicConsumedData QuicPacketCreator::ConsumeData(QuicStreamId id, next_transmission_type_, &frame)) { // The creator is always flushed if there's not enough room for a new // stream frame before ConsumeData, so ConsumeData should always succeed. - QUIC_BUG(quic_bug_10752_23) << "Failed to ConsumeData, stream:" << id; + QUIC_BUG(quic_bug_10752_23) + << ENDPOINT << "Failed to ConsumeData, stream:" << id; return QuicConsumedData(0, false); } @@ -1285,7 +1354,8 @@ QuicConsumedData QuicPacketCreator::ConsumeData(QuicStreamId id, AddRandomPadding(); } QUICHE_DCHECK(total_bytes_consumed == write_length || - (bytes_consumed > 0 && HasPendingFrames())); + (bytes_consumed > 0 && HasPendingFrames())) + << ENDPOINT; if (total_bytes_consumed == write_length) { // We're done writing the data. Exit the loop. @@ -1320,7 +1390,8 @@ QuicConsumedData QuicPacketCreator::ConsumeDataFastPath( QuicStreamOffset offset, bool fin, size_t total_bytes_consumed) { - QUICHE_DCHECK(!QuicUtils::IsCryptoStreamId(transport_version(), id)); + QUICHE_DCHECK(!QuicUtils::IsCryptoStreamId(transport_version(), id)) + << ENDPOINT; if (AttemptingToSendUnencryptedStreamData()) { return QuicConsumedData(total_bytes_consumed, fin && (total_bytes_consumed == write_length)); @@ -1337,7 +1408,7 @@ QuicConsumedData QuicPacketCreator::ConsumeDataFastPath( if (bytes_consumed == 0) { const std::string error_details = "Failed in CreateAndSerializeStreamFrame."; - QUIC_BUG(quic_bug_10752_24) << error_details; + QUIC_BUG(quic_bug_10752_24) << ENDPOINT << error_details; delegate_->OnUnrecoverableError(QUIC_FAILED_TO_SERIALIZE_PACKET, error_details); break; @@ -1352,9 +1423,10 @@ QuicConsumedData QuicPacketCreator::ConsumeDataFastPath( size_t QuicPacketCreator::ConsumeCryptoData(EncryptionLevel level, size_t write_length, QuicStreamOffset offset) { - QUIC_DVLOG(2) << "ConsumeCryptoData " << level << " write_length " + QUIC_DVLOG(2) << ENDPOINT << "ConsumeCryptoData " << level << " write_length " << write_length << " offset " << offset; QUIC_BUG_IF(quic_bug_10752_25, !flusher_attached_) + << ENDPOINT << "Packet flusher is not attached when " "generator tries to write crypto data."; MaybeBundleAckOpportunistically(); @@ -1381,7 +1453,7 @@ size_t QuicPacketCreator::ConsumeCryptoData(EncryptionLevel level, // assuming here that they won't occupy so much of the packet that a // CRYPTO frame won't fit. QUIC_BUG(quic_bug_10752_26) - << "Failed to ConsumeCryptoData at level " << level; + << ENDPOINT << "Failed to ConsumeCryptoData at level " << level; return 0; } total_bytes_consumed += frame.crypto_frame->data_length; @@ -1398,6 +1470,7 @@ void QuicPacketCreator::GenerateMtuDiscoveryPacket(QuicByteCount target_mtu) { // MTU discovery frames must be sent by themselves. if (!CanSetMaxPacketLength()) { QUIC_BUG(quic_bug_10752_27) + << ENDPOINT << "MTU discovery packets should only be sent when no other " << "frames needs to be sent."; return; @@ -1416,7 +1489,7 @@ void QuicPacketCreator::GenerateMtuDiscoveryPacket(QuicByteCount target_mtu) { // The only reason AddFrame can fail is that the packet is too full to fit in // a ping. This is not possible for any sane MTU. QUIC_BUG_IF(quic_bug_10752_28, !success) - << "Failed to send path MTU target_mtu:" << target_mtu + << ENDPOINT << "Failed to send path MTU target_mtu:" << target_mtu << " transmission_type:" << next_transmission_type_; // Reset the packet length back. @@ -1435,12 +1508,13 @@ void QuicPacketCreator::MaybeBundleAckOpportunistically() { const bool flushed = FlushAckFrame(delegate_->MaybeBundleAckOpportunistically()); QUIC_BUG_IF(quic_bug_10752_29, !flushed) - << "Failed to flush ACK frame. encryption_level:" + << ENDPOINT << "Failed to flush ACK frame. encryption_level:" << packet_.encryption_level; } bool QuicPacketCreator::FlushAckFrame(const QuicFrames& frames) { QUIC_BUG_IF(quic_bug_10752_30, !flusher_attached_) + << ENDPOINT << "Packet flusher is not attached when " "generator tries to send ACK frame."; // MaybeBundleAckOpportunistically could be called nestedly when sending a @@ -1448,16 +1522,18 @@ bool QuicPacketCreator::FlushAckFrame(const QuicFrames& frames) { QUIC_BUG_IF(quic_bug_12398_18, GetQuicReloadableFlag(quic_single_ack_in_packet2) && !frames.empty() && has_ack()) - << "Trying to flush " << frames << " when there is ACK queued"; + << ENDPOINT << "Trying to flush " << frames + << " when there is ACK queued"; for (const auto& frame : frames) { - QUICHE_DCHECK(frame.type == ACK_FRAME || frame.type == STOP_WAITING_FRAME); + QUICHE_DCHECK(frame.type == ACK_FRAME || frame.type == STOP_WAITING_FRAME) + << ENDPOINT; if (HasPendingFrames()) { if (AddFrame(frame, next_transmission_type_)) { // There is pending frames and current frame fits. continue; } } - QUICHE_DCHECK(!HasPendingFrames()); + QUICHE_DCHECK(!HasPendingFrames()) << ENDPOINT; // There is no pending frames, consult the delegate whether a packet can be // generated. if (!delegate_->ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA, @@ -1465,7 +1541,8 @@ bool QuicPacketCreator::FlushAckFrame(const QuicFrames& frames) { return false; } const bool success = AddFrame(frame, next_transmission_type_); - QUIC_BUG_IF(quic_bug_10752_31, !success) << "Failed to flush " << frame; + QUIC_BUG_IF(quic_bug_10752_31, !success) + << ENDPOINT << "Failed to flush " << frame; } return true; } @@ -1488,7 +1565,7 @@ void QuicPacketCreator::Flush() { if (GetQuicFlag(FLAGS_quic_export_write_path_stats_at_server)) { if (!write_start_packet_number_.IsInitialized()) { QUIC_BUG(quic_bug_10752_32) - << "write_start_packet_number is not initialized"; + << ENDPOINT << "write_start_packet_number is not initialized"; return; } QUIC_SERVER_HISTOGRAM_COUNTS( @@ -1522,6 +1599,7 @@ void QuicPacketCreator::SetTransmissionType(TransmissionType type) { MessageStatus QuicPacketCreator::AddMessageFrame(QuicMessageId message_id, QuicMemSliceSpan message) { QUIC_BUG_IF(quic_bug_10752_33, !flusher_attached_) + << ENDPOINT << "Packet flusher is not attached when " "generator tries to add message frame."; MaybeBundleAckOpportunistically(); @@ -1535,7 +1613,8 @@ MessageStatus QuicPacketCreator::AddMessageFrame(QuicMessageId message_id, QuicMessageFrame* frame = new QuicMessageFrame(message_id, message); const bool success = AddFrame(QuicFrame(frame), next_transmission_type_); if (!success) { - QUIC_BUG(quic_bug_10752_34) << "Failed to send message " << message_id; + QUIC_BUG(quic_bug_10752_34) + << ENDPOINT << "Failed to send message " << message_id; delete frame; return MESSAGE_STATUS_INTERNAL_ERROR; } @@ -1564,7 +1643,8 @@ void QuicPacketCreator::FillPacketHeader(QuicPacketHeader* header) { header->reset_flag = false; header->version_flag = IncludeVersionInHeader(); if (IncludeNonceInPublicHeader()) { - QUICHE_DCHECK_EQ(Perspective::IS_SERVER, framer_->perspective()); + QUICHE_DCHECK_EQ(Perspective::IS_SERVER, framer_->perspective()) + << ENDPOINT; header->nonce = &diversification_nonce_; } else { header->nonce = nullptr; @@ -1640,7 +1720,8 @@ bool QuicPacketCreator::AddFrame(const QuicFrame& frame, frame.type != MESSAGE_FRAME && frame.type != NEW_TOKEN_FRAME && frame.type != RETIRE_CONNECTION_ID_FRAME && frame.type != ACK_FREQUENCY_FRAME)) - << frame.type << " not allowed at " << packet_.encryption_level; + << ENDPOINT << frame.type << " not allowed at " + << packet_.encryption_level; if (frame.type == STREAM_FRAME) { if (MaybeCoalesceStreamFrame(frame.stream_frame)) { @@ -1656,7 +1737,7 @@ bool QuicPacketCreator::AddFrame(const QuicFrame& frame, QUICHE_DCHECK(frame.type != ACK_FRAME || (!frame.ack_frame->packets.Empty() && frame.ack_frame->packets.Max() == frame.ack_frame->largest_acked)) - << "Invalid ACK frame: " << frame; + << ENDPOINT << "Invalid ACK frame: " << frame; size_t frame_len = GetSerializedFrameLength(frame); if (frame_len == 0 && RemoveSoftMaxPacketLength()) { @@ -1664,7 +1745,8 @@ bool QuicPacketCreator::AddFrame(const QuicFrame& frame, frame_len = GetSerializedFrameLength(frame); } if (frame_len == 0) { - QUIC_DVLOG(1) << "Flushing because current open packet is full when adding " + QUIC_DVLOG(1) << ENDPOINT + << "Flushing because current open packet is full when adding " << frame; FlushCurrentPacket(); return false; @@ -1672,7 +1754,7 @@ bool QuicPacketCreator::AddFrame(const QuicFrame& frame, if (queued_frames_.empty()) { packet_size_ = PacketHeaderSize(); } - QUICHE_DCHECK_LT(0u, packet_size_); + QUICHE_DCHECK_LT(0u, packet_size_) << ENDPOINT; packet_size_ += ExpansionOnNewFrame() + frame_len; @@ -1749,12 +1831,14 @@ bool QuicPacketCreator::MaybeCoalesceStreamFrame(const QuicStreamFrame& frame) { // The back of retransmittable frames must be the same as the original // queued frames' back. - QUICHE_DCHECK_EQ(packet_.retransmittable_frames.back().type, STREAM_FRAME); + QUICHE_DCHECK_EQ(packet_.retransmittable_frames.back().type, STREAM_FRAME) + << ENDPOINT; QuicStreamFrame* retransmittable = &packet_.retransmittable_frames.back().stream_frame; - QUICHE_DCHECK_EQ(retransmittable->stream_id, frame.stream_id); + QUICHE_DCHECK_EQ(retransmittable->stream_id, frame.stream_id) << ENDPOINT; QUICHE_DCHECK_EQ(retransmittable->offset + retransmittable->data_length, - frame.offset); + frame.offset) + << ENDPOINT; retransmittable->data_length = candidate->data_length; retransmittable->fin = candidate->fin; packet_size_ += frame.data_length; @@ -1771,7 +1855,7 @@ bool QuicPacketCreator::RemoveSoftMaxPacketLength() { if (!CanSetMaxPacketLength()) { return false; } - QUIC_DVLOG(1) << "Restoring max packet length to: " + QUIC_DVLOG(1) << ENDPOINT << "Restoring max packet length to: " << latched_hard_max_packet_length_; SetMaxPacketLength(latched_hard_max_packet_length_); // Reset latched_max_packet_length_. @@ -1814,7 +1898,7 @@ void QuicPacketCreator::MaybeAddPadding() { bool success = AddFrame(QuicFrame(QuicPaddingFrame(padding_bytes)), packet_.transmission_type); QUIC_BUG_IF(quic_bug_10752_36, !success) - << "Failed to add padding_bytes: " << padding_bytes + << ENDPOINT << "Failed to add padding_bytes: " << padding_bytes << " transmission_type: " << packet_.transmission_type; } @@ -1848,9 +1932,11 @@ bool QuicPacketCreator::StreamFrameIsClientHello( void QuicPacketCreator::SetServerConnectionIdIncluded( QuicConnectionIdIncluded server_connection_id_included) { QUICHE_DCHECK(server_connection_id_included == CONNECTION_ID_PRESENT || - server_connection_id_included == CONNECTION_ID_ABSENT); + server_connection_id_included == CONNECTION_ID_ABSENT) + << ENDPOINT; QUICHE_DCHECK(framer_->perspective() == Perspective::IS_SERVER || - server_connection_id_included != CONNECTION_ID_ABSENT); + server_connection_id_included != CONNECTION_ID_ABSENT) + << ENDPOINT; server_connection_id_included_ = server_connection_id_included; } @@ -1862,7 +1948,8 @@ void QuicPacketCreator::SetServerConnectionId( void QuicPacketCreator::SetClientConnectionId( QuicConnectionId client_connection_id) { QUICHE_DCHECK(client_connection_id.IsEmpty() || - framer_->version().SupportsClientConnectionIds()); + framer_->version().SupportsClientConnectionIds()) + << ENDPOINT; client_connection_id_ = client_connection_id; } @@ -1928,7 +2015,8 @@ QuicPacketLength QuicPacketCreator::GetGuaranteedLargestMessagePayload() const { const QuicPacketLength largest_payload = largest_frame - std::min(largest_frame, kQuicFrameTypeSize); // This must always be less than or equal to GetCurrentLargestMessagePayload. - QUICHE_DCHECK_LE(largest_payload, GetCurrentLargestMessagePayload()); + QUICHE_DCHECK_LE(largest_payload, GetCurrentLargestMessagePayload()) + << ENDPOINT; return largest_payload; } @@ -1940,7 +2028,7 @@ bool QuicPacketCreator::AttemptingToSendUnencryptedStreamData() { const std::string error_details = absl::StrCat("Cannot send stream data with level: ", EncryptionLevelToString(packet_.encryption_level)); - QUIC_BUG(quic_bug_10752_37) << error_details; + QUIC_BUG(quic_bug_10752_37) << ENDPOINT << error_details; delegate_->OnUnrecoverableError(QUIC_ATTEMPT_TO_SEND_UNENCRYPTED_STREAM_DATA, error_details); return true; @@ -2005,19 +2093,56 @@ void QuicPacketCreator::SetDefaultPeerAddress(QuicSocketAddress address) { } } +#define ENDPOINT2 \ + (creator_->framer_->perspective() == Perspective::IS_SERVER ? "Server: " \ + : "Client: ") + +QuicPacketCreator::ScopedPeerAddressContext::ScopedPeerAddressContext( + QuicPacketCreator* creator, + QuicSocketAddress address, + bool update_connection_id) + : ScopedPeerAddressContext(creator, + address, + EmptyQuicConnectionId(), + EmptyQuicConnectionId(), + update_connection_id) {} + QuicPacketCreator::ScopedPeerAddressContext::ScopedPeerAddressContext( QuicPacketCreator* creator, - QuicSocketAddress address) - : creator_(creator), old_peer_address_(creator_->packet_.peer_address) { - QUIC_BUG_IF(quic_bug_12398_19, - !creator_->packet_.peer_address.IsInitialized()) - << "Context is used before seralized packet's peer address is " + QuicSocketAddress address, + const QuicConnectionId& client_connection_id, + const QuicConnectionId& server_connection_id, + bool update_connection_id) + : creator_(creator), + old_peer_address_(creator_->packet_.peer_address), + old_client_connection_id_(creator_->GetClientConnectionId()), + old_server_connection_id_(creator_->GetServerConnectionId()), + update_connection_id_(update_connection_id) { + QUIC_BUG_IF(quic_bug_12398_19, !old_peer_address_.IsInitialized()) + << ENDPOINT2 + << "Context is used before serialized packet's peer address is " "initialized."; creator_->SetDefaultPeerAddress(address); + if (update_connection_id_) { + // Flush current packet if connection ID length changes. + if (address == old_peer_address_ && + ((client_connection_id.length() != + old_client_connection_id_.length()) || + (server_connection_id.length() != + old_server_connection_id_.length()))) { + creator_->FlushCurrentPacket(); + } + creator_->SetClientConnectionId(client_connection_id); + creator_->SetServerConnectionId(server_connection_id); + } } QuicPacketCreator::ScopedPeerAddressContext::~ScopedPeerAddressContext() { creator_->SetDefaultPeerAddress(old_peer_address_); + if (update_connection_id_) { + creator_->SetClientConnectionId(old_client_connection_id_); + creator_->SetServerConnectionId(old_server_connection_id_); + } } QuicPacketCreator::ScopedSerializationFailureHandler:: @@ -2034,16 +2159,19 @@ QuicPacketCreator::ScopedSerializationFailureHandler:: if (creator_->packet_.encrypted_buffer == nullptr) { const std::string error_details = "Failed to SerializePacket."; - QUIC_BUG(quic_bug_10752_38) << error_details; + QUIC_BUG(quic_bug_10752_38) << ENDPOINT2 << error_details; creator_->delegate_->OnUnrecoverableError(QUIC_FAILED_TO_SERIALIZE_PACKET, error_details); } } +#undef ENDPOINT2 + void QuicPacketCreator::set_encryption_level(EncryptionLevel level) { QUICHE_DCHECK(level == packet_.encryption_level || !HasPendingFrames()) - << "Cannot update encryption level from " << packet_.encryption_level - << " to " << level << " when we already have pending frames: " + << ENDPOINT << "Cannot update encryption level from " + << packet_.encryption_level << " to " << level + << " when we already have pending frames: " << QuicFramesToString(queued_frames_); packet_.encryption_level = level; } @@ -2054,6 +2182,7 @@ void QuicPacketCreator::AddPathChallengeFrame( // AddFrame(). Sort out test helper functions and peer class that don't // enforce this check. QUIC_BUG_IF(quic_bug_10752_39, !flusher_attached_) + << ENDPOINT << "Packet flusher is not attached when " "generator tries to write stream data."; // Write a PATH_CHALLENGE frame, which has a random 8-byte payload. @@ -2094,13 +2223,13 @@ bool QuicPacketCreator::AddPaddedFrameWithRetry(const QuicFrame& frame) { } } // Frame was not queued but queued frames were flushed. - QUICHE_DCHECK(!HasPendingFrames()); + QUICHE_DCHECK(!HasPendingFrames()) << ENDPOINT; if (!delegate_->ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA, NOT_HANDSHAKE)) { return false; } bool success = AddPaddedSavedFrame(frame, NOT_RETRANSMISSION); - QUIC_BUG_IF(quic_bug_12398_20, !success); + QUIC_BUG_IF(quic_bug_12398_20, !success) << ENDPOINT; return true; } 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 5e0c65e35fc..d4a58055282 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 @@ -22,13 +22,15 @@ #include "absl/base/attributes.h" #include "absl/strings/string_view.h" +#include "absl/types/optional.h" #include "quic/core/frames/quic_stream_frame.h" -#include "quic/core/quic_circular_deque.h" #include "quic/core/quic_coalesced_packet.h" +#include "quic/core/quic_connection_id.h" #include "quic/core/quic_framer.h" #include "quic/core/quic_packets.h" #include "quic/core/quic_types.h" #include "quic/platform/api/quic_export.h" +#include "common/quiche_circular_deque.h" namespace quic { namespace test { @@ -83,18 +85,28 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { virtual void OnStreamFrameCoalesced(const QuicStreamFrame& /*frame*/) {} }; - // Set the peer address which the serialized packet will be sent to during the - // scope of this object. Upon exiting the scope, the original peer address is - // restored. + // Set the peer address and connection IDs with which the serialized packet + // will be sent to during the scope of this object. Upon exiting the scope, + // the original peer address and connection IDs are restored. class QUIC_EXPORT_PRIVATE ScopedPeerAddressContext { public: ScopedPeerAddressContext(QuicPacketCreator* creator, - QuicSocketAddress address); + QuicSocketAddress address, + bool update_connection_id); + + ScopedPeerAddressContext(QuicPacketCreator* creator, + QuicSocketAddress address, + const QuicConnectionId& client_connection_id, + const QuicConnectionId& server_connection_id, + bool update_connection_id); ~ScopedPeerAddressContext(); private: QuicPacketCreator* creator_; QuicSocketAddress old_peer_address_; + QuicConnectionId old_client_connection_id_; + QuicConnectionId old_server_connection_id_; + bool update_connection_id_; }; QuicPacketCreator(QuicConnectionId server_connection_id, @@ -247,7 +259,7 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { // |payloads| is cleared. std::unique_ptr<SerializedPacket> SerializePathResponseConnectivityProbingPacket( - const QuicCircularDeque<QuicPathFrameBuffer>& payloads, + const quiche::QuicheCircularDeque<QuicPathFrameBuffer>& payloads, const bool is_padded); // Add PATH_RESPONSE to current packet, flush before or afterwards if needed. @@ -261,6 +273,16 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { // Returns a dummy packet that is valid but contains no useful information. static SerializedPacket NoPacket(); + // Returns the server connection ID to send over the wire. + const QuicConnectionId& GetServerConnectionId() const { + return server_connection_id_; + } + + // Returns the client connection ID to send over the wire. + const QuicConnectionId& GetClientConnectionId() const { + return client_connection_id_; + } + // Returns the destination connection ID to send over the wire. QuicConnectionId GetDestinationConnectionId() const; @@ -287,6 +309,11 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { void set_encryption_level(EncryptionLevel level); EncryptionLevel encryption_level() { return packet_.encryption_level; } + // Sets whether initial packets are protected with chaos. + void set_chaos_protection_enabled(bool chaos_protection_enabled) { + chaos_protection_enabled_ = chaos_protection_enabled; + } + // packet number of the last created packet, or 0 if no packets have been // created. QuicPacketNumber packet_number() const { return packet_.packet_number; } @@ -444,7 +471,7 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { const QuicPacketHeader& header, char* buffer, size_t packet_length, - const QuicCircularDeque<QuicPathFrameBuffer>& payloads, + const quiche::QuicheCircularDeque<QuicPathFrameBuffer>& payloads, const bool is_padded, EncryptionLevel level); @@ -487,6 +514,13 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { QuicPacketCreator* creator_; // Unowned. }; + // Attempts to build a data packet with chaos protection. If this packet isn't + // supposed to be protected or if serialization fails then absl::nullopt is + // returned. Otherwise returns the serialized length. + absl::optional<size_t> MaybeBuildDataPacketWithChaosProtection( + const QuicPacketHeader& header, + char* buffer); + // Creates a stream frame which fits into the current open packet. If // |data_size| is 0 and fin is true, the expected behavior is to consume // the fin. @@ -671,6 +705,9 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { // accept. There is no limit for QUIC_CRYPTO connections, but QUIC+TLS // negotiates this during the handshake. QuicByteCount max_datagram_frame_size_; + + // Whether to attempt protecting initial packets with chaos. + bool chaos_protection_enabled_; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator_test.cc index 5986bd2890f..57d1018d94c 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 @@ -19,6 +19,7 @@ #include "quic/core/crypto/quic_decrypter.h" #include "quic/core/crypto/quic_encrypter.h" #include "quic/core/frames/quic_stream_frame.h" +#include "quic/core/quic_connection_id.h" #include "quic/core/quic_data_writer.h" #include "quic/core/quic_simple_buffer_allocator.h" #include "quic/core/quic_types.h" @@ -34,13 +35,14 @@ #include "quic/test_tools/simple_quic_framer.h" #include "common/test_tools/quiche_test_utils.h" -using testing::_; -using testing::DoAll; -using testing::InSequence; -using testing::Invoke; -using testing::Return; -using testing::SaveArg; -using testing::StrictMock; +using ::testing::_; +using ::testing::AtLeast; +using ::testing::DoAll; +using ::testing::InSequence; +using ::testing::Invoke; +using ::testing::Return; +using ::testing::SaveArg; +using ::testing::StrictMock; namespace quic { namespace test { @@ -269,6 +271,8 @@ class QuicPacketCreatorTest : public QuicTestWithParam<TestParams> { n * 2; } + void TestChaosProtection(bool enabled); + static constexpr QuicStreamOffset kOffset = 0u; char buffer_[kMaxOutgoingPacketSize]; @@ -751,7 +755,7 @@ TEST_P(QuicPacketCreatorTest, BuildPathResponsePacket1ResponseUnpadded) { }; // clang-format on std::unique_ptr<char[]> buffer(new char[kMaxOutgoingPacketSize]); - QuicCircularDeque<QuicPathFrameBuffer> payloads; + quiche::QuicheCircularDeque<QuicPathFrameBuffer> payloads; payloads.push_back(payload0); size_t length = creator_.BuildPathResponsePacket( header, buffer.get(), ABSL_ARRAYSIZE(packet), payloads, @@ -798,7 +802,7 @@ TEST_P(QuicPacketCreatorTest, BuildPathResponsePacket1ResponsePadded) { }; // clang-format on std::unique_ptr<char[]> buffer(new char[kMaxOutgoingPacketSize]); - QuicCircularDeque<QuicPathFrameBuffer> payloads; + quiche::QuicheCircularDeque<QuicPathFrameBuffer> payloads; payloads.push_back(payload0); size_t length = creator_.BuildPathResponsePacket( header, buffer.get(), ABSL_ARRAYSIZE(packet), payloads, @@ -848,7 +852,7 @@ TEST_P(QuicPacketCreatorTest, BuildPathResponsePacket3ResponsesUnpadded) { // clang-format on std::unique_ptr<char[]> buffer(new char[kMaxOutgoingPacketSize]); - QuicCircularDeque<QuicPathFrameBuffer> payloads; + quiche::QuicheCircularDeque<QuicPathFrameBuffer> payloads; payloads.push_back(payload0); payloads.push_back(payload1); payloads.push_back(payload2); @@ -902,7 +906,7 @@ TEST_P(QuicPacketCreatorTest, BuildPathResponsePacket3ResponsesPadded) { // clang-format on std::unique_ptr<char[]> buffer(new char[kMaxOutgoingPacketSize]); - QuicCircularDeque<QuicPathFrameBuffer> payloads; + quiche::QuicheCircularDeque<QuicPathFrameBuffer> payloads; payloads.push_back(payload0); payloads.push_back(payload1); payloads.push_back(payload2); @@ -987,7 +991,7 @@ TEST_P(QuicPacketCreatorTest, SerializePathResponseProbePacket1PayloadPadded) { creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE); - QuicCircularDeque<QuicPathFrameBuffer> payloads; + quiche::QuicheCircularDeque<QuicPathFrameBuffer> payloads; payloads.push_back(payload0); std::unique_ptr<SerializedPacket> encrypted( @@ -1017,7 +1021,7 @@ TEST_P(QuicPacketCreatorTest, creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE); - QuicCircularDeque<QuicPathFrameBuffer> payloads; + quiche::QuicheCircularDeque<QuicPathFrameBuffer> payloads; payloads.push_back(payload0); std::unique_ptr<SerializedPacket> encrypted( @@ -1047,7 +1051,7 @@ TEST_P(QuicPacketCreatorTest, SerializePathResponseProbePacket2PayloadsPadded) { creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE); - QuicCircularDeque<QuicPathFrameBuffer> payloads; + quiche::QuicheCircularDeque<QuicPathFrameBuffer> payloads; payloads.push_back(payload0); payloads.push_back(payload1); @@ -1080,7 +1084,7 @@ TEST_P(QuicPacketCreatorTest, creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE); - QuicCircularDeque<QuicPathFrameBuffer> payloads; + quiche::QuicheCircularDeque<QuicPathFrameBuffer> payloads; payloads.push_back(payload0); payloads.push_back(payload1); @@ -1113,7 +1117,7 @@ TEST_P(QuicPacketCreatorTest, SerializePathResponseProbePacket3PayloadsPadded) { creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE); - QuicCircularDeque<QuicPathFrameBuffer> payloads; + quiche::QuicheCircularDeque<QuicPathFrameBuffer> payloads; payloads.push_back(payload0); payloads.push_back(payload1); payloads.push_back(payload2); @@ -1149,7 +1153,7 @@ TEST_P(QuicPacketCreatorTest, creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE); - QuicCircularDeque<QuicPathFrameBuffer> payloads; + quiche::QuicheCircularDeque<QuicPathFrameBuffer> payloads; payloads.push_back(payload0); payloads.push_back(payload1); payloads.push_back(payload2); @@ -1311,7 +1315,7 @@ TEST_P(QuicPacketCreatorTest, SerializeFrameShortData) { if (!GetParam().version_serialization) { creator_.StopSendingVersion(); } - std::string data("a"); + std::string data("Hello World!"); if (!QuicVersionUsesCryptoFrames(client_framer_.transport_version())) { QuicStreamFrame stream_frame( QuicUtils::GetCryptoStreamId(client_framer_.transport_version()), @@ -1338,15 +1342,51 @@ TEST_P(QuicPacketCreatorTest, SerializeFrameShortData) { } else { EXPECT_CALL(framer_visitor_, OnStreamFrame(_)); } - if (client_framer_.version().HasHeaderProtection()) { - EXPECT_CALL(framer_visitor_, OnPaddingFrame(_)); - } EXPECT_CALL(framer_visitor_, OnPacketComplete()); } ProcessPacket(serialized); EXPECT_EQ(GetParam().version_serialization, header.version_flag); } +void QuicPacketCreatorTest::TestChaosProtection(bool enabled) { + if (!GetParam().version.UsesCryptoFrames()) { + return; + } + MockRandom mock_random(2); + QuicPacketCreatorPeer::SetRandom(&creator_, &mock_random); + creator_.set_chaos_protection_enabled(enabled); + std::string data("ChAoS_ThEoRy!"); + producer_.SaveCryptoData(ENCRYPTION_INITIAL, 0, data); + frames_.push_back( + QuicFrame(new QuicCryptoFrame(ENCRYPTION_INITIAL, 0, data.length()))); + frames_.push_back(QuicFrame(QuicPaddingFrame(33))); + SerializedPacket serialized = SerializeAllFrames(frames_); + EXPECT_CALL(framer_visitor_, OnPacket()); + EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_)); + EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_)); + EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_, _)); + EXPECT_CALL(framer_visitor_, OnPacketHeader(_)); + if (enabled) { + EXPECT_CALL(framer_visitor_, OnCryptoFrame(_)).Times(AtLeast(2)); + EXPECT_CALL(framer_visitor_, OnPaddingFrame(_)).Times(AtLeast(2)); + EXPECT_CALL(framer_visitor_, OnPingFrame(_)).Times(AtLeast(1)); + } else { + EXPECT_CALL(framer_visitor_, OnCryptoFrame(_)).Times(1); + EXPECT_CALL(framer_visitor_, OnPaddingFrame(_)).Times(1); + EXPECT_CALL(framer_visitor_, OnPingFrame(_)).Times(0); + } + EXPECT_CALL(framer_visitor_, OnPacketComplete()); + ProcessPacket(serialized); +} + +TEST_P(QuicPacketCreatorTest, ChaosProtectionEnabled) { + TestChaosProtection(/*enabled=*/true); +} + +TEST_P(QuicPacketCreatorTest, ChaosProtectionDisabled) { + TestChaosProtection(/*enabled=*/false); +} + TEST_P(QuicPacketCreatorTest, ConsumeDataLargerThanOneStreamFrame) { if (!GetParam().version_serialization) { creator_.StopSendingVersion(); @@ -1954,17 +1994,7 @@ TEST_P(QuicPacketCreatorTest, RetryToken) { creator_.SetRetryToken( std::string(retry_token_bytes, sizeof(retry_token_bytes))); - std::string data("a"); - if (!QuicVersionUsesCryptoFrames(client_framer_.transport_version())) { - QuicStreamFrame stream_frame( - QuicUtils::GetCryptoStreamId(client_framer_.transport_version()), - /*fin=*/false, 0u, absl::string_view()); - frames_.push_back(QuicFrame(stream_frame)); - } else { - producer_.SaveCryptoData(ENCRYPTION_INITIAL, 0, data); - frames_.push_back( - QuicFrame(new QuicCryptoFrame(ENCRYPTION_INITIAL, 0, data.length()))); - } + frames_.push_back(QuicFrame(QuicPingFrame())); SerializedPacket serialized = SerializeAllFrames(frames_); QuicPacketHeader header; @@ -1976,11 +2006,7 @@ TEST_P(QuicPacketCreatorTest, RetryToken) { EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_, _)); EXPECT_CALL(framer_visitor_, OnPacketHeader(_)) .WillOnce(DoAll(SaveArg<0>(&header), Return(true))); - if (QuicVersionUsesCryptoFrames(client_framer_.transport_version())) { - EXPECT_CALL(framer_visitor_, OnCryptoFrame(_)); - } else { - EXPECT_CALL(framer_visitor_, OnStreamFrame(_)); - } + EXPECT_CALL(framer_visitor_, OnPingFrame(_)); if (client_framer_.version().HasHeaderProtection()) { EXPECT_CALL(framer_visitor_, OnPaddingFrame(_)); } @@ -2261,6 +2287,32 @@ TEST_P(QuicPacketCreatorTest, SoftMaxPacketLength) { EXPECT_TRUE(creator_.HasPendingFrames()); } +TEST_P(QuicPacketCreatorTest, + ChangingEncryptionLevelRemovesSoftMaxPacketLength) { + if (!client_framer_.version().CanSendCoalescedPackets()) { + return; + } + // First set encryption level to forward secure which has the shortest header. + creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE); + const QuicByteCount previous_max_packet_length = creator_.max_packet_length(); + const size_t min_acceptable_packet_size = + GetPacketHeaderOverhead(client_framer_.transport_version()) + + QuicPacketCreator::MinPlaintextPacketSize(client_framer_.version()) + + GetEncryptionOverhead(); + // Then set the soft max packet length to the lowest allowed value. + creator_.SetSoftMaxPacketLength(min_acceptable_packet_size); + // Make sure that the low value was accepted. + EXPECT_EQ(creator_.max_packet_length(), min_acceptable_packet_size); + // Now set the encryption level to handshake which increases the header size. + creator_.set_encryption_level(ENCRYPTION_HANDSHAKE); + // Make sure that adding a frame removes the the soft max packet length. + QuicAckFrame ack_frame(InitAckFrame(1)); + frames_.push_back(QuicFrame(&ack_frame)); + SerializedPacket serialized = SerializeAllFrames(frames_); + EXPECT_EQ(serialized.encryption_level, ENCRYPTION_HANDSHAKE); + EXPECT_EQ(creator_.max_packet_length(), previous_max_packet_length); +} + class MockDelegate : public QuicPacketCreator::DelegateInterface { public: MockDelegate() {} @@ -3811,8 +3863,12 @@ TEST_F(QuicPacketCreatorMultiplePacketsTest, ExtraPaddingNeeded) { TEST_F(QuicPacketCreatorMultiplePacketsTest, PeerAddressContextWithSameAddress) { + QuicConnectionId client_connection_id = TestConnectionId(1); + QuicConnectionId server_connection_id = TestConnectionId(2); QuicSocketAddress peer_addr(QuicIpAddress::Any4(), 12345); creator_.SetDefaultPeerAddress(peer_addr); + creator_.SetClientConnectionId(client_connection_id); + creator_.SetServerConnectionId(server_connection_id); // Send some stream data. MakeIOVector("foo", &iov_); EXPECT_CALL(delegate_, ShouldGeneratePacket(_, _)) @@ -3824,8 +3880,12 @@ TEST_F(QuicPacketCreatorMultiplePacketsTest, EXPECT_EQ(3u, consumed.bytes_consumed); EXPECT_TRUE(creator_.HasPendingFrames()); { - // Set a different address via context which should trigger flush. - QuicPacketCreator::ScopedPeerAddressContext context(&creator_, peer_addr); + // Set the same address via context which should not trigger flush. + QuicPacketCreator::ScopedPeerAddressContext context( + &creator_, peer_addr, client_connection_id, server_connection_id, + /*update_connection_id=*/true); + ASSERT_EQ(client_connection_id, creator_.GetClientConnectionId()); + ASSERT_EQ(server_connection_id, creator_.GetServerConnectionId()); EXPECT_TRUE(creator_.HasPendingFrames()); // Queue another STREAM_FRAME. QuicConsumedData consumed = creator_.ConsumeData( @@ -3874,8 +3934,14 @@ TEST_F(QuicPacketCreatorMultiplePacketsTest, })); EXPECT_TRUE(creator_.HasPendingFrames()); { + QuicConnectionId client_connection_id = TestConnectionId(1); + QuicConnectionId server_connection_id = TestConnectionId(2); // Set a different address via context which should trigger flush. - QuicPacketCreator::ScopedPeerAddressContext context(&creator_, peer_addr1); + QuicPacketCreator::ScopedPeerAddressContext context( + &creator_, peer_addr1, client_connection_id, server_connection_id, + /*update_connection_id=*/true); + ASSERT_EQ(client_connection_id, creator_.GetClientConnectionId()); + ASSERT_EQ(server_connection_id, creator_.GetServerConnectionId()); EXPECT_FALSE(creator_.HasPendingFrames()); // Queue another STREAM_FRAME. QuicConsumedData consumed = creator_.ConsumeData( @@ -3891,9 +3957,15 @@ TEST_F(QuicPacketCreatorMultiplePacketsTest, TEST_F(QuicPacketCreatorMultiplePacketsTest, NestedPeerAddressContextWithDifferentAddress) { + QuicConnectionId client_connection_id1 = creator_.GetClientConnectionId(); + QuicConnectionId server_connection_id1 = creator_.GetServerConnectionId(); QuicSocketAddress peer_addr(QuicIpAddress::Any4(), 12345); creator_.SetDefaultPeerAddress(peer_addr); - QuicPacketCreator::ScopedPeerAddressContext context(&creator_, peer_addr); + QuicPacketCreator::ScopedPeerAddressContext context( + &creator_, peer_addr, client_connection_id1, server_connection_id1, + /*update_connection_id=*/true); + ASSERT_EQ(client_connection_id1, creator_.GetClientConnectionId()); + ASSERT_EQ(server_connection_id1, creator_.GetServerConnectionId()); // Send some stream data. MakeIOVector("foo", &iov_); @@ -3913,9 +3985,14 @@ TEST_F(QuicPacketCreatorMultiplePacketsTest, ASSERT_EQ(1u, packet.retransmittable_frames.size()); EXPECT_EQ(STREAM_FRAME, packet.retransmittable_frames.front().type); + QuicConnectionId client_connection_id2 = TestConnectionId(3); + QuicConnectionId server_connection_id2 = TestConnectionId(4); // Set up another context with a different address. - QuicPacketCreator::ScopedPeerAddressContext context(&creator_, - peer_addr1); + QuicPacketCreator::ScopedPeerAddressContext context( + &creator_, peer_addr1, client_connection_id2, server_connection_id2, + /*update_connection_id=*/true); + ASSERT_EQ(client_connection_id2, creator_.GetClientConnectionId()); + ASSERT_EQ(server_connection_id2, creator_.GetServerConnectionId()); MakeIOVector("foo", &iov_); EXPECT_CALL(delegate_, ShouldGeneratePacket(_, _)) .WillRepeatedly(Return(true)); 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 5cc593f41bf..d625b5dcb6a 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 @@ -15,7 +15,6 @@ #include "quic/core/quic_versions.h" #include "quic/platform/api/quic_flag_utils.h" #include "quic/platform/api/quic_flags.h" -#include "common/platform/api/quiche_text_utils.h" namespace quic { diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_protocol_flags_list.h b/chromium/net/third_party/quiche/src/quic/core/quic_protocol_flags_list.h index 5187c61def4..56f83594b8f 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_protocol_flags_list.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_protocol_flags_list.h @@ -249,4 +249,11 @@ QUIC_PROTOCOL_FLAG( true, "If true, QUIC QPACK decoder includes 32-bytes overheader per entry while " "comparing request/response header size against its upper limit.") + +QUIC_PROTOCOL_FLAG( + bool, + quic_reject_retry_token_in_initial_packet, + false, + "If true, always reject retry_token received in INITIAL packets") + #endif 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 a1b78a4fb86..079778cd5d8 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 @@ -205,11 +205,7 @@ QuicTime::Delta QuicReceivedPacketManager::GetMaxAckDelay( // before sending an ack. QuicTime::Delta ack_delay = std::min( local_max_ack_delay_, rtt_stats.min_rtt() * ack_decimation_delay_); - if (GetQuicReloadableFlag(quic_ack_delay_alarm_granularity)) { - QUIC_RELOADABLE_FLAG_COUNT(quic_ack_delay_alarm_granularity); - ack_delay = std::max(ack_delay, kAlarmGranularity); - } - return ack_delay; + return std::max(ack_delay, kAlarmGranularity); } void QuicReceivedPacketManager::MaybeUpdateAckFrequency( 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 3cfa0ce0a43..da586c67a3d 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 @@ -397,9 +397,6 @@ TEST_F(QuicReceivedPacketManagerTest, SendDelayedAckDecimation) { } TEST_F(QuicReceivedPacketManagerTest, SendDelayedAckDecimationMin1ms) { - if (!GetQuicReloadableFlag(quic_ack_delay_alarm_granularity)) { - return; - } EXPECT_FALSE(HasPendingAck()); // Seed the min_rtt with a kAlarmGranularity signal. rtt_stats_.UpdateRtt(kAlarmGranularity, QuicTime::Delta::Zero(), 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 13e2396fd86..781f6f95b90 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h @@ -19,7 +19,6 @@ #include "quic/core/congestion_control/send_algorithm_interface.h" #include "quic/core/congestion_control/uber_loss_algorithm.h" #include "quic/core/proto/cached_network_parameters_proto.h" -#include "quic/core/quic_circular_deque.h" #include "quic/core/quic_packets.h" #include "quic/core/quic_sustained_bandwidth_recorder.h" #include "quic/core/quic_time.h" @@ -28,6 +27,7 @@ #include "quic/core/quic_unacked_packet_map.h" #include "quic/platform/api/quic_containers.h" #include "quic/platform/api/quic_export.h" +#include "common/quiche_circular_deque.h" namespace quic { @@ -673,7 +673,8 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { // The history of outstanding max_ack_delays sent to peer. Outstanding means // a max_ack_delay is sent as part of the last acked AckFrequencyFrame or // an unacked AckFrequencyFrame after that. - QuicCircularDeque<std::pair<QuicTime::Delta, /*sequence_number=*/uint64_t>> + quiche::QuicheCircularDeque< + std::pair<QuicTime::Delta, /*sequence_number=*/uint64_t>> in_use_sent_ack_delays_; // Latest received ack frame. 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 7c7aa4d077f..1bcb9dcb7bd 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 @@ -25,7 +25,7 @@ #include "quic/platform/api/quic_map_util.h" #include "quic/platform/api/quic_server_stats.h" #include "quic/platform/api/quic_stack_trace.h" -#include "common/platform/api/quiche_text_utils.h" +#include "common/quiche_text_utils.h" using spdy::SpdyPriority; @@ -686,11 +686,8 @@ bool QuicSession::WillingAndAbleToWrite() const { if (HasPendingHandshake()) { return true; } - if (GetQuicReloadableFlag(quic_fix_willing_and_able_to_write2)) { - QUIC_RELOADABLE_FLAG_COUNT(quic_fix_willing_and_able_to_write2); - if (!IsEncryptionEstablished()) { - return false; - } + if (!IsEncryptionEstablished()) { + return false; } } if (control_frame_manager_.WillingToWrite() || @@ -773,10 +770,24 @@ QuicConsumedData QuicSession::WritevData( perspective() == Perspective::IS_CLIENT); QUIC_BUG_IF(quic_bug_12435_3, type == NOT_RETRANSMISSION) << ENDPOINT << "Try to send new data on stream " << id - << "before 1-RTT keys are available while 0-RTT is rejected."; + << "before 1-RTT keys are available while 0-RTT is rejected. " + "Version: " + << ParsedQuicVersionToString(version()); + } else if (version().UsesTls() || perspective() == Perspective::IS_SERVER) { + QUIC_BUG(quic_bug_10866_2) + << ENDPOINT << "Try to send data of stream " << id + << " before encryption is established. Version: " + << ParsedQuicVersionToString(version()); } else { - QUIC_BUG(quic_bug_10866_2) << ENDPOINT << "Try to send data of stream " - << id << " before encryption is established."; + // In QUIC crypto, this could happen when the client sends full CHLO and + // 0-RTT request, then receives an inchoate REJ and sends an inchoate + // CHLO. The client then gets the ACK of the inchoate CHLO or the client + // gets the full REJ and needs to verify the proof (before it sends the + // full CHLO), such that there is no outstanding crypto data. + // Retransmission alarm fires in TLP mode which tries to retransmit the + // 0-RTT request (without encryption). + QUIC_DLOG(INFO) << ENDPOINT << "Try to send data of stream " << id + << " before encryption is established."; } return QuicConsumedData(0, false); } @@ -920,15 +931,12 @@ void QuicSession::SendGoAway(QuicErrorCode error_code, const std::string& reason) { // GOAWAY frame is not supported in IETF QUIC. QUICHE_DCHECK(!VersionHasIetfQuicFrames(transport_version())); - if (GetQuicReloadableFlag(quic_encrypted_goaway)) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_encrypted_goaway, 1, 2); - if (!IsEncryptionEstablished()) { - QUIC_CODE_COUNT(quic_goaway_before_encryption_established); - connection_->CloseConnection( - error_code, reason, - ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); - return; - } + if (!IsEncryptionEstablished()) { + QUIC_CODE_COUNT(quic_goaway_before_encryption_established); + connection_->CloseConnection( + error_code, reason, + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + return; } if (transport_goaway_sent_) { return; @@ -1666,10 +1674,7 @@ void QuicSession::OnTlsHandshakeComplete() { // Server sends HANDSHAKE_DONE to signal confirmation of the handshake // to the client. control_frame_manager_.WriteOrBufferHandshakeDone(); - if (GetQuicReloadableFlag(quic_enable_token_based_address_validation) && - connection()->version().HasIetfQuicFrames()) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_token_based_address_validation, - 1, 2); + if (connection()->version().HasIetfQuicFrames()) { MaybeSendAddressToken(); } } @@ -1775,6 +1780,11 @@ void QuicSession::OnHandshakeCallbackDone() { } } +bool QuicSession::PacketFlusherAttached() const { + QUICHE_DCHECK(connection_->connected()); + return connection()->packet_creator().PacketFlusherAttached(); +} + void QuicSession::OnCryptoHandshakeMessageSent( const CryptoHandshakeMessage& /*message*/) {} @@ -2096,12 +2106,14 @@ void QuicSession::SendAckFrequency(const QuicAckFrequencyFrame& frame) { } void QuicSession::SendNewConnectionId(const QuicNewConnectionIdFrame& frame) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_connection_migration_use_new_cid_v2, 1, 5); control_frame_manager_.WriteOrBufferNewConnectionId( frame.connection_id, frame.sequence_number, frame.retire_prior_to, frame.stateless_reset_token); } void QuicSession::SendRetireConnectionId(uint64_t sequence_number) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_connection_migration_use_new_cid_v2, 2, 5); control_frame_manager_.WriteOrBufferRetireConnectionId(sequence_number); } @@ -2495,11 +2507,6 @@ QuicPacketLength QuicSession::GetGuaranteedLargestMessagePayload() const { return connection_->GetGuaranteedLargestMessagePayload(); } -void QuicSession::SendStopSending(QuicRstStreamErrorCode code, - QuicStreamId stream_id) { - control_frame_manager_.WriteOrBufferStopSending(code, stream_id); -} - QuicStreamId QuicSession::next_outgoing_bidirectional_stream_id() const { if (VersionHasIetfQuicFrames(transport_version())) { return ietf_streamid_manager_.next_outgoing_bidirectional_stream_id(); @@ -2609,15 +2616,19 @@ bool QuicSession::HasPendingPathValidation() const { return connection_->HasPendingPathValidation(); } -void QuicSession::MigratePath(const QuicSocketAddress& self_address, +bool QuicSession::MigratePath(const QuicSocketAddress& self_address, const QuicSocketAddress& peer_address, QuicPacketWriter* writer, bool owns_writer) { - connection_->MigratePath(self_address, peer_address, writer, owns_writer); + return connection_->MigratePath(self_address, peer_address, writer, + owns_writer); } bool QuicSession::ValidateToken(absl::string_view token) const { QUICHE_DCHECK_EQ(perspective_, Perspective::IS_SERVER); + if (GetQuicFlag(FLAGS_quic_reject_retry_token_in_initial_packet)) { + return false; + } if (token.empty() || token[0] != 0) { // Validate the prefix for token received in NEW_TOKEN frame. return false; 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 cf366cf5654..b6c1367019f 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 @@ -264,10 +264,6 @@ class QUIC_EXPORT_PRIVATE QuicSession // Sends a WINDOW_UPDATE frame. virtual void SendWindowUpdate(QuicStreamId id, QuicStreamOffset byte_offset); - // Create and transmit a STOP_SENDING frame - virtual void SendStopSending(QuicRstStreamErrorCode code, - QuicStreamId stream_id); - // Called by stream |stream_id| when it gets closed. virtual void OnStreamClosed(QuicStreamId stream_id); @@ -306,6 +302,7 @@ class QUIC_EXPORT_PRIVATE QuicSession bool is_resumption, std::string* error_details) override; void OnHandshakeCallbackDone() override; + bool PacketFlusherAttached() const override; // Implement StreamDelegateInterface. void OnStreamError(QuicErrorCode error_code, @@ -458,7 +455,7 @@ class QUIC_EXPORT_PRIVATE QuicSession bool HasPendingPathValidation() const; // Switch to the path described in |context| without validating the path. - void MigratePath(const QuicSocketAddress& self_address, + bool MigratePath(const QuicSocketAddress& self_address, const QuicSocketAddress& peer_address, QuicPacketWriter* writer, bool owns_writer); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream_send_buffer.h b/chromium/net/third_party/quiche/src/quic/core/quic_stream_send_buffer.h index cb6e3aa943c..4b23d3d82cd 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_stream_send_buffer.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream_send_buffer.h @@ -6,13 +6,13 @@ #define QUICHE_QUIC_CORE_QUIC_STREAM_SEND_BUFFER_H_ #include "quic/core/frames/quic_stream_frame.h" -#include "quic/core/quic_circular_deque.h" #include "quic/core/quic_interval_deque.h" #include "quic/core/quic_interval_set.h" #include "quic/core/quic_types.h" #include "quic/platform/api/quic_iovec.h" #include "quic/platform/api/quic_mem_slice.h" #include "quic/platform/api/quic_mem_slice_span.h" +#include "common/quiche_circular_deque.h" namespace quic { 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 cf7340bdb65..88a51bd5e08 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 @@ -56,13 +56,10 @@ void QuicStreamSequencer::OnStreamFrame(const QuicStreamFrame& frame) { (!CloseStreamAtOffset(frame.offset + data_len) || data_len == 0)) { return; } - if (GetQuicReloadableFlag(quic_accept_empty_stream_frame_with_no_fin)) { - QUIC_RELOADABLE_FLAG_COUNT(quic_accept_empty_stream_frame_with_no_fin); - if (stream_->version().HasIetfQuicFrames() && data_len == 0) { - QUICHE_DCHECK(!frame.fin); - // Ignore empty frame with no fin. - return; - } + if (stream_->version().HasIetfQuicFrames() && data_len == 0) { + QUICHE_DCHECK(!frame.fin); + // Ignore empty frame with no fin. + return; } OnFrameData(byte_offset, data_len, frame.data_buffer); } 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 e8fe6f367e2..b097bc5bc93 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 @@ -252,8 +252,7 @@ TEST_F(QuicStreamSequencerTest, BlockedThenFullFrameAndFinConsumed) { } TEST_F(QuicStreamSequencerTest, EmptyFrame) { - if (!GetQuicReloadableFlag(quic_accept_empty_stream_frame_with_no_fin) || - !stream_.version().HasIetfQuicFrames()) { + if (!stream_.version().HasIetfQuicFrames()) { EXPECT_CALL(stream_, OnUnrecoverableError(QUIC_EMPTY_STREAM_FRAME_NO_FIN, _)); } 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 739113a9147..2d3298b6fc9 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 @@ -1634,8 +1634,7 @@ TEST_P(QuicStreamTest, RstStreamFrameChangesCloseOffset) { TEST_P(QuicStreamTest, EmptyStreamFrameWithNoFin) { Initialize(); QuicStreamFrame empty_stream_frame(stream_->id(), false, 0, ""); - if (GetQuicReloadableFlag(quic_accept_empty_stream_frame_with_no_fin) && - stream_->version().HasIetfQuicFrames()) { + if (stream_->version().HasIetfQuicFrames()) { EXPECT_CALL(*connection_, CloseConnection(QUIC_EMPTY_STREAM_FRAME_NO_FIN, _, _)) .Times(0); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_tag.cc b/chromium/net/third_party/quiche/src/quic/core/quic_tag.cc index a6305b086f3..32b7bf9cd76 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_tag.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_tag.cc @@ -12,7 +12,7 @@ #include "absl/strings/str_split.h" #include "quic/platform/api/quic_flag_utils.h" #include "quic/platform/api/quic_flags.h" -#include "common/platform/api/quiche_text_utils.h" +#include "common/quiche_text_utils.h" namespace quic { 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 d6fa2da7a10..dbaa38bdefe 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 @@ -18,12 +18,13 @@ #include "quic/core/quic_framer.h" #include "quic/core/quic_packets.h" #include "quic/core/quic_utils.h" +#include "quic/platform/api/quic_bug_tracker.h" #include "quic/platform/api/quic_flag_utils.h" #include "quic/platform/api/quic_flags.h" #include "quic/platform/api/quic_logging.h" #include "quic/platform/api/quic_map_util.h" #include "quic/platform/api/quic_socket_address.h" -#include "common/platform/api/quiche_text_utils.h" +#include "common/quiche_text_utils.h" namespace quic { @@ -324,6 +325,13 @@ void QuicTimeWaitListManager::SendPublicReset( if (ietf_quic) { std::unique_ptr<QuicEncryptedPacket> ietf_reset_packet = BuildIetfStatelessResetPacket(connection_id, received_packet_length); + if (GetQuicRestartFlag(quic_fix_stateless_reset2) && + ietf_reset_packet == nullptr) { + // This could happen when trying to reject a short header packet of + // a connection which is in the time wait list (and with no termination + // packet). + return; + } QUIC_DVLOG(2) << "Dispatcher sending IETF reset packet for " << connection_id << std::endl << quiche::QuicheTextUtils::HexDump( @@ -381,6 +389,10 @@ QuicTimeWaitListManager::BuildIetfStatelessResetPacket( bool QuicTimeWaitListManager::SendOrQueuePacket( std::unique_ptr<QueuedPacket> packet, const QuicPerPacketContext* /*packet_context*/) { + if (packet == nullptr) { + QUIC_LOG(ERROR) << "Tried to send or queue a null packet"; + return true; + } if (WriteToWire(packet.get())) { // Allow the packet to be deleted upon leaving this function. return true; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.h b/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.h index 2018f723306..ac371f2c180 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 @@ -224,7 +224,7 @@ class QUIC_NO_EXPORT QuicTimeWaitListManager virtual bool SendOrQueuePacket(std::unique_ptr<QueuedPacket> packet, const QuicPerPacketContext* packet_context); - const QuicCircularDeque<std::unique_ptr<QueuedPacket>>& + const quiche::QuicheCircularDeque<std::unique_ptr<QueuedPacket>>& pending_packets_queue() const { return pending_packets_queue_; } @@ -318,7 +318,8 @@ class QUIC_NO_EXPORT QuicTimeWaitListManager // Pending termination packets that need to be sent out to the peer when we // are given a chance to write by the dispatcher. - QuicCircularDeque<std::unique_ptr<QueuedPacket>> pending_packets_queue_; + quiche::QuicheCircularDeque<std::unique_ptr<QueuedPacket>> + pending_packets_queue_; // Time period for which connection_ids should remain in time wait state. const QuicTime::Delta time_wait_period_; 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 d33e992e372..4e9f957182b 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 @@ -19,6 +19,7 @@ #include "quic/core/quic_packet_writer.h" #include "quic/core/quic_packets.h" #include "quic/core/quic_utils.h" +#include "quic/platform/api/quic_expect_bug.h" #include "quic/platform/api/quic_flags.h" #include "quic/platform/api/quic_test.h" #include "quic/test_tools/mock_quic_session_visitor.h" @@ -749,6 +750,24 @@ TEST_F(QuicTimeWaitListManagerTest, } } +// Regression test for b/184053898. +TEST_F(QuicTimeWaitListManagerTest, DonotCrashOnNullStatelessReset) { + // Received a packet with length < + // QuicFramer::GetMinStatelessResetPacketLength(), and this will result in a + // null stateless reset. + time_wait_list_manager_.SendPublicReset( + self_address_, peer_address_, TestConnectionId(1), + /*ietf_quic=*/true, + /*received_packet_length=*/ + QuicFramer::GetMinStatelessResetPacketLength() - 1, + /*packet_context=*/nullptr); +} + +TEST_F(QuicTimeWaitListManagerTest, SendOrQueueNullPacket) { + QuicTimeWaitListManagerPeer::SendOrQueuePacket(&time_wait_list_manager_, + nullptr, nullptr); +} + } // namespace } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map.h b/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map.h index 75c835d6c49..676f054b1fb 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map.h @@ -7,15 +7,14 @@ #include <cstddef> #include <cstdint> -#include <deque> #include "absl/strings/str_cat.h" -#include "quic/core/quic_circular_deque.h" #include "quic/core/quic_packets.h" #include "quic/core/quic_transmission_info.h" #include "quic/core/session_notifier_interface.h" #include "quic/platform/api/quic_export.h" #include "quic/platform/api/quic_flags.h" +#include "common/quiche_circular_deque.h" namespace quic { @@ -113,10 +112,10 @@ class QUIC_EXPORT_PRIVATE QuicUnackedPacketMap { QuicPacketNumber GetLeastUnacked() const; using const_iterator = - QuicCircularDeque<QuicTransmissionInfo>::const_iterator; + quiche::QuicheCircularDeque<QuicTransmissionInfo>::const_iterator; using const_reverse_iterator = - QuicCircularDeque<QuicTransmissionInfo>::const_reverse_iterator; - using iterator = QuicCircularDeque<QuicTransmissionInfo>::iterator; + quiche::QuicheCircularDeque<QuicTransmissionInfo>::const_reverse_iterator; + using iterator = quiche::QuicheCircularDeque<QuicTransmissionInfo>::iterator; const_iterator begin() const { return unacked_packets_.begin(); } const_iterator end() const { return unacked_packets_.end(); } @@ -300,7 +299,7 @@ class QUIC_EXPORT_PRIVATE QuicUnackedPacketMap { // If the old packet is acked before the new packet, then the old entry will // be removed from the map and the new entry's retransmittable frames will be // set to nullptr. - QuicCircularDeque<QuicTransmissionInfo> unacked_packets_; + quiche::QuicheCircularDeque<QuicTransmissionInfo> unacked_packets_; // The packet at the 0th index of unacked_packets_. QuicPacketNumber least_unacked_; 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 27b74bb9430..1f0137a91bc 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 @@ -21,8 +21,8 @@ #include "quic/platform/api/quic_bug_tracker.h" #include "quic/platform/api/quic_flag_utils.h" #include "quic/platform/api/quic_flags.h" -#include "quic/platform/api/quic_prefetch.h" #include "common/platform/api/quiche_logging.h" +#include "common/platform/api/quiche_prefetch.h" #include "common/quiche_endian.h" namespace quic { @@ -266,9 +266,9 @@ void QuicUtils::CopyToBuffer(const struct iovec* iov, char* next_base = static_cast<char*>(iov[iovnum + 1].iov_base); // Prefetch 2 cachelines worth of data to get the prefetcher started; leave // it to the hardware prefetcher after that. - QuicPrefetchT0(next_base); + quiche::QuichePrefetchT0(next_base); if (iov[iovnum + 1].iov_len >= 64) { - QuicPrefetchT0(next_base + ABSL_CACHELINE_SIZE); + quiche::QuichePrefetchT0(next_base + ABSL_CACHELINE_SIZE); } } @@ -308,7 +308,6 @@ bool QuicUtils::IsRetransmittableFrame(QuicFrameType type) { case MTU_DISCOVERY_FRAME: case PATH_CHALLENGE_FRAME: case PATH_RESPONSE_FRAME: - case NEW_CONNECTION_ID_FRAME: return false; default: return true; 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 ab68ddd57d1..ba2ec7ee29e 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 @@ -17,8 +17,8 @@ #include "quic/platform/api/quic_flag_utils.h" #include "quic/platform/api/quic_flags.h" #include "quic/platform/api/quic_logging.h" -#include "common/platform/api/quiche_text_utils.h" #include "common/quiche_endian.h" +#include "common/quiche_text_utils.h" namespace quic { namespace { @@ -599,7 +599,6 @@ std::string AlpnForVersion(ParsedQuicVersion parsed_version) { void QuicVersionInitializeSupportForIetfDraft() { // Enable necessary flags. - SetQuicReloadableFlag(quic_fix_key_update_on_first_packet, true); } void QuicEnableVersion(const ParsedQuicVersion& version) { 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 3379fcb39df..dbc2ca9173d 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,13 +9,13 @@ #include <cstdint> #include <utility> +#include "http2/core/priority_write_scheduler.h" #include "quic/core/quic_packets.h" #include "quic/platform/api/quic_bug_tracker.h" #include "quic/platform/api/quic_containers.h" #include "quic/platform/api/quic_export.h" #include "quic/platform/api/quic_flags.h" #include "quic/platform/api/quic_map_util.h" -#include "spdy/core/priority_write_scheduler.h" namespace quic { @@ -78,7 +78,7 @@ class QUIC_EXPORT_PRIVATE QuicWriteBlockedList { bool IsStreamBlocked(QuicStreamId stream_id) const; private: - spdy::PriorityWriteScheduler<QuicStreamId> priority_write_scheduler_; + http2::PriorityWriteScheduler<QuicStreamId> 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 diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_chlo_extractor.cc b/chromium/net/third_party/quiche/src/quic/core/tls_chlo_extractor.cc index ae85b07c251..ac1fb180f54 100644 --- a/chromium/net/third_party/quiche/src/quic/core/tls_chlo_extractor.cc +++ b/chromium/net/third_party/quiche/src/quic/core/tls_chlo_extractor.cc @@ -17,7 +17,6 @@ #include "quic/core/quic_types.h" #include "quic/core/quic_versions.h" #include "quic/platform/api/quic_bug_tracker.h" -#include "common/platform/api/quiche_text_utils.h" 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 f8e321663ca..1b9de030860 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 @@ -17,7 +17,7 @@ #include "quic/core/quic_types.h" #include "quic/platform/api/quic_flags.h" #include "quic/platform/api/quic_hostname_utils.h" -#include "common/platform/api/quiche_text_utils.h" +#include "common/quiche_text_utils.h" namespace quic { @@ -42,12 +42,10 @@ TlsClientHandshaker::TlsClientHandshaker( has_application_state_(has_application_state), crypto_config_(crypto_config), tls_connection_(crypto_config->ssl_ctx(), this) { - if (GetQuicReloadableFlag(quic_enable_token_based_address_validation)) { - std::string token = - crypto_config->LookupOrCreate(server_id)->source_address_token(); - if (!token.empty()) { - session->SetSourceAddressTokenToSend(token); - } + std::string token = + crypto_config->LookupOrCreate(server_id)->source_address_token(); + if (!token.empty()) { + session->SetSourceAddressTokenToSend(token); } } @@ -179,18 +177,16 @@ bool TlsClientHandshaker::SetAlpn() { } // Enable ALPS only for versions that use HTTP/3 frames. - if (enable_alps_) { - for (const std::string& alpn_string : alpns) { - ParsedQuicVersion version = ParseQuicVersionString(alpn_string); - if (!version.IsKnown() || !version.UsesHttp3()) { - continue; - } - if (SSL_add_application_settings( - ssl(), reinterpret_cast<const uint8_t*>(alpn_string.data()), - alpn_string.size(), nullptr, /* settings_len = */ 0) != 1) { - QUIC_BUG(quic_bug_10576_7) << "Failed to enable ALPS."; - return false; - } + for (const std::string& alpn_string : alpns) { + ParsedQuicVersion version = ParseQuicVersionString(alpn_string); + if (!version.IsKnown() || !version.UsesHttp3()) { + continue; + } + if (SSL_add_application_settings( + ssl(), reinterpret_cast<const uint8_t*>(alpn_string.data()), + alpn_string.size(), nullptr, /* settings_len = */ 0) != 1) { + QUIC_BUG(quic_bug_10576_7) << "Failed to enable ALPS."; + return false; } } @@ -502,20 +498,18 @@ void TlsClientHandshaker::FinishHandshake() { << "'"; // Parse ALPS extension. - if (enable_alps_) { - const uint8_t* alps_data; - size_t alps_length; - SSL_get0_peer_application_settings(ssl(), &alps_data, &alps_length); - if (alps_length > 0) { - auto error = session()->OnAlpsData(alps_data, alps_length); - if (error) { - // Calling CloseConnection() is safe even in case OnAlpsData() has - // already closed the connection. - CloseConnection( - QUIC_HANDSHAKE_FAILED, - absl::StrCat("Error processing ALPS data: ", error.value())); - return; - } + const uint8_t* alps_data; + size_t alps_length; + SSL_get0_peer_application_settings(ssl(), &alps_data, &alps_length); + if (alps_length > 0) { + auto error = session()->OnAlpsData(alps_data, alps_length); + if (error) { + // Calling CloseConnection() is safe even in case OnAlpsData() has + // already closed the connection. + CloseConnection( + QUIC_HANDSHAKE_FAILED, + absl::StrCat("Error processing ALPS data: ", error.value())); + return; } } 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 8fb6da69d2c..eb39ccf9fab 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 @@ -168,9 +168,6 @@ class QUIC_EXPORT_PRIVATE TlsClientHandshaker std::unique_ptr<TransportParameters> received_transport_params_ = nullptr; std::unique_ptr<ApplicationState> received_application_state_ = nullptr; - - // Latched value of reloadable flag quic_enable_alps_client. - const bool enable_alps_ = GetQuicReloadableFlag(quic_enable_alps_client); }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker_test.cc b/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker_test.cc index e498acb9a43..8365f633f0f 100644 --- a/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker_test.cc @@ -279,11 +279,7 @@ TEST_P(TlsClientHandshakerTest, ConnectedAfterHandshake) { TEST_P(TlsClientHandshakerTest, ConnectionClosedOnTlsError) { // Have client send ClientHello. stream()->CryptoConnect(); - if (GetQuicReloadableFlag(quic_send_tls_crypto_error_code)) { - EXPECT_CALL(*connection_, CloseConnection(QUIC_HANDSHAKE_FAILED, _, _, _)); - } else { - EXPECT_CALL(*connection_, CloseConnection(QUIC_HANDSHAKE_FAILED, _, _)); - } + EXPECT_CALL(*connection_, CloseConnection(QUIC_HANDSHAKE_FAILED, _, _, _)); // Send a zero-length ServerHello from server to client. char bogus_handshake_message[] = { @@ -621,23 +617,14 @@ TEST_P(TlsClientHandshakerTest, ServerRequiresCustomALPN) { .WillOnce([kTestAlpn](const std::vector<absl::string_view>& alpns) { return std::find(alpns.cbegin(), alpns.cend(), kTestAlpn); }); - if (GetQuicReloadableFlag(quic_send_tls_crypto_error_code)) { - EXPECT_CALL( - *server_connection_, - CloseConnection( - QUIC_HANDSHAKE_FAILED, - static_cast<QuicIetfTransportErrorCodes>(CRYPTO_ERROR_FIRST + 120), - "TLS handshake failure (ENCRYPTION_INITIAL) 120: " - "no application protocol", - _)); - } else { - EXPECT_CALL( - *server_connection_, - CloseConnection(QUIC_HANDSHAKE_FAILED, - "TLS handshake failure (ENCRYPTION_INITIAL) 120: " - "no application protocol", - _)); - } + + EXPECT_CALL(*server_connection_, + CloseConnection(QUIC_HANDSHAKE_FAILED, + static_cast<QuicIetfTransportErrorCodes>( + CRYPTO_ERROR_FIRST + 120), + "TLS handshake failure (ENCRYPTION_INITIAL) 120: " + "no application protocol", + _)); stream()->CryptoConnect(); crypto_test_utils::AdvanceHandshake(connection_, stream(), 0, 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 bc8e0b48d4d..9ba5f3c12f6 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 @@ -96,6 +96,13 @@ void TlsHandshaker::AdvanceHandshake() { return; } + QUICHE_BUG_IF(quic_tls_server_async_done_no_flusher, + SSL_is_server(ssl()) && add_packet_flusher_on_async_op_done_ && + !handshaker_delegate_->PacketFlusherAttached()) + << "is_server:" << SSL_is_server(ssl()) + << ", add_packet_flusher_on_async_op_done_:" + << add_packet_flusher_on_async_op_done_; + QUIC_VLOG(1) << ENDPOINT << "Continuing handshake"; int rv = SSL_do_handshake(ssl()); @@ -105,6 +112,7 @@ void TlsHandshaker::AdvanceHandshake() { // that case. If there are no unprocessed ServerHello, the retry will return a // non-positive number. if (retry_handshake_on_early_data_ && rv == 1 && SSL_in_early_data(ssl())) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_tls_retry_handshake_on_early_data, 1, 2); OnEnterEarlyData(); rv = SSL_do_handshake(ssl()); QUIC_VLOG(1) << ENDPOINT @@ -335,15 +343,10 @@ void TlsHandshaker::SendAlert(EncryptionLevel level, uint8_t desc) { "TLS handshake failure (", EncryptionLevelToString(level), ") ", static_cast<int>(desc), ": ", SSL_alert_desc_string_long(desc)); QUIC_DLOG(ERROR) << error_details; - if (GetQuicReloadableFlag(quic_send_tls_crypto_error_code)) { - QUIC_RELOADABLE_FLAG_COUNT(quic_send_tls_crypto_error_code); - CloseConnection( - TlsAlertToQuicErrorCode(desc), - static_cast<QuicIetfTransportErrorCodes>(CRYPTO_ERROR_FIRST + desc), - error_details); - } else { - CloseConnection(QUIC_HANDSHAKE_FAILED, error_details); - } + CloseConnection( + TlsAlertToQuicErrorCode(desc), + static_cast<QuicIetfTransportErrorCodes>(CRYPTO_ERROR_FIRST + desc), + error_details); } } // namespace quic 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 6bf48b548c4..0b5ddc36769 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 @@ -16,6 +16,7 @@ #include "quic/core/crypto/tls_connection.h" #include "quic/core/quic_session.h" #include "quic/platform/api/quic_export.h" +#include "quic/platform/api/quic_flags.h" namespace quic { @@ -167,6 +168,9 @@ class QUIC_EXPORT_PRIVATE TlsHandshaker : public TlsConnection::Delegate, // error code corresponding to the TLS alert description |desc|. void SendAlert(EncryptionLevel level, uint8_t desc) override; + const bool add_packet_flusher_on_async_op_done_ = + GetQuicReloadableFlag(quic_add_packet_flusher_on_async_op_done); + const bool retry_handshake_on_early_data_ = GetQuicReloadableFlag(quic_tls_retry_handshake_on_early_data); 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 b628db1744a..efd4d275013 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 @@ -8,6 +8,7 @@ #include <string> #include "absl/base/macros.h" +#include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" #include "third_party/boringssl/src/include/openssl/pool.h" #include "third_party/boringssl/src/include/openssl/ssl.h" @@ -22,7 +23,6 @@ #include "quic/platform/api/quic_hostname_utils.h" #include "quic/platform/api/quic_logging.h" #include "quic/platform/api/quic_server_stats.h" -#include "common/platform/api/quiche_text_utils.h" #define RECORD_LATENCY_IN_US(stat_name, latency, comment) \ do { \ @@ -47,8 +47,6 @@ void TlsServerHandshaker::DefaultProofSourceHandle::CancelPendingOperation() { QUIC_DVLOG(1) << "CancelPendingOperation. is_signature_pending=" << (signature_callback_ != nullptr); if (signature_callback_) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_tls_use_per_handshaker_proof_source, 3, - 3); signature_callback_->Cancel(); signature_callback_ = nullptr; } @@ -58,9 +56,11 @@ QuicAsyncStatus TlsServerHandshaker::DefaultProofSourceHandle::SelectCertificate( const QuicSocketAddress& server_address, const QuicSocketAddress& client_address, + absl::string_view /*ssl_capabilities*/, const std::string& hostname, absl::string_view /*client_hello*/, const std::string& /*alpn*/, + absl::optional<std::string> /*alps*/, const std::vector<uint8_t>& /*quic_transport_params*/, const absl::optional<std::vector<uint8_t>>& /*early_data_context*/) { if (!handshaker_ || !proof_source_) { @@ -73,7 +73,8 @@ TlsServerHandshaker::DefaultProofSourceHandle::SelectCertificate( proof_source_->GetCertChain(server_address, client_address, hostname); handshaker_->OnSelectCertificateDone( - /*ok=*/true, /*is_sync=*/true, chain.get()); + /*ok=*/true, /*is_sync=*/true, chain.get(), + /*handshake_hints=*/absl::string_view()); if (!handshaker_->select_cert_status().has_value()) { QUIC_BUG(quic_bug_12423_1) << "select_cert_status() has no value after a synchronous select cert"; @@ -119,35 +120,6 @@ QuicAsyncStatus TlsServerHandshaker::DefaultProofSourceHandle::ComputeSignature( return success ? QUIC_SUCCESS : QUIC_FAILURE; } -TlsServerHandshaker::SignatureCallback::SignatureCallback( - TlsServerHandshaker* handshaker) - : handshaker_(handshaker) { - QUICHE_DCHECK(!handshaker_->use_proof_source_handle_); -} - -void TlsServerHandshaker::SignatureCallback::Run( - bool ok, - std::string signature, - std::unique_ptr<ProofSource::Details> details) { - if (handshaker_ == nullptr) { - return; - } - if (ok) { - handshaker_->cert_verify_sig_ = std::move(signature); - handshaker_->proof_source_details_ = std::move(details); - } - int last_expected_ssl_error = handshaker_->expected_ssl_error(); - handshaker_->set_expected_ssl_error(SSL_ERROR_WANT_READ); - handshaker_->signature_callback_ = nullptr; - if (last_expected_ssl_error == SSL_ERROR_WANT_PRIVATE_KEY_OPERATION) { - handshaker_->AdvanceHandshakeFromCallback(); - } -} - -void TlsServerHandshaker::SignatureCallback::Cancel() { - handshaker_ = nullptr; -} - TlsServerHandshaker::DecryptCallback::DecryptCallback( TlsServerHandshaker* handshaker) : handshaker_(handshaker) {} @@ -217,13 +189,9 @@ TlsServerHandshaker::~TlsServerHandshaker() { } void TlsServerHandshaker::CancelOutstandingCallbacks() { - if (use_proof_source_handle_ && proof_source_handle_) { + if (proof_source_handle_) { proof_source_handle_->CancelPendingOperation(); } - if (signature_callback_) { - signature_callback_->Cancel(); - signature_callback_ = nullptr; - } if (ticket_decryption_callback_) { ticket_decryption_callback_->Cancel(); ticket_decryption_callback_ = nullptr; @@ -232,7 +200,6 @@ void TlsServerHandshaker::CancelOutstandingCallbacks() { std::unique_ptr<ProofSourceHandle> TlsServerHandshaker::MaybeCreateProofSourceHandle() { - QUICHE_DCHECK(use_proof_source_handle_); return std::make_unique<DefaultProofSourceHandle>(this, proof_source_); } @@ -384,6 +351,19 @@ TlsServerHandshaker::CreateCurrentOneRttEncrypter() { void TlsServerHandshaker::OverrideQuicConfigDefaults(QuicConfig* /*config*/) {} void TlsServerHandshaker::AdvanceHandshakeFromCallback() { + std::unique_ptr<QuicConnection::ScopedPacketFlusher> flusher; + if (add_packet_flusher_on_async_op_done_) { + if (session()->PacketFlusherAttached()) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_add_packet_flusher_on_async_op_done, 1, + 2); + } else { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_add_packet_flusher_on_async_op_done, 2, + 2); + } + flusher = std::make_unique<QuicConnection::ScopedPacketFlusher>( + session()->connection()); + } + AdvanceHandshake(); if (!is_connection_closed()) { handshaker_delegate()->OnHandshakeCallbackDone(); @@ -541,6 +521,7 @@ std::string TlsServerHandshaker::GetAcceptChValueForOrigin( void TlsServerHandshaker::FinishHandshake() { if (retry_handshake_on_early_data_) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_tls_retry_handshake_on_early_data, 2, 2); QUICHE_DCHECK(!SSL_in_early_data(ssl())); } else { if (SSL_in_early_data(ssl())) { @@ -601,33 +582,19 @@ ssl_private_key_result_t TlsServerHandshaker::PrivateKeySign( uint16_t sig_alg, absl::string_view in) { QUICHE_DCHECK_EQ(expected_ssl_error(), SSL_ERROR_WANT_READ); - if (use_proof_source_handle_) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_tls_use_per_handshaker_proof_source, 2, - 3); - QuicAsyncStatus status = proof_source_handle_->ComputeSignature( - session()->connection()->self_address(), - session()->connection()->peer_address(), cert_selection_hostname(), - sig_alg, in, max_out); - if (status == QUIC_PENDING) { - set_expected_ssl_error(SSL_ERROR_WANT_PRIVATE_KEY_OPERATION); - if (async_op_timer_.has_value()) { - QUIC_CODE_COUNT( - quic_tls_server_computing_signature_while_another_op_pending); - } - async_op_timer_ = QuicTimeAccumulator(); - async_op_timer_->Start(now()); - } - return PrivateKeyComplete(out, out_len, max_out); - } - signature_callback_ = new SignatureCallback(this); - proof_source_->ComputeTlsSignature( + QuicAsyncStatus status = proof_source_handle_->ComputeSignature( session()->connection()->self_address(), - session()->connection()->peer_address(), cert_selection_hostname(), - sig_alg, in, std::unique_ptr<SignatureCallback>(signature_callback_)); - if (signature_callback_) { + session()->connection()->peer_address(), crypto_negotiated_params_->sni, + sig_alg, in, max_out); + if (status == QUIC_PENDING) { set_expected_ssl_error(SSL_ERROR_WANT_PRIVATE_KEY_OPERATION); - return ssl_private_key_retry; + if (async_op_timer_.has_value()) { + QUIC_CODE_COUNT( + quic_tls_server_computing_signature_while_another_op_pending); + } + async_op_timer_ = QuicTimeAccumulator(); + async_op_timer_->Start(now()); } return PrivateKeyComplete(out, out_len, max_out); } @@ -673,7 +640,6 @@ void TlsServerHandshaker::OnComputeSignatureDone( QUIC_DVLOG(1) << "OnComputeSignatureDone. ok:" << ok << ", is_sync:" << is_sync << ", len(signature):" << signature.size(); - QUICHE_DCHECK(use_proof_source_handle_); if (ok) { cert_verify_sig_ = std::move(signature); proof_source_details_ = std::move(details); @@ -795,24 +761,21 @@ ssl_select_cert_result_t TlsServerHandshaker::EarlySelectCertCallback( // EarlySelectCertCallback can be called twice from BoringSSL: If the first // call returns ssl_select_cert_retry, when cert selection completes, // SSL_do_handshake will call it again. - if (use_proof_source_handle_) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_tls_use_per_handshaker_proof_source, 1, - 3); - if (select_cert_status_.has_value()) { - // This is the second call, return the result directly. - QUIC_DVLOG(1) << "EarlySelectCertCallback called to continue handshake, " - "returning directly. success:" - << (select_cert_status_.value() == QUIC_SUCCESS); - return (select_cert_status_.value() == QUIC_SUCCESS) - ? ssl_select_cert_success - : ssl_select_cert_error; - } - // This is the first call. - select_cert_status_ = QUIC_PENDING; - proof_source_handle_ = MaybeCreateProofSourceHandle(); + if (select_cert_status_.has_value()) { + // This is the second call, return the result directly. + QUIC_DVLOG(1) << "EarlySelectCertCallback called to continue handshake, " + "returning directly. success:" + << (select_cert_status_.value() == QUIC_SUCCESS); + return (select_cert_status_.value() == QUIC_SUCCESS) + ? ssl_select_cert_success + : ssl_select_cert_error; } + // This is the first call. + select_cert_status_ = QUIC_PENDING; + proof_source_handle_ = MaybeCreateProofSourceHandle(); + if (!pre_shared_key_.empty()) { // TODO(b/154162689) add PSK support to QUIC+TLS. QUIC_BUG(quic_bug_10341_6) @@ -824,18 +787,17 @@ ssl_select_cert_result_t TlsServerHandshaker::EarlySelectCertCallback( // function do not work at this point, but SSL_get_servername does. const char* hostname = SSL_get_servername(ssl(), TLSEXT_NAMETYPE_host_name); if (hostname) { - hostname_ = hostname; crypto_negotiated_params_->sni = - QuicHostnameUtils::NormalizeHostname(hostname_); - if (!ValidateHostname(hostname_)) { + QuicHostnameUtils::NormalizeHostname(hostname); + if (!ValidateHostname(hostname)) { return ssl_select_cert_error; } - if (hostname_ != crypto_negotiated_params_->sni) { + if (hostname != crypto_negotiated_params_->sni) { QUIC_CODE_COUNT(quic_tls_server_hostname_diff); QUIC_LOG_EVERY_N_SEC(WARNING, 300) << "Raw and normalized hostnames differ, but both are valid SNIs. " "raw hostname:" - << hostname_ << ", normalized:" << crypto_negotiated_params_->sni; + << hostname << ", normalized:" << crypto_negotiated_params_->sni; } else { QUIC_CODE_COUNT(quic_tls_server_hostname_same); } @@ -843,97 +805,105 @@ ssl_select_cert_result_t TlsServerHandshaker::EarlySelectCertCallback( QUIC_LOG(INFO) << "No hostname indicated in SNI"; } - if (use_proof_source_handle_) { - std::string error_details; - if (!ProcessTransportParameters(client_hello, &error_details)) { - CloseConnection(QUIC_HANDSHAKE_FAILED, error_details); - return ssl_select_cert_error; - } - OverrideQuicConfigDefaults(session()->config()); - session()->OnConfigNegotiated(); - - auto set_transport_params_result = SetTransportParameters(); - if (!set_transport_params_result.success) { - QUIC_LOG(ERROR) << "Failed to set transport parameters"; - return ssl_select_cert_error; - } - - const QuicAsyncStatus status = proof_source_handle_->SelectCertificate( - session()->connection()->self_address(), - session()->connection()->peer_address(), cert_selection_hostname(), - absl::string_view( - reinterpret_cast<const char*>(client_hello->client_hello), - client_hello->client_hello_len), - AlpnForVersion(session()->version()), - set_transport_params_result.quic_transport_params, - set_transport_params_result.early_data_context); + std::string error_details; + if (!ProcessTransportParameters(client_hello, &error_details)) { + CloseConnection(QUIC_HANDSHAKE_FAILED, error_details); + return ssl_select_cert_error; + } + OverrideQuicConfigDefaults(session()->config()); + session()->OnConfigNegotiated(); - QUICHE_DCHECK_EQ(status, select_cert_status().value()); + auto set_transport_params_result = SetTransportParameters(); + if (!set_transport_params_result.success) { + QUIC_LOG(ERROR) << "Failed to set transport parameters"; + return ssl_select_cert_error; + } - if (status == QUIC_PENDING) { - set_expected_ssl_error(SSL_ERROR_PENDING_CERTIFICATE); - if (async_op_timer_.has_value()) { - QUIC_CODE_COUNT( - quic_tls_server_selecting_cert_while_another_op_pending); - } - async_op_timer_ = QuicTimeAccumulator(); - async_op_timer_->Start(now()); - return ssl_select_cert_retry; + bssl::UniquePtr<uint8_t> ssl_capabilities; + size_t ssl_capabilities_len = 0; + absl::string_view ssl_capabilities_view; + + absl::optional<std::string> alps; + if (use_handshake_hints_) { + QUIC_RELOADABLE_FLAG_COUNT(quic_tls_server_use_handshake_hints); + if (CryptoUtils::GetSSLCapabilities(ssl(), &ssl_capabilities, + &ssl_capabilities_len)) { + ssl_capabilities_view = absl::string_view( + reinterpret_cast<const char*>(ssl_capabilities.get()), + ssl_capabilities_len); } - if (status == QUIC_FAILURE) { + // Enable ALPS for the session's ALPN. + SetApplicationSettingsResult alps_result = + SetApplicationSettings(AlpnForVersion(session()->version())); + if (!alps_result.success) { return ssl_select_cert_error; } - - return ssl_select_cert_success; - } - - QuicReferenceCountedPointer<ProofSource::Chain> chain = - proof_source_->GetCertChain(session()->connection()->self_address(), - session()->connection()->peer_address(), - cert_selection_hostname()); - if (!chain || chain->certs.empty()) { - QUIC_LOG(ERROR) << "No certs provided for host. raw:" << hostname_ - << ", normalized:" << crypto_negotiated_params_->sni; - return ssl_select_cert_error; + alps = alps_result.alps_length > 0 + ? std::string(alps_result.alps_buffer.get(), + alps_result.alps_length) + : std::string(); } - CryptoBuffers cert_buffers = chain->ToCryptoBuffers(); - tls_connection_.SetCertChain(cert_buffers.value); - - std::string error_details; - if (!ProcessTransportParameters(client_hello, &error_details)) { - CloseConnection(QUIC_HANDSHAKE_FAILED, error_details); - return ssl_select_cert_error; + const QuicAsyncStatus status = proof_source_handle_->SelectCertificate( + session()->connection()->self_address(), + session()->connection()->peer_address(), ssl_capabilities_view, + crypto_negotiated_params_->sni, + absl::string_view( + reinterpret_cast<const char*>(client_hello->client_hello), + client_hello->client_hello_len), + AlpnForVersion(session()->version()), std::move(alps), + set_transport_params_result.quic_transport_params, + set_transport_params_result.early_data_context); + + QUICHE_DCHECK_EQ(status, select_cert_status().value()); + + if (status == QUIC_PENDING) { + set_expected_ssl_error(SSL_ERROR_PENDING_CERTIFICATE); + if (async_op_timer_.has_value()) { + QUIC_CODE_COUNT(quic_tls_server_selecting_cert_while_another_op_pending); + } + async_op_timer_ = QuicTimeAccumulator(); + async_op_timer_->Start(now()); + return ssl_select_cert_retry; } - OverrideQuicConfigDefaults(session()->config()); - session()->OnConfigNegotiated(); - if (!SetTransportParameters().success) { - QUIC_LOG(ERROR) << "Failed to set transport parameters"; + if (status == QUIC_FAILURE) { return ssl_select_cert_error; } - QUIC_DLOG(INFO) << "Set " << chain->certs.size() << " certs for server " - << "with hostname " << hostname_; return ssl_select_cert_success; } void TlsServerHandshaker::OnSelectCertificateDone( bool ok, bool is_sync, - const ProofSource::Chain* chain) { + const ProofSource::Chain* chain, + absl::string_view handshake_hints) { QUIC_DVLOG(1) << "OnSelectCertificateDone. ok:" << ok - << ", is_sync:" << is_sync; - QUICHE_DCHECK(use_proof_source_handle_); - + << ", is_sync:" << is_sync + << ", len(handshake_hints):" << handshake_hints.size(); select_cert_status_ = QUIC_FAILURE; if (ok) { if (chain && !chain->certs.empty()) { tls_connection_.SetCertChain(chain->ToCryptoBuffers().value); + if (use_handshake_hints_) { + if (!handshake_hints.empty() && + !SSL_set_handshake_hints( + ssl(), reinterpret_cast<const uint8_t*>(handshake_hints.data()), + handshake_hints.size())) { + // If |SSL_set_handshake_hints| fails, the ssl() object will remain + // intact, it is as if we didn't call it. The handshaker will + // continue to compute signature/decrypt ticket as normal. + QUIC_CODE_COUNT(quic_tls_server_set_handshake_hints_failed); + QUIC_DVLOG(1) << "SSL_set_handshake_hints failed"; + } + } select_cert_status_ = QUIC_SUCCESS; } else { - QUIC_LOG(ERROR) << "No certs provided for host '" << hostname_ << "'"; + QUIC_LOG(ERROR) << "No certs provided for host '" + << crypto_negotiated_params_->sni << "', server_address:" + << session()->connection()->self_address(); } } @@ -1008,40 +978,17 @@ int TlsServerHandshaker::SelectAlpn(const uint8_t** out, alpn_length); } + // TODO(wub): Remove QuicSession::SelectAlpn. QuicSessions should know the + // ALPN on construction. 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; } - // Enable ALPS for the selected ALPN protocol. - if (GetQuicReloadableFlag(quic_enable_alps_server)) { - QUIC_RELOADABLE_FLAG_COUNT(quic_enable_alps_server); - - const uint8_t* alps_data = nullptr; - size_t alps_length = 0; - std::unique_ptr<char[]> buffer; - - const std::string& hostname = crypto_negotiated_params_->sni; - std::string accept_ch_value = GetAcceptChValueForOrigin(hostname); - - std::string origin; - if (GetQuicReloadableFlag(quic_alps_include_scheme_in_origin)) { - QUIC_RELOADABLE_FLAG_COUNT(quic_alps_include_scheme_in_origin); - origin = "https://"; - } - origin.append(crypto_negotiated_params_->sni); - - if (!accept_ch_value.empty()) { - AcceptChFrame frame{{{std::move(origin), std::move(accept_ch_value)}}}; - alps_length = HttpEncoder::SerializeAcceptChFrame(frame, &buffer); - alps_data = reinterpret_cast<const uint8_t*>(buffer.get()); - } - - if (SSL_add_application_settings( - ssl(), reinterpret_cast<const uint8_t*>(selected_alpn->data()), - selected_alpn->size(), alps_data, alps_length) != 1) { - QUIC_DLOG(ERROR) << "Failed to enable ALPS"; + if (!use_handshake_hints_) { + // Enable ALPS for the selected ALPN protocol. + if (!SetApplicationSettings(*selected_alpn).success) { return SSL_TLSEXT_ERR_NOACK; } } @@ -1053,4 +1000,31 @@ int TlsServerHandshaker::SelectAlpn(const uint8_t** out, return SSL_TLSEXT_ERR_OK; } +TlsServerHandshaker::SetApplicationSettingsResult +TlsServerHandshaker::SetApplicationSettings(absl::string_view alpn) { + TlsServerHandshaker::SetApplicationSettingsResult result; + const uint8_t* alps_data = nullptr; + + const std::string& hostname = crypto_negotiated_params_->sni; + std::string accept_ch_value = GetAcceptChValueForOrigin(hostname); + std::string origin = absl::StrCat("https://", hostname); + + if (!accept_ch_value.empty()) { + AcceptChFrame frame{{{std::move(origin), std::move(accept_ch_value)}}}; + result.alps_length = + HttpEncoder::SerializeAcceptChFrame(frame, &result.alps_buffer); + alps_data = reinterpret_cast<const uint8_t*>(result.alps_buffer.get()); + } + + if (SSL_add_application_settings( + ssl(), reinterpret_cast<const uint8_t*>(alpn.data()), alpn.size(), + alps_data, result.alps_length) != 1) { + QUIC_DLOG(ERROR) << "Failed to enable ALPS"; + result.success = false; + } else { + result.success = true; + } + return result; +} + } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.h b/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.h index 7850d3519a8..260b094bda7 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 @@ -19,6 +19,7 @@ #include "quic/core/quic_types.h" #include "quic/core/tls_handshaker.h" #include "quic/platform/api/quic_export.h" +#include "quic/platform/api/quic_flags.h" namespace quic { @@ -88,25 +89,14 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker protected: // Creates a proof source handle for selecting cert and computing signature. - // Only called when |use_proof_source_handle_| is true. virtual std::unique_ptr<ProofSourceHandle> MaybeCreateProofSourceHandle(); - bool use_proof_source_handle() const { return use_proof_source_handle_; } - // Hook to allow the server to override parts of the QuicConfig based on SNI // before we generate transport parameters. virtual void OverrideQuicConfigDefaults(QuicConfig* config); virtual bool ValidateHostname(const std::string& hostname) const; - // The hostname to be used to select certificates and compute signatures. - // The function should only be called after a successful ValidateHostname(). - const std::string& cert_selection_hostname() const { - return use_normalized_sni_for_cert_selection_ - ? crypto_negotiated_params_->sni - : hostname_; - } - const TlsConnection* tls_connection() const override { return &tls_connection_; } @@ -177,7 +167,8 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker // ProofSourceHandleCallback implementation: void OnSelectCertificateDone(bool ok, bool is_sync, - const ProofSource::Chain* chain) override; + const ProofSource::Chain* chain, + absl::string_view handshake_hints) override; void OnComputeSignatureDone( bool ok, @@ -186,21 +177,6 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker std::unique_ptr<ProofSource::Details> details) override; private: - class QUIC_EXPORT_PRIVATE SignatureCallback - : public ProofSource::SignatureCallback { - public: - explicit SignatureCallback(TlsServerHandshaker* handshaker); - void Run(bool ok, - std::string signature, - std::unique_ptr<ProofSource::Details> details) override; - - // If called, Cancel causes the pending callback to be a no-op. - void Cancel(); - - private: - TlsServerHandshaker* handshaker_; - }; - class QUIC_EXPORT_PRIVATE DecryptCallback : public ProofSource::DecryptCallback { public: @@ -232,9 +208,11 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker QuicAsyncStatus SelectCertificate( const QuicSocketAddress& server_address, const QuicSocketAddress& client_address, + absl::string_view ssl_capabilities, const std::string& hostname, absl::string_view client_hello, const std::string& alpn, + absl::optional<std::string> alps, const std::vector<uint8_t>& quic_transport_params, const absl::optional<std::vector<uint8_t>>& early_data_context) override; @@ -302,6 +280,13 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker bool ProcessTransportParameters(const SSL_CLIENT_HELLO* client_hello, std::string* error_details); + struct QUIC_NO_EXPORT SetApplicationSettingsResult { + bool success = false; + std::unique_ptr<char[]> alps_buffer; + size_t alps_length = 0; + }; + SetApplicationSettingsResult SetApplicationSettings(absl::string_view alpn); + QuicConnectionStats& connection_stats() { return session()->connection()->mutable_stats(); } @@ -309,7 +294,6 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker std::unique_ptr<ProofSourceHandle> proof_source_handle_; ProofSource* proof_source_; - SignatureCallback* signature_callback_ = nullptr; // State to handle potentially asynchronous session ticket decryption. // |ticket_decryption_callback_| points to the non-owned callback that was @@ -328,7 +312,6 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker // nullopt means select cert hasn't started. absl::optional<QuicAsyncStatus> select_cert_status_; - std::string hostname_; std::string cert_verify_sig_; std::unique_ptr<ProofSource::Details> proof_source_details_; @@ -346,11 +329,9 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> crypto_negotiated_params_; TlsServerConnection tls_connection_; - const bool use_proof_source_handle_ = - GetQuicReloadableFlag(quic_tls_use_per_handshaker_proof_source); - const bool use_normalized_sni_for_cert_selection_ = - GetQuicReloadableFlag(quic_tls_use_normalized_sni_for_cert_selectioon); const QuicCryptoServerConfig* crypto_config_; // Unowned. + const bool use_handshake_hints_ = + GetQuicReloadableFlag(quic_tls_server_use_handshake_hints); }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker_test.cc b/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker_test.cc index fbec2551227..d67c8791d2c 100644 --- a/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker_test.cc @@ -400,10 +400,6 @@ TEST_P(TlsServerHandshakerTest, ConnectedAfterTlsHandshake) { } TEST_P(TlsServerHandshakerTest, HandshakeWithAsyncSelectCertSuccess) { - if (!GetQuicReloadableFlag(quic_tls_use_per_handshaker_proof_source)) { - return; - } - InitializeServerWithFakeProofSourceHandle(); server_handshaker_->SetupProofSourceHandle( /*select_cert_action=*/FakeProofSourceHandle::Action::DELEGATE_ASYNC, @@ -426,10 +422,6 @@ TEST_P(TlsServerHandshakerTest, HandshakeWithAsyncSelectCertSuccess) { } TEST_P(TlsServerHandshakerTest, HandshakeWithAsyncSelectCertFailure) { - if (!GetQuicReloadableFlag(quic_tls_use_per_handshaker_proof_source)) { - return; - } - InitializeServerWithFakeProofSourceHandle(); server_handshaker_->SetupProofSourceHandle( /*select_cert_action=*/FakeProofSourceHandle::Action::FAIL_ASYNC, @@ -449,10 +441,6 @@ TEST_P(TlsServerHandshakerTest, HandshakeWithAsyncSelectCertFailure) { } TEST_P(TlsServerHandshakerTest, HandshakeWithAsyncSelectCertAndSignature) { - if (!GetQuicReloadableFlag(quic_tls_use_per_handshaker_proof_source)) { - return; - } - InitializeServerWithFakeProofSourceHandle(); server_handshaker_->SetupProofSourceHandle( /*select_cert_action=*/FakeProofSourceHandle::Action::DELEGATE_ASYNC, @@ -507,10 +495,6 @@ TEST_P(TlsServerHandshakerTest, HandshakeWithAsyncSignature) { } TEST_P(TlsServerHandshakerTest, CancelPendingSelectCert) { - if (!GetQuicReloadableFlag(quic_tls_use_per_handshaker_proof_source)) { - return; - } - InitializeServerWithFakeProofSourceHandle(); server_handshaker_->SetupProofSourceHandle( /*select_cert_action=*/FakeProofSourceHandle::Action::DELEGATE_ASYNC, @@ -557,10 +541,6 @@ TEST_P(TlsServerHandshakerTest, ExtractSNI) { } TEST_P(TlsServerHandshakerTest, HostnameForCertSelectionAndComputeSignature) { - if (!GetQuicReloadableFlag(quic_tls_use_per_handshaker_proof_source)) { - return; - } - // Client uses upper case letters in hostname. It is considered valid by // QuicHostnameUtils::IsValidSNI, but it should be normalized for cert // selection. @@ -577,23 +557,13 @@ TEST_P(TlsServerHandshakerTest, HostnameForCertSelectionAndComputeSignature) { EXPECT_EQ(server_stream()->crypto_negotiated_params().sni, "test.example.com"); - if (GetQuicReloadableFlag(quic_tls_use_normalized_sni_for_cert_selectioon)) { - EXPECT_EQ(last_select_cert_args().hostname, "test.example.com"); - EXPECT_EQ(last_compute_signature_args().hostname, "test.example.com"); - } else { - EXPECT_EQ(last_select_cert_args().hostname, "tEsT.EXAMPLE.CoM"); - EXPECT_EQ(last_compute_signature_args().hostname, "tEsT.EXAMPLE.CoM"); - } + EXPECT_EQ(last_select_cert_args().hostname, "test.example.com"); + EXPECT_EQ(last_compute_signature_args().hostname, "test.example.com"); } TEST_P(TlsServerHandshakerTest, ConnectionClosedOnTlsError) { - if (GetQuicReloadableFlag(quic_send_tls_crypto_error_code)) { - EXPECT_CALL(*server_connection_, - CloseConnection(QUIC_HANDSHAKE_FAILED, _, _, _)); - } else { - EXPECT_CALL(*server_connection_, - CloseConnection(QUIC_HANDSHAKE_FAILED, _, _)); - } + EXPECT_CALL(*server_connection_, + CloseConnection(QUIC_HANDSHAKE_FAILED, _, _, _)); // Send a zero-length ClientHello from client to server. char bogus_handshake_message[] = { @@ -601,6 +571,15 @@ TEST_P(TlsServerHandshakerTest, ConnectionClosedOnTlsError) { 1, // HandshakeType client_hello 0, 0, 0, // uint24 length }; + + // Install a packet flusher such that the packets generated by + // |server_connection_| in response to this handshake message are more likely + // to be coalesced and/or batched in the writer. + // + // This is required by TlsServerHandshaker because without the flusher, it + // tends to generate many small, uncoalesced packets, one per + // TlsHandshaker::WriteMessage. + QuicConnection::ScopedPacketFlusher flusher(server_connection_); server_stream()->crypto_message_parser()->ProcessInput( absl::string_view(bogus_handshake_message, ABSL_ARRAYSIZE(bogus_handshake_message)), @@ -613,23 +592,14 @@ TEST_P(TlsServerHandshakerTest, ClientSendingBadALPN) { const std::string kTestBadClientAlpn = "bad-client-alpn"; EXPECT_CALL(*client_session_, GetAlpnsToOffer()) .WillOnce(Return(std::vector<std::string>({kTestBadClientAlpn}))); - if (GetQuicReloadableFlag(quic_send_tls_crypto_error_code)) { - EXPECT_CALL( - *server_connection_, - CloseConnection( - QUIC_HANDSHAKE_FAILED, - static_cast<QuicIetfTransportErrorCodes>(CRYPTO_ERROR_FIRST + 120), - "TLS handshake failure (ENCRYPTION_INITIAL) 120: " - "no application protocol", - _)); - } else { - EXPECT_CALL( - *server_connection_, - CloseConnection(QUIC_HANDSHAKE_FAILED, - "TLS handshake failure (ENCRYPTION_INITIAL) 120: " - "no application protocol", - _)); - } + + EXPECT_CALL(*server_connection_, + CloseConnection(QUIC_HANDSHAKE_FAILED, + static_cast<QuicIetfTransportErrorCodes>( + CRYPTO_ERROR_FIRST + 120), + "TLS handshake failure (ENCRYPTION_INITIAL) 120: " + "no application protocol", + _)); AdvanceHandshakeWithFakeClient(); 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 5ed0e08777a..8f20b33c183 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 @@ -120,14 +120,11 @@ void UberReceivedPacketManager::EnableMultiplePacketNumberSpacesSupport( } // In IETF QUIC, the peer is expected to acknowledge packets in Initial and // Handshake packets with minimal delay. - if (!GetQuicReloadableFlag(quic_delay_initial_ack) || - perspective == Perspective::IS_CLIENT) { + if (perspective == Perspective::IS_CLIENT) { // Delay the first server ACK, because server ACKs are padded to // full size and count towards the amplification limit. received_packet_managers_[INITIAL_DATA].set_local_max_ack_delay( kAlarmGranularity); - } else { - QUIC_RELOADABLE_FLAG_COUNT(quic_delay_initial_ack); } received_packet_managers_[HANDSHAKE_DATA].set_local_max_ack_delay( kAlarmGranularity); 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 05e4a33aedf..cf612feab1d 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 @@ -478,17 +478,10 @@ TEST_F(UberReceivedPacketManagerTest, AckSendingDifferentPacketNumberSpaces) { MaybeUpdateAckTimeout(kInstigateAck, ENCRYPTION_INITIAL, 3); EXPECT_TRUE(HasPendingAck()); // Delayed ack is scheduled. - if (GetQuicReloadableFlag(quic_delay_initial_ack)) { - CheckAckTimeout(clock_.ApproximateNow() + - QuicTime::Delta::FromMilliseconds(25)); - // Send delayed handshake data ACK. - clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(25)); - } else { - CheckAckTimeout(clock_.ApproximateNow() + - QuicTime::Delta::FromMilliseconds(1)); - // Send delayed handshake data ACK. - clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1)); - } + CheckAckTimeout(clock_.ApproximateNow() + + QuicTime::Delta::FromMilliseconds(25)); + // Send delayed handshake data ACK. + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(25)); CheckAckTimeout(clock_.ApproximateNow()); EXPECT_FALSE(HasPendingAck()); diff --git a/chromium/net/third_party/quiche/src/quic/masque/masque_client_bin.cc b/chromium/net/third_party/quiche/src/quic/masque/masque_client_bin.cc index 4d0523f5177..920372574a1 100644 --- a/chromium/net/third_party/quiche/src/quic/masque/masque_client_bin.cc +++ b/chromium/net/third_party/quiche/src/quic/masque/masque_client_bin.cc @@ -22,7 +22,6 @@ #include "quic/platform/api/quic_system_event_loop.h" #include "quic/tools/fake_proof_verifier.h" #include "quic/tools/quic_url.h" -#include "common/platform/api/quiche_text_utils.h" DEFINE_QUIC_COMMAND_LINE_FLAG(bool, disable_certificate_verification, diff --git a/chromium/net/third_party/quiche/src/quic/masque/masque_client_session.cc b/chromium/net/third_party/quiche/src/quic/masque/masque_client_session.cc index 8793d5319f2..6eee553e076 100644 --- a/chromium/net/third_party/quiche/src/quic/masque/masque_client_session.cc +++ b/chromium/net/third_party/quiche/src/quic/masque/masque_client_session.cc @@ -7,7 +7,6 @@ #include "quic/core/http/spdy_utils.h" #include "quic/core/quic_data_reader.h" #include "quic/core/quic_utils.h" -#include "common/platform/api/quiche_text_utils.h" namespace quic { diff --git a/chromium/net/third_party/quiche/src/quic/masque/masque_compression_engine.cc b/chromium/net/third_party/quiche/src/quic/masque/masque_compression_engine.cc index 8413e0d974b..b021b41a0a6 100644 --- a/chromium/net/third_party/quiche/src/quic/masque/masque_compression_engine.cc +++ b/chromium/net/third_party/quiche/src/quic/masque/masque_compression_engine.cc @@ -15,7 +15,7 @@ #include "quic/core/quic_types.h" #include "quic/core/quic_versions.h" #include "quic/platform/api/quic_containers.h" -#include "common/platform/api/quiche_text_utils.h" +#include "common/quiche_text_utils.h" namespace quic { diff --git a/chromium/net/third_party/quiche/src/quic/masque/masque_server_backend.cc b/chromium/net/third_party/quiche/src/quic/masque/masque_server_backend.cc index 112f3053180..9684ce1956c 100644 --- a/chromium/net/third_party/quiche/src/quic/masque/masque_server_backend.cc +++ b/chromium/net/third_party/quiche/src/quic/masque/masque_server_backend.cc @@ -90,7 +90,7 @@ bool MasqueServerBackend::MaybeHandleMasqueRequest( QUIC_DLOG(INFO) << "Sending MASQUE response for " << request_headers.DebugString(); - request_handler->OnResponseBackendComplete(response.get(), {}); + request_handler->OnResponseBackendComplete(response.get()); it->second.responses.emplace_back(std::move(response)); return true; diff --git a/chromium/net/third_party/quiche/src/quic/masque/masque_server_session.cc b/chromium/net/third_party/quiche/src/quic/masque/masque_server_session.cc index 036c75fb95c..8a531cab3a0 100644 --- a/chromium/net/third_party/quiche/src/quic/masque/masque_server_session.cc +++ b/chromium/net/third_party/quiche/src/quic/masque/masque_server_session.cc @@ -13,7 +13,6 @@ #include "quic/core/quic_data_reader.h" #include "quic/core/quic_udp_socket.h" #include "quic/tools/quic_url.h" -#include "common/platform/api/quiche_text_utils.h" namespace quic { diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/quic_containers.h b/chromium/net/third_party/quiche/src/quic/platform/api/quic_containers.h index fa4610be27b..f7fd922f594 100644 --- a/chromium/net/third_party/quiche/src/quic/platform/api/quic_containers.h +++ b/chromium/net/third_party/quiche/src/quic/platform/api/quic_containers.h @@ -7,47 +7,14 @@ #include "net/quic/platform/impl/quic_containers_impl.h" -namespace quic { - -// The default hasher used by hash tables. -template <typename Key> -using QuicDefaultHasher = QuicDefaultHasherImpl<Key>; - -// A general-purpose unordered map. -template <typename Key, typename Value, typename Hash = QuicDefaultHasher<Key>> -using QuicUnorderedMap = QuicUnorderedMapImpl<Key, Value, Hash>; +#include "absl/hash/hash.h" -// A general-purpose unordered map that does not gurantee pointer stability. -template <typename Key, typename Value, typename Hash = QuicDefaultHasher<Key>> -using QuicHashMap = QuicHashMapImpl<Key, Value, Hash>; - -// A general-purpose unordered set. -template <typename Key, typename Hash = QuicDefaultHasher<Key>> -using QuicUnorderedSet = QuicUnorderedSetImpl<Key, Hash>; - -// A general-purpose unordered set that does not gurantee pointer stability. -template <typename Key, typename Hash = QuicDefaultHasher<Key>> -using QuicHashSet = QuicHashSetImpl<Key, Hash>; +namespace quic { // A map which offers insertion-ordered iteration. -template <typename Key, typename Value, typename Hash = QuicDefaultHasher<Key>> +template <typename Key, typename Value, typename Hash = absl::Hash<Key>> using QuicLinkedHashMap = QuicLinkedHashMapImpl<Key, Value, Hash>; -// Used for maps that are typically small, then it is faster than (for example) -// hash_map which is optimized for large data sets. QuicSmallMap upgrades itself -// automatically to a QuicSmallMapImpl-specified map when it runs out of space. -// -// DOES NOT GUARANTEE POINTER OR ITERATOR STABILITY! -template <typename Key, typename Value, int Size> -using QuicSmallMap = QuicSmallMapImpl<Key, Value, Size>; - -// Represents a simple queue which may be backed by a list or -// a flat circular buffer. -// -// DOES NOT GUARANTEE POINTER OR ITERATOR STABILITY! -template <typename T> -using QuicQueue = QuicQueueImpl<T>; - // A vector optimized for small sizes. Provides the same APIs as a std::vector. template <typename T, size_t N, typename A = std::allocator<T>> using QuicInlinedVector = QuicInlinedVectorImpl<T, N, A>; diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/quic_sleep.h b/chromium/net/third_party/quiche/src/quic/platform/api/quic_sleep.h index 8067d458330..00253c3c6fc 100644 --- a/chromium/net/third_party/quiche/src/quic/platform/api/quic_sleep.h +++ b/chromium/net/third_party/quiche/src/quic/platform/api/quic_sleep.h @@ -6,7 +6,8 @@ #define QUICHE_QUIC_PLATFORM_API_QUIC_SLEEP_H_ #include "quic/core/quic_time.h" -#include "net/quic/platform/impl/quic_sleep_impl.h" +// TODO(b/178613777): move into the common QUICHE platform. +#include "quiche_platform_impl/quiche_sleep_impl.h" namespace quic { diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/quic_test.h b/chromium/net/third_party/quiche/src/quic/platform/api/quic_test.h index 69995c35ff8..58896f76d5e 100644 --- a/chromium/net/third_party/quiche/src/quic/platform/api/quic_test.h +++ b/chromium/net/third_party/quiche/src/quic/platform/api/quic_test.h @@ -25,9 +25,6 @@ inline std::string QuicGetTestMemoryCachePath() { return QuicGetTestMemoryCachePathImpl(); } -#define EXPECT_QUIC_DEBUG_DEATH(condition, message) \ - EXPECT_QUIC_DEBUG_DEATH_IMPL(condition, message) - #define QUIC_SLOW_TEST(test) QUIC_SLOW_TEST_IMPL(test) #endif // QUICHE_QUIC_PLATFORM_API_QUIC_TEST_H_ diff --git a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/icmp_reachable.cc b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/icmp_reachable.cc index b5d9c47f3b8..8e39996284e 100644 --- a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/icmp_reachable.cc +++ b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/icmp_reachable.cc @@ -11,8 +11,8 @@ #include "quic/platform/api/quic_logging.h" #include "quic/platform/api/quic_mutex.h" #include "quic/qbone/platform/icmp_packet.h" -#include "common/platform/api/quiche_text_utils.h" #include "common/quiche_endian.h" +#include "common/quiche_text_utils.h" namespace quic { namespace { @@ -98,8 +98,6 @@ bool IcmpReachable::Init() { 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; 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 index d593913d3ae..056346ca000 100644 --- 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 @@ -18,6 +18,8 @@ class MockTunDevice : public TunDeviceInterface { MOCK_METHOD(bool, Down, (), (override)); + MOCK_METHOD(void, CloseDevice, (), (override)); + MOCK_METHOD(int, GetFileDescriptor, (), (const, override)); }; diff --git a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device.cc b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device.cc index 3ca52e8d6d6..65197cdd4d9 100644 --- a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device.cc +++ b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device.cc @@ -10,6 +10,7 @@ #include <sys/ioctl.h> #include <sys/socket.h> +#include "absl/cleanup/cleanup.h" #include "quic/platform/api/quic_bug_tracker.h" #include "quic/platform/api/quic_logging.h" #include "quic/qbone/platform/kernel_interface.h" @@ -39,7 +40,7 @@ TunDevice::~TunDevice() { if (!persist_) { Down(); } - CleanUpFileDescriptor(); + CloseDevice(); } bool TunDevice::Init() { @@ -63,39 +64,33 @@ bool TunDevice::Init() { // TODO(pengg): might be better to use netlink socket, once we have a library to // use bool TunDevice::Up() { - if (setup_tun_ && !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 { + if (!setup_tun_) { return true; } + 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; + + return NetdeviceIoctl(SIOCSIFFLAGS, reinterpret_cast<void*>(&if_request)); } // TODO(pengg): might be better to use netlink socket, once we have a library to // use bool TunDevice::Down() { - if (setup_tun_ && 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 { + if (!setup_tun_) { return true; } + 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; + + return NetdeviceIoctl(SIOCSIFFLAGS, reinterpret_cast<void*>(&if_request)); } int TunDevice::GetFileDescriptor() const { @@ -103,6 +98,10 @@ int TunDevice::GetFileDescriptor() const { } bool TunDevice::OpenDevice() { + if (file_descriptor_ != kInvalidFd) { + CloseDevice(); + } + 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 @@ -116,39 +115,41 @@ bool TunDevice::OpenDevice() { // '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. + bool successfully_opened = false; + auto cleanup = absl::MakeCleanup([this, &successfully_opened]() { + if (!successfully_opened) { + CloseDevice(); + } + }); + const std::string tun_device_path = absl::GetFlag(FLAGS_qbone_client_tun_device_path); int fd = kernel_.open(tun_device_path.c_str(), O_RDWR); if (fd < 0) { QUIC_PLOG(WARNING) << "Failed to open " << tun_device_path; - CleanUpFileDescriptor(); - return false; + return successfully_opened; } file_descriptor_ = fd; if (!CheckFeatures(fd)) { - CleanUpFileDescriptor(); - return false; + return successfully_opened; } if (kernel_.ioctl(fd, TUNSETIFF, reinterpret_cast<void*>(&if_request)) != 0) { QUIC_PLOG(WARNING) << "Failed to TUNSETIFF on fd(" << fd << ")"; - CleanUpFileDescriptor(); - return false; + return successfully_opened; } 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 successfully_opened; } - return true; + successfully_opened = true; + return successfully_opened; } // TODO(pengg): might be better to use netlink socket, once we have a library to @@ -166,7 +167,7 @@ bool TunDevice::ConfigureInterface() { if_request.ifr_mtu = mtu_; if (!NetdeviceIoctl(SIOCSIFMTU, reinterpret_cast<void*>(&if_request))) { - CleanUpFileDescriptor(); + CloseDevice(); return false; } @@ -206,7 +207,7 @@ bool TunDevice::NetdeviceIoctl(int request, void* argp) { return true; } -void TunDevice::CleanUpFileDescriptor() { +void TunDevice::CloseDevice() { if (file_descriptor_ != kInvalidFd) { kernel_.close(file_descriptor_); file_descriptor_ = kInvalidFd; diff --git a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device.h b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device.h index bff85f5943a..129e1d121c6 100644 --- a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device.h +++ b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device.h @@ -49,6 +49,11 @@ class TunDevice : public TunDeviceInterface { // Marks the interface down to stop receiving packets. bool Down() override; + // Closes the open file descriptor for the TUN device (if one exists). + // It is safe to reinitialize and reuse this TunDevice after calling + // CloseDevice. + void CloseDevice() 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; @@ -63,10 +68,6 @@ class TunDevice : public TunDeviceInterface { // 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); @@ -76,7 +77,6 @@ class TunDevice : public TunDeviceInterface { const bool setup_tun_; int file_descriptor_; KernelInterface& kernel_; - bool is_interface_up_ = false; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_interface.h b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_interface.h index e99c547ee7c..3c6f9624960 100644 --- a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_interface.h +++ b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_interface.h @@ -12,7 +12,7 @@ namespace quic { // An interface with methods for interacting with a TUN device. class TunDeviceInterface { public: - virtual ~TunDeviceInterface() {} + virtual ~TunDeviceInterface() = default; // Actually creates/reopens and configures the device. virtual bool Init() = 0; @@ -23,6 +23,11 @@ class TunDeviceInterface { // Marks the interface down to stop receiving packets. virtual bool Down() = 0; + // Closes the open file descriptor for the TUN device (if one exists). + // It is safe to reinitialize and reuse this TunDevice after calling + // CloseDevice. + virtual void CloseDevice() = 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; diff --git a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger.cc b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger.cc index 21196716760..4783e9cc9c3 100644 --- a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger.cc +++ b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger.cc @@ -11,14 +11,12 @@ 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) {} @@ -78,8 +76,8 @@ std::unique_ptr<QuicData> TunDevicePacketExchanger::ReadPacket( return std::make_unique<QuicData>(read_buffer.release(), result, true); } -int TunDevicePacketExchanger::file_descriptor() const { - return fd_; +void TunDevicePacketExchanger::set_file_descriptor(int fd) { + fd_ = fd; } const TunDevicePacketExchanger::StatsInterface* diff --git a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger.h b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger.h index 1d28fee1dbc..115f5b580c6 100644 --- a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger.h +++ b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger.h @@ -35,8 +35,6 @@ class TunDevicePacketExchanger : public QbonePacketExchanger { ABSL_MUST_USE_RESULT virtual int64_t PacketsWritten() const = 0; }; - // |fd| is a open file descriptor on a TUN device that's opened for both read - // 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. @@ -44,14 +42,13 @@ class TunDevicePacketExchanger : public QbonePacketExchanger { // the TUN device become blocked. // |stats| is notified about packet read/write statistics. It is not owned, // but should outlive objects of this class. - TunDevicePacketExchanger(int fd, - size_t mtu, + TunDevicePacketExchanger(size_t mtu, KernelInterface* kernel, QbonePacketExchanger::Visitor* visitor, size_t max_pending_packets, StatsInterface* stats); - ABSL_MUST_USE_RESULT int file_descriptor() const; + void set_file_descriptor(int fd); ABSL_MUST_USE_RESULT const StatsInterface* stats_interface() const; diff --git a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger_test.cc b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger_test.cc index 4a00c60eb78..c8f3ff0c861 100644 --- a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger_test.cc +++ b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_packet_exchanger_test.cc @@ -30,14 +30,15 @@ class MockVisitor : public QbonePacketExchanger::Visitor { class TunDevicePacketExchangerTest : public QuicTest { protected: TunDevicePacketExchangerTest() - : exchanger_(kFd, - kMtu, + : exchanger_(kMtu, &mock_kernel_, &mock_visitor_, kMaxPendingPackets, - &mock_stats_) {} + &mock_stats_) { + exchanger_.set_file_descriptor(kFd); + } - ~TunDevicePacketExchangerTest() override {} + ~TunDevicePacketExchangerTest() override = default; MockKernel mock_kernel_; StrictMock<MockVisitor> mock_visitor_; diff --git a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_test.cc b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_test.cc index 9c216afe258..6a02f07062e 100644 --- a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_test.cc +++ b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/tun_device_test.cc @@ -139,6 +139,7 @@ TEST_F(TunDeviceTest, FailToOpenTunDevice) { TunDevice tun_device(kDeviceName, 1500, false, true, &mock_kernel_); EXPECT_FALSE(tun_device.Init()); EXPECT_EQ(tun_device.GetFileDescriptor(), -1); + ExpectDown(false); } TEST_F(TunDeviceTest, FailToCheckFeature) { @@ -147,6 +148,7 @@ TEST_F(TunDeviceTest, FailToCheckFeature) { TunDevice tun_device(kDeviceName, 1500, false, true, &mock_kernel_); EXPECT_FALSE(tun_device.Init()); EXPECT_EQ(tun_device.GetFileDescriptor(), -1); + ExpectDown(false); } TEST_F(TunDeviceTest, TooFewFeature) { @@ -160,6 +162,7 @@ TEST_F(TunDeviceTest, TooFewFeature) { TunDevice tun_device(kDeviceName, 1500, false, true, &mock_kernel_); EXPECT_FALSE(tun_device.Init()); EXPECT_EQ(tun_device.GetFileDescriptor(), -1); + ExpectDown(false); } TEST_F(TunDeviceTest, FailToSetFlag) { diff --git a/chromium/net/third_party/quiche/src/quic/qbone/platform/icmp_packet_test.cc b/chromium/net/third_party/quiche/src/quic/qbone/platform/icmp_packet_test.cc index 857cada50a6..9721e36aa40 100644 --- a/chromium/net/third_party/quiche/src/quic/qbone/platform/icmp_packet_test.cc +++ b/chromium/net/third_party/quiche/src/quic/qbone/platform/icmp_packet_test.cc @@ -10,7 +10,7 @@ #include "absl/strings/string_view.h" #include "quic/platform/api/quic_test.h" -#include "common/platform/api/quiche_text_utils.h" +#include "common/quiche_text_utils.h" namespace quic { namespace { 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 index df107d63c2f..9da9cb83603 100644 --- 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 @@ -10,7 +10,7 @@ #include "absl/strings/string_view.h" #include "quic/platform/api/quic_test.h" -#include "common/platform/api/quiche_text_utils.h" +#include "common/quiche_text_utils.h" namespace quic { namespace { diff --git a/chromium/net/third_party/quiche/src/quic/qbone/qbone_session_test.cc b/chromium/net/third_party/quiche/src/quic/qbone/qbone_session_test.cc index f0d9d16059e..fb9a288cbeb 100644 --- a/chromium/net/third_party/quiche/src/quic/qbone/qbone_session_test.cc +++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_session_test.cc @@ -23,7 +23,6 @@ #include "quic/test_tools/quic_connection_peer.h" #include "quic/test_tools/quic_session_peer.h" #include "quic/test_tools/quic_test_utils.h" -#include "common/platform/api/quiche_text_utils.h" namespace quic { namespace test { diff --git a/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_client_session.h b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_client_session.h index 6f6d091d71a..ad29a150b58 100644 --- a/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_client_session.h +++ b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_client_session.h @@ -152,8 +152,10 @@ class QUIC_EXPORT_PRIVATE QuicTransportClientSession // has not accepted to a smaller number, by checking the size of // |incoming_bidirectional_streams_| and |incoming_unidirectional_streams_| // before sending MAX_STREAMS. - QuicCircularDeque<QuicTransportStream*> incoming_bidirectional_streams_; - QuicCircularDeque<QuicTransportStream*> incoming_unidirectional_streams_; + quiche::QuicheCircularDeque<QuicTransportStream*> + incoming_bidirectional_streams_; + quiche::QuicheCircularDeque<QuicTransportStream*> + incoming_unidirectional_streams_; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_server_session_test.cc b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_server_session_test.cc index c58e658591b..159f8864fd8 100644 --- a/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_server_session_test.cc +++ b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_server_session_test.cc @@ -21,7 +21,7 @@ #include "quic/test_tools/crypto_test_utils.h" #include "quic/test_tools/quic_test_utils.h" #include "quic/test_tools/quic_transport_test_tools.h" -#include "common/platform/api/quiche_text_utils.h" +#include "common/quiche_text_utils.h" namespace quic { namespace test { diff --git a/chromium/net/third_party/quiche/src/quic/quic_transport/web_transport_fingerprint_proof_verifier.cc b/chromium/net/third_party/quiche/src/quic/quic_transport/web_transport_fingerprint_proof_verifier.cc index cbe55453af2..7e43341b543 100644 --- a/chromium/net/third_party/quiche/src/quic/quic_transport/web_transport_fingerprint_proof_verifier.cc +++ b/chromium/net/third_party/quiche/src/quic/quic_transport/web_transport_fingerprint_proof_verifier.cc @@ -14,7 +14,7 @@ #include "quic/core/quic_time.h" #include "quic/core/quic_types.h" #include "quic/platform/api/quic_bug_tracker.h" -#include "common/platform/api/quiche_text_utils.h" +#include "common/quiche_text_utils.h" namespace quic { namespace { 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 968b4140451..00264e59a09 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 @@ -40,7 +40,6 @@ #include "quic/test_tools/quic_stream_peer.h" #include "quic/test_tools/quic_test_utils.h" #include "quic/test_tools/simple_quic_framer.h" -#include "common/platform/api/quiche_text_utils.h" #include "common/test_tools/quiche_test_utils.h" namespace quic { @@ -760,6 +759,12 @@ void MovePackets(PacketSavingConnection* source_conn, continue; } QuicConnectionPeer::SwapCrypters(dest_conn, framer.framer()); + + // Install a packet flusher such that the packets generated by |dest_conn| + // in response to this packet are more likely to be coalesced and/or batched + // in the writer. + QuicConnection::ScopedPacketFlusher flusher(dest_conn); + dest_conn->OnDecryptedPacket( source_conn->encrypted_packets_[index]->length(), framer.last_decrypted_level()); diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/crypto_test_utils_test.cc b/chromium/net/third_party/quiche/src/quic/test_tools/crypto_test_utils_test.cc index ce45b827551..b1f21158d91 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/crypto_test_utils_test.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/crypto_test_utils_test.cc @@ -12,7 +12,6 @@ #include "quic/core/quic_utils.h" #include "quic/platform/api/quic_test.h" #include "quic/test_tools/mock_clock.h" -#include "common/platform/api/quiche_text_utils.h" namespace quic { namespace test { diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/fake_proof_source_handle.cc b/chromium/net/third_party/quiche/src/quic/test_tools/fake_proof_source_handle.cc index b239f7d140c..b1fedf8c161 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/fake_proof_source_handle.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/fake_proof_source_handle.cc @@ -71,14 +71,16 @@ void FakeProofSourceHandle::CancelPendingOperation() { QuicAsyncStatus FakeProofSourceHandle::SelectCertificate( const QuicSocketAddress& server_address, const QuicSocketAddress& client_address, + absl::string_view ssl_capabilities, const std::string& hostname, absl::string_view client_hello, const std::string& alpn, + absl::optional<std::string> alps, const std::vector<uint8_t>& quic_transport_params, const absl::optional<std::vector<uint8_t>>& early_data_context) { - all_select_cert_args_.push_back( - SelectCertArgs(server_address, client_address, hostname, client_hello, - alpn, quic_transport_params, early_data_context)); + all_select_cert_args_.push_back(SelectCertArgs( + server_address, client_address, ssl_capabilities, hostname, client_hello, + alpn, alps, quic_transport_params, early_data_context)); if (select_cert_action_ == Action::DELEGATE_ASYNC || select_cert_action_ == Action::FAIL_ASYNC) { @@ -86,8 +88,9 @@ QuicAsyncStatus FakeProofSourceHandle::SelectCertificate( all_select_cert_args_.back()); return QUIC_PENDING; } else if (select_cert_action_ == Action::FAIL_SYNC) { - callback()->OnSelectCertificateDone(/*ok=*/false, - /*is_sync=*/true, nullptr); + callback()->OnSelectCertificateDone( + /*ok=*/false, + /*is_sync=*/true, nullptr, /*handshake_hints=*/absl::string_view()); return QUIC_FAILURE; } @@ -96,7 +99,8 @@ QuicAsyncStatus FakeProofSourceHandle::SelectCertificate( delegate_->GetCertChain(server_address, client_address, hostname); bool ok = chain && !chain->certs.empty(); - callback_->OnSelectCertificateDone(ok, /*is_sync=*/true, chain.get()); + callback_->OnSelectCertificateDone(ok, /*is_sync=*/true, chain.get(), + /*handshake_hints=*/absl::string_view()); return ok ? QUIC_SUCCESS : QUIC_FAILURE; } @@ -168,13 +172,15 @@ FakeProofSourceHandle::SelectCertOperation::SelectCertOperation( void FakeProofSourceHandle::SelectCertOperation::Run() { if (action_ == Action::FAIL_ASYNC) { callback_->OnSelectCertificateDone(/*ok=*/false, - /*is_sync=*/false, nullptr); + /*is_sync=*/false, nullptr, + /*handshake_hints=*/absl::string_view()); } else if (action_ == Action::DELEGATE_ASYNC) { QuicReferenceCountedPointer<ProofSource::Chain> chain = delegate_->GetCertChain(args_.server_address, args_.client_address, args_.hostname); bool ok = chain && !chain->certs.empty(); - callback_->OnSelectCertificateDone(ok, /*is_sync=*/false, chain.get()); + callback_->OnSelectCertificateDone(ok, /*is_sync=*/false, chain.get(), + /*handshake_hints=*/absl::string_view()); } else { QUIC_BUG(quic_bug_10139_1) << "Unexpected action: " << static_cast<int>(action_); diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/fake_proof_source_handle.h b/chromium/net/third_party/quiche/src/quic/test_tools/fake_proof_source_handle.h index 9c05ba4fa66..d2b991896f8 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/fake_proof_source_handle.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/fake_proof_source_handle.h @@ -40,9 +40,11 @@ class FakeProofSourceHandle : public ProofSourceHandle { QuicAsyncStatus SelectCertificate( const QuicSocketAddress& server_address, const QuicSocketAddress& client_address, + absl::string_view ssl_capabilities, const std::string& hostname, absl::string_view client_hello, const std::string& alpn, + absl::optional<std::string> alps, const std::vector<uint8_t>& quic_transport_params, const absl::optional<std::vector<uint8_t>>& early_data_context) override; @@ -62,24 +64,30 @@ class FakeProofSourceHandle : public ProofSourceHandle { struct SelectCertArgs { SelectCertArgs(QuicSocketAddress server_address, QuicSocketAddress client_address, + absl::string_view ssl_capabilities, std::string hostname, absl::string_view client_hello, std::string alpn, + absl::optional<std::string> alps, std::vector<uint8_t> quic_transport_params, absl::optional<std::vector<uint8_t>> early_data_context) : server_address(server_address), client_address(client_address), + ssl_capabilities(ssl_capabilities), hostname(hostname), client_hello(client_hello), alpn(alpn), + alps(alps), quic_transport_params(quic_transport_params), early_data_context(early_data_context) {} QuicSocketAddress server_address; QuicSocketAddress client_address; + std::string ssl_capabilities; std::string hostname; std::string client_hello; std::string alpn; + absl::optional<std::string> alps; std::vector<uint8_t> quic_transport_params; absl::optional<std::vector<uint8_t>> early_data_context; }; diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/mock_random.cc b/chromium/net/third_party/quiche/src/quic/test_tools/mock_random.cc index c50c75cf432..a789cdf083b 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/mock_random.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/mock_random.cc @@ -33,5 +33,10 @@ void MockRandom::ChangeValue() { increment_++; } +void MockRandom::ResetBase(uint32_t base) { + base_ = base; + increment_ = 0; +} + } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/mock_random.h b/chromium/net/third_party/quiche/src/quic/test_tools/mock_random.h index 63d438d457e..8dba8601f37 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/mock_random.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/mock_random.h @@ -33,6 +33,9 @@ class MockRandom : public QuicRandom { // |RandUint64| and the byte that |RandBytes| fills with, to change. void ChangeValue(); + // Sets the base to |base| and resets increment to zero. + void ResetBase(uint32_t base); + private: uint32_t base_; uint8_t increment_; diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_encoder_peer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_encoder_peer.cc index b51684fed04..cc5f010c0e1 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_encoder_peer.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_encoder_peer.cc @@ -10,7 +10,7 @@ namespace quic { namespace test { // static -QpackHeaderTable* QpackEncoderPeer::header_table(QpackEncoder* encoder) { +QpackEncoderHeaderTable* QpackEncoderPeer::header_table(QpackEncoder* encoder) { return &encoder->header_table_; } diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_encoder_peer.h b/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_encoder_peer.h index a824276bc4c..94a308af980 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_encoder_peer.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_encoder_peer.h @@ -10,7 +10,7 @@ namespace quic { class QpackEncoder; -class QpackHeaderTable; +class QpackEncoderHeaderTable; namespace test { @@ -18,7 +18,7 @@ class QpackEncoderPeer { public: QpackEncoderPeer() = delete; - static QpackHeaderTable* header_table(QpackEncoder* encoder); + static QpackEncoderHeaderTable* header_table(QpackEncoder* encoder); static uint64_t maximum_blocked_streams(const QpackEncoder* encoder); static uint64_t smallest_blocking_index(const QpackEncoder* encoder); }; diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_header_table_peer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_header_table_peer.cc deleted file mode 100644 index 4dbf09617ed..00000000000 --- a/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_header_table_peer.cc +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "quic/test_tools/qpack/qpack_header_table_peer.h" - -#include "quic/core/qpack/qpack_header_table.h" - -namespace quic { -namespace test { - -// static -uint64_t QpackHeaderTablePeer::dynamic_table_capacity( - const QpackHeaderTable* header_table) { - return header_table->dynamic_table_capacity_; -} - -// static -uint64_t QpackHeaderTablePeer::maximum_dynamic_table_capacity( - const QpackHeaderTable* header_table) { - return header_table->maximum_dynamic_table_capacity_; -} - -} // namespace test -} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_header_table_peer.h b/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_header_table_peer.h deleted file mode 100644 index 19e8d0d64e3..00000000000 --- a/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_header_table_peer.h +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef QUICHE_QUIC_TEST_TOOLS_QPACK_QPACK_HEADER_TABLE_PEER_H_ -#define QUICHE_QUIC_TEST_TOOLS_QPACK_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_QPACK_HEADER_TABLE_PEER_H_ diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_offline_decoder.cc b/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_offline_decoder.cc index 6bad8d6ff65..0f681fef83a 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_offline_decoder.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_offline_decoder.cc @@ -38,7 +38,6 @@ #include "quic/platform/api/quic_file_utils.h" #include "quic/platform/api/quic_logging.h" #include "quic/test_tools/qpack/qpack_test_utils.h" -#include "common/platform/api/quiche_text_utils.h" #include "common/quiche_endian.h" namespace quic { 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 3f1eaeb16bd..71036cb2512 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 @@ -398,7 +398,11 @@ QuicIdleNetworkDetector& QuicConnectionPeer::GetIdleNetworkDetector( void QuicConnectionPeer::SetServerConnectionId( QuicConnection* connection, const QuicConnectionId& server_connection_id) { - connection->server_connection_id_ = server_connection_id; + if (connection->use_connection_id_on_default_path_) { + connection->default_path_.server_connection_id = server_connection_id; + } else { + connection->server_connection_id_ = server_connection_id; + } connection->InstallInitialCrypters(server_connection_id); } @@ -448,6 +452,18 @@ QuicByteCount QuicConnectionPeer::BytesReceivedOnAlternativePath( } // static +QuicConnectionId QuicConnectionPeer::GetClientConnectionIdOnAlternativePath( + const QuicConnection* connection) { + return connection->alternative_path_.client_connection_id; +} + +// static +QuicConnectionId QuicConnectionPeer::GetServerConnectionIdOnAlternativePath( + const QuicConnection* connection) { + return connection->alternative_path_.server_connection_id; +} + +// static bool QuicConnectionPeer::IsAlternativePathValidated( QuicConnection* connection) { return connection->alternative_path_.validated; @@ -478,5 +494,36 @@ void QuicConnectionPeer::ResetPeerIssuedConnectionIdManager( QuicConnection* connection) { connection->peer_issued_cid_manager_ = nullptr; } + +// static +QuicConnection::PathState* QuicConnectionPeer::GetDefaultPath( + QuicConnection* connection) { + return &connection->default_path_; +} + +// static +QuicConnection::PathState* QuicConnectionPeer::GetAlternativePath( + QuicConnection* connection) { + return &connection->alternative_path_; +} + +// static +void QuicConnectionPeer::RetirePeerIssuedConnectionIdsNoLongerOnPath( + QuicConnection* connection) { + connection->RetirePeerIssuedConnectionIdsNoLongerOnPath(); +} + +// static +bool QuicConnectionPeer::HasUnusedPeerIssuedConnectionId( + const QuicConnection* connection) { + return connection->peer_issued_cid_manager_->HasUnusedConnectionId(); +} + +// static +bool QuicConnectionPeer::HasSelfIssuedConnectionIdToConsume( + const QuicConnection* connection) { + return connection->self_issued_cid_manager_->HasConnectionIdToConsume(); +} + } // 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 1de3ae72f0b..cbc829a7a65 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 @@ -182,6 +182,12 @@ class QuicConnectionPeer { static QuicByteCount BytesReceivedOnAlternativePath( QuicConnection* connection); + static QuicConnectionId GetClientConnectionIdOnAlternativePath( + const QuicConnection* connection); + + static QuicConnectionId GetServerConnectionIdOnAlternativePath( + const QuicConnection* connection); + static bool IsAlternativePath(QuicConnection* connection, const QuicSocketAddress& self_address, const QuicSocketAddress& peer_address); @@ -194,6 +200,19 @@ class QuicConnectionPeer { static void EnableMultipleConnectionIdSupport(QuicConnection* connection); static void ResetPeerIssuedConnectionIdManager(QuicConnection* connection); + + static QuicConnection::PathState* GetDefaultPath(QuicConnection* connection); + + static QuicConnection::PathState* GetAlternativePath( + QuicConnection* connection); + + static void RetirePeerIssuedConnectionIdsNoLongerOnPath( + QuicConnection* connection); + + static bool HasUnusedPeerIssuedConnectionId(const QuicConnection* connection); + + static bool HasSelfIssuedConnectionIdToConsume( + const QuicConnection* connection); }; } // namespace test diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_dispatcher_peer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_dispatcher_peer.cc index 3a553ce0838..8002170ad90 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_dispatcher_peer.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_dispatcher_peer.cc @@ -117,31 +117,20 @@ std::string QuicDispatcherPeer::SelectAlpn( // static QuicSession* QuicDispatcherPeer::GetFirstSessionIfAny( QuicDispatcher* dispatcher) { - if (dispatcher->use_reference_counted_session_map()) { - if (dispatcher->reference_counted_session_map_.empty()) { - return nullptr; - } - return dispatcher->reference_counted_session_map_.begin()->second.get(); - } else { - if (dispatcher->session_map_.empty()) { - return nullptr; - } - return dispatcher->session_map_.begin()->second.get(); + if (dispatcher->reference_counted_session_map_.empty()) { + return nullptr; } + return dispatcher->reference_counted_session_map_.begin()->second.get(); } // static const QuicSession* QuicDispatcherPeer::FindSession( const QuicDispatcher* dispatcher, QuicConnectionId id) { - if (dispatcher->use_reference_counted_session_map()) { - auto it = dispatcher->reference_counted_session_map_.find(id); - return (it == dispatcher->reference_counted_session_map_.end()) - ? nullptr - : it->second.get(); - } - auto it = dispatcher->session_map_.find(id); - return (it == dispatcher->session_map_.end()) ? nullptr : it->second.get(); + auto it = dispatcher->reference_counted_session_map_.find(id); + return (it == dispatcher->reference_counted_session_map_.end()) + ? nullptr + : it->second.get(); } } // namespace test diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_packet_creator_peer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_packet_creator_peer.cc index 0caf2635be7..d638959f88b 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_packet_creator_peer.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_packet_creator_peer.cc @@ -156,5 +156,11 @@ QuicFrames& QuicPacketCreatorPeer::QueuedFrames(QuicPacketCreator* creator) { return creator->queued_frames_; } +// static +void QuicPacketCreatorPeer::SetRandom(QuicPacketCreator* creator, + QuicRandom* random) { + creator->random_ = random; +} + } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_packet_creator_peer.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_packet_creator_peer.h index 12f00867244..259191d214b 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_packet_creator_peer.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_packet_creator_peer.h @@ -10,6 +10,7 @@ namespace quic { class QuicFramer; class QuicPacketCreator; +class QuicRandom; namespace test { @@ -61,6 +62,7 @@ class QuicPacketCreatorPeer { static QuicFramer* framer(QuicPacketCreator* creator); static std::string GetRetryToken(QuicPacketCreator* creator); static QuicFrames& QueuedFrames(QuicPacketCreator* creator); + static void SetRandom(QuicPacketCreator* creator, QuicRandom* random); }; } // namespace test diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_backend.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_backend.cc index 9623d752027..eb419b607f5 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_backend.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_backend.cc @@ -9,7 +9,6 @@ #include "absl/strings/string_view.h" #include "quic/core/quic_buffer_allocator.h" -#include "quic/core/quic_circular_deque.h" #include "quic/core/quic_simple_buffer_allocator.h" #include "quic/core/web_transport_interface.h" #include "quic/platform/api/quic_mem_slice.h" @@ -18,95 +17,6 @@ namespace quic { namespace test { -namespace { - -class EchoWebTransportServer : public WebTransportVisitor { - public: - EchoWebTransportServer(WebTransportSession* session) : session_(session) {} - - void OnSessionReady() override { - if (session_->CanOpenNextOutgoingBidirectionalStream()) { - OnCanCreateNewOutgoingBidirectionalStream(); - } - } - - void OnIncomingBidirectionalStreamAvailable() override { - while (true) { - WebTransportStream* stream = - session_->AcceptIncomingBidirectionalStream(); - if (stream == nullptr) { - return; - } - QUIC_DVLOG(1) << "EchoWebTransportServer received a bidirectional stream " - << stream->GetStreamId(); - stream->SetVisitor( - std::make_unique<WebTransportBidirectionalEchoVisitor>(stream)); - stream->visitor()->OnCanRead(); - } - } - - void OnIncomingUnidirectionalStreamAvailable() override { - while (true) { - WebTransportStream* stream = - session_->AcceptIncomingUnidirectionalStream(); - if (stream == nullptr) { - return; - } - QUIC_DVLOG(1) - << "EchoWebTransportServer received a unidirectional stream"; - stream->SetVisitor( - std::make_unique<WebTransportUnidirectionalEchoReadVisitor>( - stream, [this](const std::string& data) { - streams_to_echo_back_.push_back(data); - TrySendingUnidirectionalStreams(); - })); - stream->visitor()->OnCanRead(); - } - } - - void OnDatagramReceived(absl::string_view datagram) override { - auto buffer = MakeUniqueBuffer(&allocator_, datagram.size()); - memcpy(buffer.get(), datagram.data(), datagram.size()); - QuicMemSlice slice(std::move(buffer), datagram.size()); - session_->SendOrQueueDatagram(std::move(slice)); - } - - void OnCanCreateNewOutgoingBidirectionalStream() override { - if (!echo_stream_opened_) { - WebTransportStream* stream = session_->OpenOutgoingBidirectionalStream(); - stream->SetVisitor( - std::make_unique<WebTransportBidirectionalEchoVisitor>(stream)); - echo_stream_opened_ = true; - } - } - void OnCanCreateNewOutgoingUnidirectionalStream() override { - TrySendingUnidirectionalStreams(); - } - - void TrySendingUnidirectionalStreams() { - while (!streams_to_echo_back_.empty() && - session_->CanOpenNextOutgoingUnidirectionalStream()) { - QUIC_DVLOG(1) - << "EchoWebTransportServer echoed a unidirectional stream back"; - WebTransportStream* stream = session_->OpenOutgoingUnidirectionalStream(); - stream->SetVisitor( - std::make_unique<WebTransportUnidirectionalEchoWriteVisitor>( - stream, streams_to_echo_back_.front())); - streams_to_echo_back_.pop_front(); - stream->visitor()->OnCanWrite(); - } - } - - private: - WebTransportSession* session_; - SimpleBufferAllocator allocator_; - bool echo_stream_opened_ = false; - - QuicCircularDeque<std::string> streams_to_echo_back_; -}; - -} // namespace - QuicSimpleServerBackend::WebTransportResponse QuicTestBackend::ProcessWebTransportRequest( const spdy::Http2HeaderBlock& request_headers, @@ -126,7 +36,8 @@ QuicTestBackend::ProcessWebTransportRequest( if (path == "/echo") { WebTransportResponse response; response.response_headers[":status"] = "200"; - response.visitor = std::make_unique<EchoWebTransportServer>(session); + response.visitor = + std::make_unique<EchoWebTransportSessionVisitor>(session); return response; } 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 ed823b1e156..7cc3ff9be3b 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 @@ -28,7 +28,7 @@ #include "quic/test_tools/quic_spdy_stream_peer.h" #include "quic/test_tools/quic_test_utils.h" #include "quic/tools/quic_url.h" -#include "common/platform/api/quiche_text_utils.h" +#include "common/quiche_text_utils.h" namespace quic { namespace test { 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 2f16b1e072b..9fbffe0b76c 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 @@ -929,10 +929,6 @@ class MockQuicSession : public QuicSession { (override)); MOCK_METHOD(bool, ShouldKeepConnectionAlive, (), (const, override)); - MOCK_METHOD(void, - SendStopSending, - (QuicRstStreamErrorCode code, QuicStreamId stream_id), - (override)); MOCK_METHOD(std::vector<std::string>, GetAlpnsToOffer, (), (const, override)); MOCK_METHOD(std::vector<absl::string_view>::const_iterator, SelectAlpn, diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_time_wait_list_manager_peer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_time_wait_list_manager_peer.cc index 9d60443deb2..8f614e8d89d 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_time_wait_list_manager_peer.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_time_wait_list_manager_peer.cc @@ -28,5 +28,13 @@ void QuicTimeWaitListManagerPeer::set_clock(QuicTimeWaitListManager* manager, manager->clock_ = clock; } +// static +bool QuicTimeWaitListManagerPeer::SendOrQueuePacket( + QuicTimeWaitListManager* manager, + std::unique_ptr<QuicTimeWaitListManager::QueuedPacket> packet, + const QuicPerPacketContext* packet_context) { + return manager->SendOrQueuePacket(std::move(packet), packet_context); +} + } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_time_wait_list_manager_peer.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_time_wait_list_manager_peer.h index 54fd6dd1768..4e0a4a707ad 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_time_wait_list_manager_peer.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_time_wait_list_manager_peer.h @@ -21,6 +21,11 @@ class QuicTimeWaitListManagerPeer { static void set_clock(QuicTimeWaitListManager* manager, const QuicClock* clock); + + static bool SendOrQueuePacket( + QuicTimeWaitListManager* manager, + std::unique_ptr<QuicTimeWaitListManager::QueuedPacket> packet, + const QuicPerPacketContext* packet_context); }; } // namespace test diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/server_thread.cc b/chromium/net/third_party/quiche/src/quic/test_tools/server_thread.cc index f5c9b7e0725..f931567793e 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/server_thread.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/server_thread.cc @@ -126,7 +126,7 @@ void ServerThread::MaybeNotifyOfHandshakeConfirmation() { } void ServerThread::ExecuteScheduledActions() { - QuicCircularDeque<std::function<void()>> actions; + quiche::QuicheCircularDeque<std::function<void()>> actions; { QuicWriterMutexLock lock(&scheduled_actions_lock_); actions.swap(scheduled_actions_); 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 fa604a8bf77..81d0bf2a5f5 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 @@ -86,7 +86,7 @@ class ServerThread : public QuicThread { bool initialized_; QuicMutex scheduled_actions_lock_; - QuicCircularDeque<std::function<void()>> scheduled_actions_ + quiche::QuicheCircularDeque<std::function<void()>> scheduled_actions_ QUIC_GUARDED_BY(scheduled_actions_lock_); }; diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simple_data_producer.h b/chromium/net/third_party/quiche/src/quic/test_tools/simple_data_producer.h index 82021e1e1a1..8111c1cc09f 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/simple_data_producer.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/simple_data_producer.h @@ -49,23 +49,13 @@ class SimpleDataProducer : public QuicStreamFrameDataProducer { QuicByteCount data_length, QuicDataWriter* writer) override; - // TODO(wub): Allow QuicDefaultHasher to accept a pair. Then remove this. - class PairHash { - public: - template <class T1, class T2> - size_t operator()(const std::pair<T1, T2>& pair) const { - return std::hash<T1>()(pair.first) ^ std::hash<T2>()(pair.second); - } - }; - private: using SendBufferMap = absl::flat_hash_map<QuicStreamId, std::unique_ptr<QuicStreamSendBuffer>>; using CryptoBufferMap = absl::flat_hash_map<std::pair<EncryptionLevel, QuicStreamOffset>, - absl::string_view, - PairHash>; + absl::string_view>; SimpleBufferAllocator allocator_; 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 2219c27d1a4..bc76ddc877a 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 @@ -6,10 +6,10 @@ #define QUICHE_QUIC_TEST_TOOLS_SIMPLE_SESSION_NOTIFIER_H_ #include "absl/container/flat_hash_map.h" -#include "quic/core/quic_circular_deque.h" #include "quic/core/quic_interval_set.h" #include "quic/core/session_notifier_interface.h" #include "quic/platform/api/quic_test.h" +#include "common/quiche_circular_deque.h" namespace quic { @@ -132,7 +132,7 @@ class SimpleSessionNotifier : public SessionNotifierInterface { bool StreamHasBufferedData(QuicStreamId id) const; - QuicCircularDeque<QuicFrame> control_frames_; + quiche::QuicheCircularDeque<QuicFrame> control_frames_; QuicLinkedHashMap<QuicControlFrameId, bool> lost_control_frames_; diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/link.h b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/link.h index 7d2f92dfdc4..5d723859e0c 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/link.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/link.h @@ -9,9 +9,9 @@ #include "quic/core/crypto/quic_random.h" #include "quic/core/quic_bandwidth.h" -#include "quic/core/quic_circular_deque.h" #include "quic/test_tools/simulator/actor.h" #include "quic/test_tools/simulator/port.h" +#include "common/quiche_circular_deque.h" namespace quic { namespace simulator { @@ -61,7 +61,7 @@ class OneWayLink : public Actor, public ConstrainedPortInterface { void ScheduleNextPacketDeparture(); UnconstrainedPortInterface* sink_; - QuicCircularDeque<QueuedPacket> packets_in_transit_; + quiche::QuicheCircularDeque<QueuedPacket> packets_in_transit_; QuicBandwidth bandwidth_; const QuicTime::Delta propagation_delay_; diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/queue.h b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/queue.h index 943b8b069a0..7e4be833690 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/queue.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/queue.h @@ -6,8 +6,8 @@ #define QUICHE_QUIC_TEST_TOOLS_SIMULATOR_QUEUE_H_ #include "quic/core/quic_alarm.h" -#include "quic/core/quic_circular_deque.h" #include "quic/test_tools/simulator/link.h" +#include "common/quiche_circular_deque.h" namespace quic { namespace simulator { @@ -110,7 +110,7 @@ class Queue : public Actor, public UnconstrainedPortInterface { std::unique_ptr<QuicAlarm> aggregation_timeout_alarm_; ConstrainedPortInterface* tx_port_; - QuicCircularDeque<EnqueuedPacket> queue_; + quiche::QuicheCircularDeque<EnqueuedPacket> queue_; ListenerInterface* listener_; }; diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/switch.h b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/switch.h index bd4e7b619d7..eebb47cba03 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/switch.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/switch.h @@ -78,7 +78,7 @@ class Switch { void DispatchPacket(SwitchPortNumber port_number, std::unique_ptr<Packet> packet); - // This can not be a QuicCircularDeque since pointers into this are + // This cannot be a quiche::QuicheCircularDeque since pointers into this are // assumed to be stable. std::deque<Port> ports_; absl::flat_hash_map<std::string, Port*> switching_table_; diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_backend_response.h b/chromium/net/third_party/quiche/src/quic/tools/quic_backend_response.h index 1c5cad87112..64d7ade08f8 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_backend_response.h +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_backend_response.h @@ -17,6 +17,7 @@ class QuicBackendResponse { public: // A ServerPushInfo contains path of the push request and everything needed in // comprising a response for the push request. + // TODO(b/171463363): Remove. struct ServerPushInfo { ServerPushInfo(QuicUrl request_url, spdy::Http2HeaderBlock headers, diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.cc index 7077f16506e..53c6800a2e5 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.cc +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.cc @@ -64,6 +64,7 @@ class QuicClientSocketMigrationValidationResultDelegate std::unique_ptr<QuicPathValidationContext> context) override { QUIC_LOG(WARNING) << "Fail to validate path " << *context << ", stop migrating."; + client_->session()->connection()->OnPathValidationFailureAtClient(); } private: @@ -257,6 +258,8 @@ bool QuicClientBase::MigrateSocketWithSpecifiedPort( const QuicIpAddress& new_host, int port) { if (!connected()) { + QUICHE_DVLOG(1) + << "MigrateSocketWithSpecifiedPort failed as connection has closed"; return false; } @@ -264,11 +267,17 @@ bool QuicClientBase::MigrateSocketWithSpecifiedPort( std::unique_ptr<QuicPacketWriter> writer = CreateWriterForNewNetwork(new_host, port); if (writer == nullptr) { + QUICHE_DVLOG(1) + << "MigrateSocketWithSpecifiedPort failed from writer creation"; + return false; + } + if (!session()->MigratePath(network_helper_->GetLatestClientAddress(), + session()->connection()->peer_address(), + writer.get(), false)) { + QUICHE_DVLOG(1) + << "MigrateSocketWithSpecifiedPort failed from session()->MigratePath"; return false; } - session()->MigratePath(network_helper_->GetLatestClientAddress(), - session()->connection()->peer_address(), writer.get(), - false); set_writer(writer.release()); return true; } @@ -465,6 +474,7 @@ class ValidationResultDelegate : public QuicPathValidator::ResultDelegate { std::unique_ptr<QuicPathValidationContext> context) override { QUIC_LOG(WARNING) << "Fail to validate path " << *context << ", stop migrating."; + client_->session()->connection()->OnPathValidationFailureAtClient(); } private: diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_client_epoll_network_helper.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_client_epoll_network_helper.cc index 2049f15f217..9dcc2b35213 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_client_epoll_network_helper.cc +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_client_epoll_network_helper.cc @@ -74,8 +74,25 @@ bool QuicClientEpollNetworkHelper::CreateUDPSocketAndBind( client_address = QuicSocketAddress(QuicIpAddress::Any6(), bind_to_port); } + // Some platforms expect that the addrlen given to bind() exactly matches the + // size of the associated protocol family's sockaddr struct. + // TODO(b/179430548): Revert this when affected platforms are updated to + // to support binding with an addrelen of sizeof(sockaddr_storage) + socklen_t addrlen; + switch (client_address.host().address_family()) { + case IpAddressFamily::IP_V4: + addrlen = sizeof(sockaddr_in); + break; + case IpAddressFamily::IP_V6: + addrlen = sizeof(sockaddr_in6); + break; + case IpAddressFamily::IP_UNSPEC: + addrlen = 0; + break; + } + sockaddr_storage addr = client_address.generic_address(); - int rc = bind(fd, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)); + int rc = bind(fd, reinterpret_cast<sockaddr*>(&addr), addrlen); if (rc < 0) { QUIC_LOG(ERROR) << "Bind failed: " << strerror(errno) << " bind_to_address:" << bind_to_address 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 160f2553142..d932a7b533a 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 @@ -18,7 +18,7 @@ #include "quic/platform/api/quic_test_loopback.h" #include "quic/test_tools/crypto_test_utils.h" #include "quic/test_tools/quic_client_peer.h" -#include "common/platform/api/quiche_text_utils.h" +#include "common/quiche_text_utils.h" namespace quic { namespace test { 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 84830382f48..1fff089445b 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 @@ -24,7 +24,8 @@ std::unique_ptr<QuicSpdyClientBase> QuicEpollClientFactory::CreateClient( uint16_t port, ParsedQuicVersionVector versions, const QuicConfig& config, - std::unique_ptr<ProofVerifier> verifier) { + std::unique_ptr<ProofVerifier> verifier, + std::unique_ptr<SessionCache> session_cache) { QuicSocketAddress addr = tools::LookupAddress( address_family_for_lookup, host_for_lookup, absl::StrCat(port)); if (!addr.IsInitialized()) { @@ -34,7 +35,7 @@ std::unique_ptr<QuicSpdyClientBase> QuicEpollClientFactory::CreateClient( QuicServerId server_id(host_for_handshake, port, false); return std::make_unique<QuicClient>(addr, server_id, versions, config, &epoll_server_, std::move(verifier), - nullptr); + std::move(session_cache)); } } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.h b/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.h index e23eb634ea8..9e78b473619 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.h +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.h @@ -20,7 +20,8 @@ class QuicEpollClientFactory : public QuicToyClient::ClientFactory { uint16_t port, ParsedQuicVersionVector versions, const QuicConfig& config, - std::unique_ptr<ProofVerifier> verifier) override; + std::unique_ptr<ProofVerifier> verifier, + std::unique_ptr<SessionCache> session_cache) override; private: QuicEpollServer epoll_server_; diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.cc index e76a6cffb3c..de2064831f4 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.cc +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.cc @@ -15,7 +15,8 @@ #include "quic/platform/api/quic_file_utils.h" #include "quic/platform/api/quic_logging.h" #include "quic/platform/api/quic_map_util.h" -#include "common/platform/api/quiche_text_utils.h" +#include "quic/tools/web_transport_test_visitors.h" +#include "common/quiche_text_utils.h" using spdy::Http2HeaderBlock; using spdy::kV3LowestPriority; @@ -313,6 +314,10 @@ void QuicMemoryCacheBackend::GenerateDynamicResponses() { QuicBackendResponse::GENERATE_BYTES); } +void QuicMemoryCacheBackend::EnableWebTransport() { + enable_webtransport_ = true; +} + bool QuicMemoryCacheBackend::IsBackendInitialized() const { return cache_initialized_; } @@ -336,11 +341,10 @@ void QuicMemoryCacheBackend::FetchResponseFromBackend( if (path != request_headers.end()) { request_url += std::string(path->second); } - std::list<ServerPushInfo> resources = GetServerPushResources(request_url); QUIC_DVLOG(1) << "Fetching QUIC response from backend in-memory cache for url " << request_url; - quic_stream->OnResponseBackendComplete(quic_response, resources); + quic_stream->OnResponseBackendComplete(quic_response); } // The memory cache does not have a per-stream handler @@ -361,6 +365,35 @@ std::list<ServerPushInfo> QuicMemoryCacheBackend::GetServerPushResources( return resources; } +QuicMemoryCacheBackend::WebTransportResponse +QuicMemoryCacheBackend::ProcessWebTransportRequest( + const spdy::Http2HeaderBlock& request_headers, + WebTransportSession* session) { + if (!SupportsWebTransport()) { + return QuicSimpleServerBackend::ProcessWebTransportRequest(request_headers, + session); + } + + auto path_it = request_headers.find(":path"); + if (path_it == request_headers.end()) { + WebTransportResponse response; + response.response_headers[":status"] = "400"; + return response; + } + absl::string_view path = path_it->second; + if (path == "/echo") { + WebTransportResponse response; + response.response_headers[":status"] = "200"; + response.visitor = + std::make_unique<EchoWebTransportSessionVisitor>(session); + return response; + } + + WebTransportResponse response; + response.response_headers[":status"] = "404"; + return response; +} + QuicMemoryCacheBackend::~QuicMemoryCacheBackend() { { QuicWriterMutexLock lock(&response_mutex_); 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 8ba6d605218..b8d28103ced 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 @@ -90,6 +90,7 @@ class QuicMemoryCacheBackend : public QuicSimpleServerBackend { // some server push resources(resource path, corresponding response status and // path) associated with it. // Push resource implicitly come from the same host. + // TODO(b/171463363): Remove. void AddSimpleResponseWithServerPushResources( absl::string_view host, absl::string_view path, @@ -139,7 +140,10 @@ class QuicMemoryCacheBackend : public QuicSimpleServerBackend { // generated response of that many bytes. void GenerateDynamicResponses(); + void EnableWebTransport(); + // Find all the server push resources associated with |request_url|. + // TODO(b/171463363): Remove. std::list<QuicBackendResponse::ServerPushInfo> GetServerPushResources( std::string request_url); @@ -153,6 +157,10 @@ class QuicMemoryCacheBackend : public QuicSimpleServerBackend { QuicSimpleServerBackend::RequestHandler* quic_server_stream) override; void CloseBackendResponseStream( QuicSimpleServerBackend::RequestHandler* quic_server_stream) override; + WebTransportResponse ProcessWebTransportRequest( + const spdy::Http2HeaderBlock& request_headers, + WebTransportSession* session) override; + bool SupportsWebTransport() override { return enable_webtransport_; } private: void AddResponseImpl(absl::string_view host, @@ -167,6 +175,7 @@ class QuicMemoryCacheBackend : public QuicSimpleServerBackend { // Add some server push urls with given responses for specified // request if these push resources are not associated with this request yet. + // TODO(b/171463363): Remove. void MaybeAddServerPushResources( absl::string_view request_host, absl::string_view request_path, @@ -174,6 +183,7 @@ class QuicMemoryCacheBackend : public QuicSimpleServerBackend { // Check if push resource(push_host/push_path) associated with given request // url already exists in server push map. + // TODO(b/171463363): Remove. bool PushResourceExistsInCache(std::string original_request_url, QuicBackendResponse::ServerPushInfo resource); @@ -190,6 +200,7 @@ class QuicMemoryCacheBackend : public QuicSimpleServerBackend { QUIC_GUARDED_BY(response_mutex_); // A map from request URL to associated server push responses (if any). + // TODO(b/171463363): Remove. std::multimap<std::string, QuicBackendResponse::ServerPushInfo> server_push_resources_ QUIC_GUARDED_BY(response_mutex_); @@ -197,6 +208,8 @@ class QuicMemoryCacheBackend : public QuicSimpleServerBackend { // server threads accessing those responses. mutable QuicMutex response_mutex_; bool cache_initialized_; + + bool enable_webtransport_ = false; }; } // namespace quic 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 97ca71e9c6f..ad357e9b43c 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 @@ -34,7 +34,7 @@ #include "quic/core/quic_types.h" #include "quic/core/quic_utils.h" #include "quic/platform/api/quic_flags.h" -#include "common/platform/api/quiche_text_utils.h" +#include "common/quiche_text_utils.h" DEFINE_QUIC_COMMAND_LINE_FLAG(std::string, quic_version, diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_reject_reason_decoder_bin.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_reject_reason_decoder_bin.cc index aecc8fe1fdf..68443f37d1a 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_reject_reason_decoder_bin.cc +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_reject_reason_decoder_bin.cc @@ -11,7 +11,7 @@ #include "quic/core/crypto/crypto_handshake.h" #include "quic/core/crypto/crypto_utils.h" #include "quic/platform/api/quic_flags.h" -#include "common/platform/api/quiche_text_utils.h" +#include "common/quiche_text_utils.h" using quic::CryptoUtils; using quic::HandshakeFailureReason; diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_backend.h b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_backend.h index 43ced4bcefb..6411567fc1a 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_backend.h +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_backend.h @@ -32,8 +32,7 @@ class QuicSimpleServerBackend { // Called when the response is ready at the backend and can be send back to // the QUIC client. virtual void OnResponseBackendComplete( - const QuicBackendResponse* response, - std::list<QuicBackendResponse::ServerPushInfo> resources) = 0; + const QuicBackendResponse* response) = 0; }; struct WebTransportResponse { 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 4075d3ff417..688ca9ff24b 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 @@ -62,39 +62,6 @@ void QuicSimpleServerSession::OnStreamFrame(const QuicStreamFrame& frame) { QuicSpdySession::OnStreamFrame(frame); } -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::Http2HeaderBlock& original_request_headers) { - if (!server_push_enabled()) { - return; - } - - for (const QuicBackendResponse::ServerPushInfo& resource : resources) { - spdy::Http2HeaderBlock headers = SynthesizePushRequestHeaders( - request_url, resource, original_request_headers); - // TODO(b/136295430): Use sequential push IDs for IETF QUIC. - auto new_highest_promised_stream_id = - highest_promised_stream_id_ + - QuicUtils::StreamIdDelta(transport_version()); - if (VersionUsesHttp3(transport_version()) && - !CanCreatePushStreamWithId(new_highest_promised_stream_id)) { - return; - } - highest_promised_stream_id_ = new_highest_promised_stream_id; - SendPushPromise(original_stream_id, highest_promised_stream_id_, - headers.Clone()); - promised_streams_.push_back( - PromisedStreamInfo(std::move(headers), highest_promised_stream_id_, - spdy::SpdyStreamPrecedence(resource.priority))); - } - - // Procese promised push request as many as possible. - HandlePromisedPushRequests(); -} - QuicSpdyStream* QuicSimpleServerSession::CreateIncomingStream(QuicStreamId id) { if (!ShouldCreateIncomingStream(id)) { return nullptr; 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 b91966da722..2cc3dcf524f 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 @@ -68,17 +68,6 @@ class QuicSimpleServerSession : public QuicServerSessionBase { // Override base class to detact client sending data on server push stream. void OnStreamFrame(const QuicStreamFrame& frame) override; - // Send out PUSH_PROMISE for all |resources| promised stream id in each frame - // will increase by 2 for each item in |resources|. - // And enqueue HEADERS block in those PUSH_PROMISED for sending push response - // later. - virtual void PromisePushResources( - const std::string& request_url, - const std::list<QuicBackendResponse::ServerPushInfo>& resources, - QuicStreamId original_stream_id, - const spdy::SpdyStreamPrecedence& original_precedence, - const spdy::Http2HeaderBlock& original_request_headers); - void OnCanCreateNewOutgoingStream(bool unidirectional) override; protected: @@ -155,7 +144,7 @@ class QuicSimpleServerSession : public QuicServerSessionBase { // the queue also increases by 2 from previous one's. The front element's // stream_id is always next_outgoing_stream_id_, and the last one is always // highest_promised_stream_id_. - QuicCircularDeque<PromisedStreamInfo> promised_streams_; + quiche::QuicheCircularDeque<PromisedStreamInfo> promised_streams_; QuicSimpleServerBackend* quic_simple_server_backend_; // Not owned. }; 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 62bbae949d5..d23ba5d53c4 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 @@ -9,7 +9,6 @@ #include <utility> #include "absl/strings/str_cat.h" -#include "absl/strings/string_view.h" #include "quic/core/crypto/null_encrypter.h" #include "quic/core/crypto/quic_crypto_server_config.h" #include "quic/core/crypto/quic_random.h" @@ -51,10 +50,11 @@ namespace quic { namespace test { namespace { -using PromisedStreamInfo = QuicSimpleServerSession::PromisedStreamInfo; - -const QuicByteCount kHeadersFrameHeaderLength = 2; -const QuicByteCount kHeadersFramePayloadLength = 9; +// Data to be sent on a request stream. In Google QUIC, this is interpreted as +// DATA payload (there is no framing on request streams). In IETF QUIC, this is +// interpreted as HEADERS frame (type 0x1) with payload length 122 ('z'). Since +// no payload is included, QPACK decoder will not be invoked. +const char* const kStreamData = "\1z"; } // namespace @@ -257,7 +257,7 @@ class QuicSimpleServerSessionTest kMaxStreamsForTest); } - ParsedQuicVersionVector supported_versions = SupportedVersions(GetParam()); + ParsedQuicVersionVector supported_versions = SupportedVersions(version()); connection_ = new StrictMock<MockQuicConnectionWithSendStreamData>( &helper_, &alarm_factory_, Perspective::IS_SERVER, supported_versions); connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1)); @@ -289,8 +289,10 @@ class QuicSimpleServerSessionTest transport_version(), n); } + ParsedQuicVersion version() const { return GetParam(); } + QuicTransportVersion transport_version() const { - return GetParam().transport_version; + return version().transport_version; } void InjectStopSending(QuicStreamId stream_id, @@ -330,10 +332,9 @@ INSTANTIATE_TEST_SUITE_P(Tests, ::testing::PrintToStringParamName()); TEST_P(QuicSimpleServerSessionTest, CloseStreamDueToReset) { - // Open a stream, then reset it. - // Send two bytes of payload to open it. + // Send some data open a stream, then reset it. QuicStreamFrame data1(GetNthClientInitiatedBidirectionalId(0), false, 0, - absl::string_view("HT")); + kStreamData); session_->OnStreamFrame(data1); EXPECT_EQ(1u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get())); @@ -388,9 +389,8 @@ TEST_P(QuicSimpleServerSessionTest, NeverOpenStreamDueToReset) { EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get())); - // Send two bytes of payload. QuicStreamFrame data1(GetNthClientInitiatedBidirectionalId(0), false, 0, - absl::string_view("HT")); + kStreamData); session_->OnStreamFrame(data1); // The stream should never be opened, now that the reset is received. @@ -399,11 +399,11 @@ TEST_P(QuicSimpleServerSessionTest, NeverOpenStreamDueToReset) { } TEST_P(QuicSimpleServerSessionTest, AcceptClosedStream) { - // Send (empty) compressed headers followed by two bytes of data. + // Send some data to open two streams. QuicStreamFrame frame1(GetNthClientInitiatedBidirectionalId(0), false, 0, - absl::string_view("\1\0\0\0\0\0\0\0HT")); + kStreamData); QuicStreamFrame frame2(GetNthClientInitiatedBidirectionalId(1), false, 0, - absl::string_view("\3\0\0\0\0\0\0\0HT")); + kStreamData); session_->OnStreamFrame(frame1); session_->OnStreamFrame(frame2); EXPECT_EQ(2u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get())); @@ -431,9 +431,9 @@ TEST_P(QuicSimpleServerSessionTest, AcceptClosedStream) { // past the reset point of stream 3. As it's a closed stream we just drop the // data on the floor, but accept the packet because it has data for stream 5. QuicStreamFrame frame3(GetNthClientInitiatedBidirectionalId(0), false, 2, - absl::string_view("TP")); + kStreamData); QuicStreamFrame frame4(GetNthClientInitiatedBidirectionalId(1), false, 2, - absl::string_view("TP")); + kStreamData); session_->OnStreamFrame(frame3); session_->OnStreamFrame(frame4); // The stream should never be opened, now that the reset is received. @@ -443,7 +443,7 @@ TEST_P(QuicSimpleServerSessionTest, AcceptClosedStream) { TEST_P(QuicSimpleServerSessionTest, CreateIncomingStreamDisconnected) { // EXPECT_QUIC_BUG tests are expensive so only run one instance of them. - if (GetParam() != AllSupportedVersions()[0]) { + if (version() != AllSupportedVersions()[0]) { return; } @@ -467,7 +467,7 @@ TEST_P(QuicSimpleServerSessionTest, CreateIncomingStream) { TEST_P(QuicSimpleServerSessionTest, CreateOutgoingDynamicStreamDisconnected) { // EXPECT_QUIC_BUG tests are expensive so only run one instance of them. - if (GetParam() != AllSupportedVersions()[0]) { + if (version() != AllSupportedVersions()[0]) { return; } @@ -486,7 +486,7 @@ TEST_P(QuicSimpleServerSessionTest, CreateOutgoingDynamicStreamDisconnected) { TEST_P(QuicSimpleServerSessionTest, CreateOutgoingDynamicStreamUnencrypted) { // EXPECT_QUIC_BUG tests are expensive so only run one instance of them. - if (GetParam() != AllSupportedVersions()[0]) { + if (version() != AllSupportedVersions()[0]) { return; } @@ -510,7 +510,7 @@ TEST_P(QuicSimpleServerSessionTest, CreateOutgoingDynamicStreamUptoLimit) { // Receive some data to initiate a incoming stream which should not effect // creating outgoing streams. QuicStreamFrame data1(GetNthClientInitiatedBidirectionalId(0), false, 0, - absl::string_view("HT")); + kStreamData); session_->OnStreamFrame(data1); EXPECT_EQ(1u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get())); EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get()) - @@ -559,7 +559,7 @@ TEST_P(QuicSimpleServerSessionTest, CreateOutgoingDynamicStreamUptoLimit) { // Create peer initiated stream should have no problem. QuicStreamFrame data2(GetNthClientInitiatedBidirectionalId(1), false, 0, - absl::string_view("HT")); + kStreamData); session_->OnStreamFrame(data2); EXPECT_EQ(2u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get()) - /*outcoming=*/kMaxStreamsForTest); @@ -567,7 +567,7 @@ TEST_P(QuicSimpleServerSessionTest, CreateOutgoingDynamicStreamUptoLimit) { TEST_P(QuicSimpleServerSessionTest, OnStreamFrameWithEvenStreamId) { QuicStreamFrame frame(GetNthServerInitiatedUnidirectionalId(0), false, 0, - absl::string_view()); + kStreamData); EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_STREAM_ID, "Client sent data on server push stream", _)); @@ -591,451 +591,6 @@ TEST_P(QuicSimpleServerSessionTest, GetEvenIncomingError) { QuicSessionPeer::GetNumOpenDynamicStreams(session_.get())); } -// In order to test the case where server push stream creation goes beyond -// limit, server push streams need to be hanging there instead of -// immediately closing after sending back response. -// To achieve this goal, this class resets flow control windows so that large -// responses will not be sent fully in order to prevent push streams from being -// closed immediately. -// Also adjust connection-level flow control window to ensure a large response -// can cause stream-level flow control blocked but not connection-level. -class QuicSimpleServerSessionServerPushTest - : public QuicSimpleServerSessionTest { - protected: - const size_t kStreamFlowControlWindowSize = 32 * 1024; // 32KB. - - QuicSimpleServerSessionServerPushTest() { - // Reset stream level flow control window to be 32KB. - if (GetParam().handshake_protocol == PROTOCOL_TLS1_3) { - if (VersionHasIetfQuicFrames(transport_version())) { - QuicConfigPeer::SetReceivedInitialMaxStreamDataBytesUnidirectional( - &config_, kStreamFlowControlWindowSize); - } else { - // In this version, push streams are server-initiated bidirectional - // streams, which are outgoing since we are the server here. - QuicConfigPeer:: - SetReceivedInitialMaxStreamDataBytesOutgoingBidirectional( - &config_, kStreamFlowControlWindowSize); - } - } else { - QuicConfigPeer::SetReceivedInitialStreamFlowControlWindow( - &config_, kStreamFlowControlWindowSize); - } - // Reset connection level flow control window to be 1.5 MB which is large - // enough that it won't block any stream to write before stream level flow - // control blocks it. - QuicConfigPeer::SetReceivedInitialSessionFlowControlWindow( - &config_, kInitialSessionFlowControlWindowForTest); - - ParsedQuicVersionVector supported_versions = SupportedVersions(GetParam()); - connection_ = new StrictMock<MockQuicConnectionWithSendStreamData>( - &helper_, &alarm_factory_, Perspective::IS_SERVER, supported_versions); - connection_->SetEncrypter( - ENCRYPTION_FORWARD_SECURE, - std::make_unique<NullEncrypter>(connection_->perspective())); - session_ = std::make_unique<MockQuicSimpleServerSession>( - config_, connection_, &owner_, &stream_helper_, &crypto_config_, - &compressed_certs_cache_, &memory_cache_backend_); - session_->Initialize(); - // Needed to make new session flow control window and server push work. - - if (VersionHasIetfQuicFrames(transport_version())) { - EXPECT_CALL(*session_, WriteControlFrame(_, _)) - .WillRepeatedly(Invoke(&ClearControlFrameWithTransmissionType)); - } - session_->OnConfigNegotiated(); - - if (!VersionUsesHttp3(transport_version())) { - session_->UnregisterStreamPriority( - QuicUtils::GetHeadersStreamId(transport_version()), - /*is_static=*/true); - } - QuicSimpleServerSessionPeer::SetCryptoStream(session_.get(), nullptr); - // Assume encryption already established. - QuicCryptoServerStreamBase* crypto_stream = - CreateMockCryptoServerStream(&crypto_config_, &compressed_certs_cache_, - session_.get(), &stream_helper_); - - QuicSimpleServerSessionPeer::SetCryptoStream(session_.get(), crypto_stream); - if (!VersionUsesHttp3(transport_version())) { - session_->RegisterStreamPriority( - QuicUtils::GetHeadersStreamId(transport_version()), - /*is_static=*/true, - spdy::SpdyStreamPrecedence(QuicStream::kDefaultPriority)); - } - if (VersionUsesHttp3(transport_version())) { - // Ignore writes on the control stream. - auto send_control_stream = - QuicSpdySessionPeer::GetSendControlStream(session_.get()); - EXPECT_CALL(*connection_, - SendStreamData(send_control_stream->id(), _, _, NO_FIN)) - .Times(AnyNumber()); - } - } - - // Given |num_resources|, create this number of fake push resources and push - // them by sending PUSH_PROMISE for all and sending push responses for as much - // as possible(limited by kMaxStreamsForTest). - // If |num_resources| > kMaxStreamsForTest, the left over will be queued. - // Returns the length of the DATA frame header, or 0 if the version does not - // use DATA frames. - QuicByteCount PromisePushResources(size_t num_resources) { - // testing::InSequence seq; - // To prevent push streams from being closed the response need to be larger - // than stream flow control window so stream won't send the full body. - size_t body_size = 2 * kStreamFlowControlWindowSize; // 64KB. - - std::string request_url = "mail.google.com/"; - spdy::Http2HeaderBlock request_headers; - std::string resource_host = "www.google.com"; - std::string partial_push_resource_path = "/server_push_src"; - std::list<QuicBackendResponse::ServerPushInfo> push_resources; - std::string scheme = "http"; - QuicByteCount data_frame_header_length = 0; - for (unsigned int i = 1; i <= num_resources; ++i) { - QuicStreamId stream_id; - if (VersionUsesHttp3(transport_version())) { - stream_id = GetNthServerInitiatedUnidirectionalId(i + 2); - } else { - stream_id = GetNthServerInitiatedUnidirectionalId(i - 1); - } - std::string path = absl::StrCat(partial_push_resource_path, i); - std::string url = scheme + "://" + resource_host + path; - QuicUrl resource_url = QuicUrl(url); - std::string body(body_size, 'a'); - std::string data; - data_frame_header_length = 0; - if (VersionUsesHttp3(transport_version())) { - std::unique_ptr<char[]> buffer; - data_frame_header_length = - HttpEncoder::SerializeDataFrameHeader(body.length(), &buffer); - std::string header(buffer.get(), data_frame_header_length); - data = header + body; - } else { - data = body; - } - - memory_cache_backend_.AddSimpleResponse(resource_host, path, 200, data); - push_resources.push_back(QuicBackendResponse::ServerPushInfo( - resource_url, spdy::Http2HeaderBlock(), QuicStream::kDefaultPriority, - body)); - // PUSH_PROMISED are sent for all the resources. - EXPECT_CALL(*session_, - WritePushPromiseMock(GetNthClientInitiatedBidirectionalId(0), - stream_id, _)); - if (i <= kMaxStreamsForTest) { - // |kMaxStreamsForTest| promised responses should be sent. - // Since flow control window is smaller than response body, not the - // whole body will be sent. - QuicStreamOffset offset = 0; - if (VersionUsesHttp3(transport_version())) { - EXPECT_CALL(*connection_, - SendStreamData(stream_id, 1, offset, NO_FIN)); - offset++; - } - - if (VersionUsesHttp3(transport_version())) { - EXPECT_CALL(*connection_, - SendStreamData(stream_id, kHeadersFrameHeaderLength, - offset, NO_FIN)); - offset += kHeadersFrameHeaderLength; - EXPECT_CALL(*connection_, - SendStreamData(stream_id, kHeadersFramePayloadLength, - offset, NO_FIN)); - offset += kHeadersFramePayloadLength; - } - if (VersionUsesHttp3(transport_version())) { - EXPECT_CALL(*connection_, - SendStreamData(stream_id, data_frame_header_length, - offset, NO_FIN)); - offset += data_frame_header_length; - } - EXPECT_CALL(*connection_, SendStreamData(stream_id, _, offset, NO_FIN)) - .WillOnce(Return(QuicConsumedData( - kStreamFlowControlWindowSize - offset, false))); - EXPECT_CALL(*session_, SendBlocked(stream_id)); - } - } - session_->PromisePushResources( - request_url, push_resources, GetNthClientInitiatedBidirectionalId(0), - spdy::SpdyStreamPrecedence(0, spdy::kHttp2DefaultStreamWeight, false), - request_headers); - return data_frame_header_length; - } - - void MaybeConsumeHeadersStreamData() { - if (!VersionUsesHttp3(transport_version())) { - QuicStreamId headers_stream_id = - QuicUtils::GetHeadersStreamId(transport_version()); - EXPECT_CALL(*connection_, SendStreamData(headers_stream_id, _, _, _)) - .Times(AtLeast(1)); - } - } -}; - -ParsedQuicVersionVector SupportedVersionsWithPush() { - ParsedQuicVersionVector versions; - for (const ParsedQuicVersion& version : AllSupportedVersions()) { - if (!version.UsesHttp3()) { - // Push over HTTP/3 is not supported. - versions.push_back(version); - } - } - return versions; -} - -INSTANTIATE_TEST_SUITE_P(Tests, - QuicSimpleServerSessionServerPushTest, - ::testing::ValuesIn(SupportedVersionsWithPush())); - -// Tests that given more than kMaxStreamsForTest resources, all their -// PUSH_PROMISE's will be sent out and only kMaxStreamsForTest streams will be -// opened and send push response. -TEST_P(QuicSimpleServerSessionServerPushTest, TestPromisePushResources) { - MaybeConsumeHeadersStreamData(); - size_t num_resources = kMaxStreamsForTest + 5; - PromisePushResources(num_resources); - EXPECT_EQ(kMaxStreamsForTest, - QuicSessionPeer::GetNumOpenDynamicStreams(session_.get())); -} - -// Tests that after promised stream queued up, when an opened stream is marked -// draining, a queued promised stream will become open and send push response. -TEST_P(QuicSimpleServerSessionServerPushTest, - HandlePromisedPushRequestsAfterStreamDraining) { - MaybeConsumeHeadersStreamData(); - size_t num_resources = kMaxStreamsForTest + 1; - QuicByteCount data_frame_header_length = PromisePushResources(num_resources); - QuicStreamId next_out_going_stream_id; - if (VersionUsesHttp3(transport_version())) { - next_out_going_stream_id = - GetNthServerInitiatedUnidirectionalId(kMaxStreamsForTest + 3); - } else { - next_out_going_stream_id = - GetNthServerInitiatedUnidirectionalId(kMaxStreamsForTest); - } - - // After an open stream is marked draining, a new stream is expected to be - // created and a response sent on the stream. - QuicStreamOffset offset = 0; - if (VersionUsesHttp3(transport_version())) { - EXPECT_CALL(*connection_, - SendStreamData(next_out_going_stream_id, 1, offset, NO_FIN)); - offset++; - } - if (VersionUsesHttp3(transport_version())) { - EXPECT_CALL(*connection_, - SendStreamData(next_out_going_stream_id, - kHeadersFrameHeaderLength, offset, NO_FIN)); - offset += kHeadersFrameHeaderLength; - EXPECT_CALL(*connection_, - SendStreamData(next_out_going_stream_id, - kHeadersFramePayloadLength, offset, NO_FIN)); - offset += kHeadersFramePayloadLength; - } - if (VersionUsesHttp3(transport_version())) { - EXPECT_CALL(*connection_, - SendStreamData(next_out_going_stream_id, - data_frame_header_length, offset, NO_FIN)); - offset += data_frame_header_length; - } - EXPECT_CALL(*connection_, - SendStreamData(next_out_going_stream_id, _, offset, NO_FIN)) - .WillOnce(Return( - QuicConsumedData(kStreamFlowControlWindowSize - offset, false))); - EXPECT_CALL(*session_, SendBlocked(next_out_going_stream_id)); - - if (VersionHasIetfQuicFrames(transport_version())) { - // The PromisePushedResources call, above, will have used all available - // stream ids. For version 99, stream ids are not made available until - // a MAX_STREAMS frame is received. This emulates the reception of one. - // For pre-v-99, the node monitors its own stream usage and makes streams - // available as it closes/etc them. - // 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 + 3, /*unidirectional=*/true)); - } - - if (VersionUsesHttp3(transport_version())) { - session_->StreamDraining(GetNthServerInitiatedUnidirectionalId(3), - /*unidirectional=*/true); - } else { - session_->StreamDraining(GetNthServerInitiatedUnidirectionalId(0), - /*unidirectional=*/true); - } - // Number of open outgoing streams should still be the same, because a new - // stream is opened. And the queue should be empty. - EXPECT_EQ(kMaxStreamsForTest, - QuicSessionPeer::GetNumOpenDynamicStreams(session_.get())); -} - -// Tests that after all resources are promised, a RST frame from client can -// prevent a promised resource to be send out. -TEST_P(QuicSimpleServerSessionServerPushTest, - ResetPromisedStreamToCancelServerPush) { - if (VersionHasIetfQuicFrames(transport_version())) { - // This test is resetting a stream that is not opened yet. IETF QUIC has no - // way to handle this. Some similar tests can be added once CANCEL_PUSH is - // supported. - return; - } - MaybeConsumeHeadersStreamData(); - - // 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. - size_t num_resources = kMaxStreamsForTest + 2; - if (VersionHasIetfQuicFrames(transport_version())) { - // V99 will send out a STREAMS_BLOCKED frame when it tries to exceed the - // limit. This will clear the frames so that they do not block the later - // rst-stream frame. - EXPECT_CALL(*session_, WriteControlFrame(_, _)) - .WillOnce(Invoke(&ClearControlFrameWithTransmissionType)); - } - QuicByteCount data_frame_header_length = PromisePushResources(num_resources); - - // Reset the last stream in the queue. It should be marked cancelled. - QuicStreamId stream_got_reset; - if (VersionUsesHttp3(transport_version())) { - stream_got_reset = - GetNthServerInitiatedUnidirectionalId(kMaxStreamsForTest + 4); - } else { - stream_got_reset = - GetNthServerInitiatedUnidirectionalId(kMaxStreamsForTest + 1); - } - QuicRstStreamFrame rst(kInvalidControlFrameId, stream_got_reset, - QUIC_STREAM_CANCELLED, 0); - EXPECT_CALL(owner_, OnRstStreamReceived(_)).Times(1); - EXPECT_CALL(*session_, WriteControlFrame(_, _)) - .WillOnce(Invoke(&ClearControlFrameWithTransmissionType)); - EXPECT_CALL(*connection_, - OnStreamReset(stream_got_reset, QUIC_RST_ACKNOWLEDGEMENT)); - session_->OnRstStream(rst); - - // When the first 2 streams becomes draining, the two queued up stream could - // be created. But since one of them was marked cancelled due to RST frame, - // only one queued resource will be sent out. - QuicStreamId stream_not_reset; - if (VersionUsesHttp3(transport_version())) { - stream_not_reset = - GetNthServerInitiatedUnidirectionalId(kMaxStreamsForTest + 3); - } else { - stream_not_reset = - GetNthServerInitiatedUnidirectionalId(kMaxStreamsForTest); - } - InSequence s; - QuicStreamOffset offset = 0; - if (VersionUsesHttp3(transport_version())) { - EXPECT_CALL(*connection_, - SendStreamData(stream_not_reset, 1, offset, NO_FIN)); - offset++; - EXPECT_CALL(*connection_, - SendStreamData(stream_not_reset, kHeadersFrameHeaderLength, - offset, NO_FIN)); - offset += kHeadersFrameHeaderLength; - EXPECT_CALL(*connection_, - SendStreamData(stream_not_reset, kHeadersFramePayloadLength, - offset, NO_FIN)); - offset += kHeadersFramePayloadLength; - EXPECT_CALL(*connection_, - SendStreamData(stream_not_reset, data_frame_header_length, - offset, NO_FIN)); - offset += data_frame_header_length; - } - EXPECT_CALL(*connection_, SendStreamData(stream_not_reset, _, offset, NO_FIN)) - .WillOnce(Return( - QuicConsumedData(kStreamFlowControlWindowSize - offset, false))); - EXPECT_CALL(*session_, SendBlocked(stream_not_reset)); - - if (VersionHasIetfQuicFrames(transport_version())) { - // The PromisePushedResources call, above, will have used all available - // stream ids. For version 99, stream ids are not made available until - // a MAX_STREAMS frame is received. This emulates the reception of one. - // 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 + 3, /*unidirectional=*/true)); - } - session_->StreamDraining(GetNthServerInitiatedUnidirectionalId(3), - /*unidirectional=*/true); - session_->StreamDraining(GetNthServerInitiatedUnidirectionalId(4), - /*unidirectional=*/true); -} - -// Tests that closing a open outgoing stream can trigger a promised resource in -// the queue to be send out. -TEST_P(QuicSimpleServerSessionServerPushTest, - CloseStreamToHandleMorePromisedStream) { - MaybeConsumeHeadersStreamData(); - 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 - // the limit. This will clear the frames so that they do not block the later - // rst-stream frame. - EXPECT_CALL(*session_, WriteControlFrame(_, _)) - .WillOnce(Invoke(&ClearControlFrameWithTransmissionType)); - } - QuicByteCount data_frame_header_length = PromisePushResources(num_resources); - QuicStreamId stream_to_open; - if (VersionUsesHttp3(transport_version())) { - stream_to_open = - 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(3); - EXPECT_CALL(*session_, WriteControlFrame(_, _)); - if (!VersionHasIetfQuicFrames(transport_version())) { - EXPECT_CALL(owner_, OnRstStreamReceived(_)).Times(1); - // For version 99, this is covered in InjectStopSending() - EXPECT_CALL(*connection_, - OnStreamReset(stream_got_reset, QUIC_RST_ACKNOWLEDGEMENT)); - } - QuicStreamOffset offset = 0; - if (VersionUsesHttp3(transport_version())) { - EXPECT_CALL(*connection_, - SendStreamData(stream_to_open, 1, offset, NO_FIN)); - offset++; - EXPECT_CALL(*connection_, - SendStreamData(stream_to_open, kHeadersFrameHeaderLength, - offset, NO_FIN)); - offset += kHeadersFrameHeaderLength; - EXPECT_CALL(*connection_, - SendStreamData(stream_to_open, kHeadersFramePayloadLength, - offset, NO_FIN)); - offset += kHeadersFramePayloadLength; - EXPECT_CALL(*connection_, - SendStreamData(stream_to_open, data_frame_header_length, offset, - NO_FIN)); - offset += data_frame_header_length; - } - EXPECT_CALL(*connection_, SendStreamData(stream_to_open, _, offset, NO_FIN)) - .WillOnce(Return( - QuicConsumedData(kStreamFlowControlWindowSize - offset, false))); - - EXPECT_CALL(*session_, SendBlocked(stream_to_open)); - QuicRstStreamFrame rst(kInvalidControlFrameId, stream_got_reset, - QUIC_STREAM_CANCELLED, 0); - if (VersionHasIetfQuicFrames(transport_version())) { - // The PromisePushedResources call, above, will have used all available - // stream ids. For version 99, stream ids are not made available until - // a MAX_STREAMS frame is received. This emulates the reception of one. - // 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 + 3, /*unidirectional=*/true)); - } else { - session_->OnRstStream(rst); - } - // Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a - // RST_STREAM frame causes a two-way close. For IETF QUIC, RST_STREAM causes - // a one-way close. - InjectStopSending(stream_got_reset, QUIC_STREAM_CANCELLED); -} - } // namespace } // namespace test } // namespace quic 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 f4afeb241c0..ac95e46fb97 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 @@ -214,8 +214,7 @@ std::string QuicSimpleServerStream::peer_host() const { } void QuicSimpleServerStream::OnResponseBackendComplete( - const QuicBackendResponse* response, - std::list<QuicBackendResponse::ServerPushInfo> resources) { + const QuicBackendResponse* response) { if (response == nullptr) { QUIC_DVLOG(1) << "Response not found in cache."; SendNotFoundResponse(); @@ -285,15 +284,6 @@ void QuicSimpleServerStream::OnResponseBackendComplete( } } - if (!resources.empty()) { - QUIC_DVLOG(1) << "Stream " << id() << " found " << resources.size() - << " push resources."; - QuicSimpleServerSession* session = - static_cast<QuicSimpleServerSession*>(spdy_session()); - session->PromisePushResources(request_url, resources, id(), precedence(), - request_headers_); - } - if (response->response_type() == QuicBackendResponse::INCOMPLETE_RESPONSE) { QUIC_DVLOG(1) << "Stream " << id() diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream.h b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream.h index 2dd59f9fc91..6395345518b 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream.h +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream.h @@ -57,9 +57,7 @@ class QuicSimpleServerStream : public QuicSpdyServerStreamBase, QuicConnectionId connection_id() const override; QuicStreamId stream_id() const override; std::string peer_host() const override; - void OnResponseBackendComplete( - const QuicBackendResponse* response, - std::list<QuicBackendResponse::ServerPushInfo> resources) override; + void OnResponseBackendComplete(const QuicBackendResponse* response) override; protected: // Sends a basic 200 response using SendHeaders for the headers and WriteData 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 bf80d476020..25423114fab 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 @@ -187,25 +187,6 @@ class MockQuicSimpleServerSession : public QuicSimpleServerSession { MaybeSendStopSendingFrame, (QuicStreamId stream_id, QuicRstStreamErrorCode error), (override)); - // Matchers cannot be used on non-copyable types like Http2HeaderBlock. - void PromisePushResources( - const std::string& request_url, - const std::list<QuicBackendResponse::ServerPushInfo>& resources, - QuicStreamId original_stream_id, - const spdy::SpdyStreamPrecedence& original_precedence, - const spdy::Http2HeaderBlock& original_request_headers) override { - original_request_headers_ = original_request_headers.Clone(); - PromisePushResourcesMock(request_url, resources, original_stream_id, - original_precedence, original_request_headers); - } - MOCK_METHOD(void, - PromisePushResourcesMock, - (const std::string&, - const std::list<QuicBackendResponse::ServerPushInfo>&, - QuicStreamId, - const spdy::SpdyStreamPrecedence&, - const spdy::Http2HeaderBlock&), - ()); using QuicSession::ActivateStream; @@ -546,46 +527,6 @@ TEST_P(QuicSimpleServerStreamTest, SendResponseWithValidHeaders) { EXPECT_TRUE(stream_->write_side_closed()); } -TEST_P(QuicSimpleServerStreamTest, SendResponseWithPushResources) { - // Tests that if a response has push resources to be send, SendResponse() will - // call PromisePushResources() to handle these resources. - - // Add a request and response with valid headers into cache. - std::string host = "www.google.com"; - std::string request_path = "/foo"; - std::string body = "Yummm"; - std::unique_ptr<char[]> buffer; - QuicByteCount header_length = - HttpEncoder::SerializeDataFrameHeader(body.length(), &buffer); - QuicBackendResponse::ServerPushInfo push_info( - QuicUrl(host, "/bar"), spdy::Http2HeaderBlock(), - QuicStream::kDefaultPriority, "Push body"); - std::list<QuicBackendResponse::ServerPushInfo> push_resources; - push_resources.push_back(push_info); - memory_cache_backend_.AddSimpleResponseWithServerPushResources( - host, request_path, 200, body, push_resources); - - spdy::Http2HeaderBlock* request_headers = stream_->mutable_headers(); - (*request_headers)[":path"] = request_path; - (*request_headers)[":authority"] = host; - (*request_headers)[":method"] = "GET"; - - QuicStreamPeer::SetFinReceived(stream_); - InSequence s; - EXPECT_CALL(session_, PromisePushResourcesMock( - host + request_path, _, - GetNthClientInitiatedBidirectionalStreamId( - connection_->transport_version(), 0), - _, _)); - EXPECT_CALL(*stream_, WriteHeadersMock(false)); - if (UsesHttp3()) { - EXPECT_CALL(session_, WritevData(_, header_length, _, NO_FIN, _, _)); - } - EXPECT_CALL(session_, WritevData(_, body.length(), _, FIN, _, _)); - stream_->DoSendResponse(); - EXPECT_EQ(*request_headers, session_.original_request_headers_); -} - TEST_P(QuicSimpleServerStreamTest, SendResponseWithEarlyHints) { std::string host = "www.google.com"; std::string request_path = "/foo"; 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 974344ed4aa..4f51eb47eba 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 @@ -13,7 +13,7 @@ #include "quic/core/quic_server_id.h" #include "quic/platform/api/quic_flags.h" #include "quic/platform/api/quic_logging.h" -#include "common/platform/api/quiche_text_utils.h" +#include "common/quiche_text_utils.h" using spdy::Http2HeaderBlock; 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 15cdc291d27..8d227913ce5 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 @@ -59,9 +59,10 @@ #include "quic/platform/api/quic_ip_address.h" #include "quic/platform/api/quic_socket_address.h" #include "quic/platform/api/quic_system_event_loop.h" +#include "quic/test_tools/simple_session_cache.h" #include "quic/tools/fake_proof_verifier.h" #include "quic/tools/quic_url.h" -#include "common/platform/api/quiche_text_utils.h" +#include "common/quiche_text_utils.h" namespace { @@ -194,6 +195,12 @@ DEFINE_QUIC_COMMAND_LINE_FLAG( false, "If true, do not change local port after each request."); +DEFINE_QUIC_COMMAND_LINE_FLAG(bool, + one_connection_per_request, + false, + "If true, close the connection after each " + "request. This allows testing 0-RTT."); + DEFINE_QUIC_COMMAND_LINE_FLAG(int32_t, server_connection_id_length, -1, @@ -260,6 +267,10 @@ int QuicToyClient::SendRequestsAndPrintResponses( } else { proof_verifier = quic::CreateDefaultProofVerifier(url.host()); } + std::unique_ptr<quic::SessionCache> session_cache; + if (num_requests > 1 && GetQuicFlag(FLAGS_one_connection_per_request)) { + session_cache = std::make_unique<test::SimpleSessionCache>(); + } QuicConfig config; std::string connection_options_string = GetQuicFlag(FLAGS_connection_options); @@ -293,7 +304,7 @@ int QuicToyClient::SendRequestsAndPrintResponses( // Build the client, and try to connect. std::unique_ptr<QuicSpdyClientBase> client = client_factory_->CreateClient( url.host(), host, address_family_for_lookup, port, versions, config, - std::move(proof_verifier)); + std::move(proof_verifier), std::move(session_cache)); if (client == nullptr) { std::cerr << "Failed to create client." << std::endl; @@ -356,7 +367,8 @@ int QuicToyClient::SendRequestsAndPrintResponses( if (sp.empty()) { continue; } - std::vector<absl::string_view> kv = absl::StrSplit(sp, ':'); + std::vector<absl::string_view> kv = + absl::StrSplit(sp, absl::MaxSplits(':', 1)); QuicheTextUtils::RemoveLeadingAndTrailingWhitespace(&kv[0]); QuicheTextUtils::RemoveLeadingAndTrailingWhitespace(&kv[1]); header_block[kv[0]] = kv[1]; @@ -429,11 +441,26 @@ int QuicToyClient::SendRequestsAndPrintResponses( return 1; } - // Change the ephemeral port if there are more requests to do. - if (!GetQuicFlag(FLAGS_disable_port_changes) && i + 1 < num_requests) { - if (!client->ChangeEphemeralPort()) { - std::cerr << "Failed to change ephemeral port." << std::endl; - return 1; + if (i + 1 < num_requests) { // There are more requests to perform. + if (GetQuicFlag(FLAGS_one_connection_per_request)) { + std::cout << "Disconnecting client between requests." << std::endl; + client->Disconnect(); + if (!client->Initialize()) { + std::cerr << "Failed to reinitialize client between requests." + << std::endl; + return 1; + } + if (!client->Connect()) { + std::cerr << "Failed to reconnect client between requests." + << std::endl; + return 1; + } + } else if (!GetQuicFlag(FLAGS_disable_port_changes)) { + // Change the ephemeral port. + if (!client->ChangeEphemeralPort()) { + std::cerr << "Failed to change ephemeral port." << std::endl; + return 1; + } } } } diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.h b/chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.h index 085e749e310..81b3733c46f 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.h +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.h @@ -29,7 +29,8 @@ class QuicToyClient { uint16_t port, ParsedQuicVersionVector versions, const QuicConfig& config, - std::unique_ptr<ProofVerifier> verifier) = 0; + std::unique_ptr<ProofVerifier> verifier, + std::unique_ptr<SessionCache> session_cache) = 0; }; // Constructs a new toy client that will use |client_factory| to create the 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 93f699ba55a..e7b4e1ecd7a 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 @@ -46,6 +46,11 @@ DEFINE_QUIC_COMMAND_LINE_FLAG( "QUIC versions to enable, e.g. \"h3-25,h3-27\". If not set, then all " "available versions are enabled."); +DEFINE_QUIC_COMMAND_LINE_FLAG(bool, + enable_webtransport, + false, + "If true, WebTransport support is enabled."); + namespace quic { std::unique_ptr<quic::QuicSimpleServerBackend> @@ -58,6 +63,9 @@ QuicToyServer::MemoryCacheBackendFactory::CreateBackend() { memory_cache_backend->InitializeBackend( GetQuicFlag(FLAGS_quic_response_cache_dir)); } + if (GetQuicFlag(FLAGS_enable_webtransport)) { + memory_cache_backend->EnableWebTransport(); + } return memory_cache_backend; } diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_transport_simple_server_session.h b/chromium/net/third_party/quiche/src/quic/tools/quic_transport_simple_server_session.h index 2d3be8a0fe2..a51eab66952 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_transport_simple_server_session.h +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_transport_simple_server_session.h @@ -73,7 +73,7 @@ class QuicTransportSimpleServerSession size_t pending_outgoing_bidirectional_streams_ = 0u; Mode mode_; std::vector<url::Origin> accepted_origins_; - QuicCircularDeque<std::string> streams_to_echo_back_; + quiche::QuicheCircularDeque<std::string> streams_to_echo_back_; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/tools/web_transport_test_visitors.h b/chromium/net/third_party/quiche/src/quic/tools/web_transport_test_visitors.h index 9bf6e6bca84..e348750a474 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/web_transport_test_visitors.h +++ b/chromium/net/third_party/quiche/src/quic/tools/web_transport_test_visitors.h @@ -7,8 +7,10 @@ #include <string> +#include "quic/core/quic_simple_buffer_allocator.h" #include "quic/core/web_transport_interface.h" #include "quic/platform/api/quic_logging.h" +#include "common/quiche_circular_deque.h" namespace quic { @@ -132,6 +134,95 @@ class WebTransportUnidirectionalEchoWriteVisitor std::string data_; }; +// A session visitor which sets unidirectional or bidirectional stream visitors +// to echo. +class EchoWebTransportSessionVisitor : public WebTransportVisitor { + public: + EchoWebTransportSessionVisitor(WebTransportSession* session) + : session_(session) {} + + void OnSessionReady() override { + if (session_->CanOpenNextOutgoingBidirectionalStream()) { + OnCanCreateNewOutgoingBidirectionalStream(); + } + } + + void OnIncomingBidirectionalStreamAvailable() override { + while (true) { + WebTransportStream* stream = + session_->AcceptIncomingBidirectionalStream(); + if (stream == nullptr) { + return; + } + QUIC_DVLOG(1) + << "EchoWebTransportSessionVisitor received a bidirectional stream " + << stream->GetStreamId(); + stream->SetVisitor( + std::make_unique<WebTransportBidirectionalEchoVisitor>(stream)); + stream->visitor()->OnCanRead(); + } + } + + void OnIncomingUnidirectionalStreamAvailable() override { + while (true) { + WebTransportStream* stream = + session_->AcceptIncomingUnidirectionalStream(); + if (stream == nullptr) { + return; + } + QUIC_DVLOG(1) + << "EchoWebTransportSessionVisitor received a unidirectional stream"; + stream->SetVisitor( + std::make_unique<WebTransportUnidirectionalEchoReadVisitor>( + stream, [this](const std::string& data) { + streams_to_echo_back_.push_back(data); + TrySendingUnidirectionalStreams(); + })); + stream->visitor()->OnCanRead(); + } + } + + void OnDatagramReceived(absl::string_view datagram) override { + auto buffer = MakeUniqueBuffer(&allocator_, datagram.size()); + memcpy(buffer.get(), datagram.data(), datagram.size()); + QuicMemSlice slice(std::move(buffer), datagram.size()); + session_->SendOrQueueDatagram(std::move(slice)); + } + + void OnCanCreateNewOutgoingBidirectionalStream() override { + if (!echo_stream_opened_) { + WebTransportStream* stream = session_->OpenOutgoingBidirectionalStream(); + stream->SetVisitor( + std::make_unique<WebTransportBidirectionalEchoVisitor>(stream)); + echo_stream_opened_ = true; + } + } + void OnCanCreateNewOutgoingUnidirectionalStream() override { + TrySendingUnidirectionalStreams(); + } + + void TrySendingUnidirectionalStreams() { + while (!streams_to_echo_back_.empty() && + session_->CanOpenNextOutgoingUnidirectionalStream()) { + QUIC_DVLOG(1) + << "EchoWebTransportServer echoed a unidirectional stream back"; + WebTransportStream* stream = session_->OpenOutgoingUnidirectionalStream(); + stream->SetVisitor( + std::make_unique<WebTransportUnidirectionalEchoWriteVisitor>( + stream, streams_to_echo_back_.front())); + streams_to_echo_back_.pop_front(); + stream->visitor()->OnCanWrite(); + } + } + + private: + WebTransportSession* session_; + SimpleBufferAllocator allocator_; + bool echo_stream_opened_ = false; + + quiche::QuicheCircularDeque<std::string> streams_to_echo_back_; +}; + } // namespace quic #endif // QUICHE_QUIC_TOOLS_WEB_TRANSPORT_TEST_VISITORS_H_ diff --git a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_constants.cc b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_constants.cc index 231fd547460..a8e48a2feb5 100644 --- a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_constants.cc +++ b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_constants.cc @@ -9,8 +9,8 @@ #include <vector> #include "absl/base/macros.h" +#include "common/platform/api/quiche_logging.h" #include "spdy/core/hpack/hpack_static_table.h" -#include "spdy/platform/api/spdy_logging.h" namespace spdy { diff --git a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_decoder_adapter.cc b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_decoder_adapter.cc index 4d03cc50018..3fd6ebcf87d 100644 --- a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_decoder_adapter.cc +++ b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_decoder_adapter.cc @@ -6,9 +6,8 @@ #include "http2/decoder/decode_buffer.h" #include "http2/decoder/decode_status.h" +#include "common/platform/api/quiche_logging.h" #include "spdy/platform/api/spdy_estimate_memory_usage.h" -#include "spdy/platform/api/spdy_flags.h" -#include "spdy/platform/api/spdy_logging.h" using ::http2::DecodeBuffer; @@ -27,13 +26,13 @@ HpackDecoderAdapter::HpackDecoderAdapter() HpackDecoderAdapter::~HpackDecoderAdapter() = default; void HpackDecoderAdapter::ApplyHeaderTableSizeSetting(size_t size_setting) { - SPDY_DVLOG(2) << "HpackDecoderAdapter::ApplyHeaderTableSizeSetting"; + QUICHE_DVLOG(2) << "HpackDecoderAdapter::ApplyHeaderTableSizeSetting"; hpack_decoder_.ApplyHeaderTableSizeSetting(size_setting); } void HpackDecoderAdapter::HandleControlFrameHeadersStart( SpdyHeadersHandlerInterface* handler) { - SPDY_DVLOG(2) << "HpackDecoderAdapter::HandleControlFrameHeadersStart"; + QUICHE_DVLOG(2) << "HpackDecoderAdapter::HandleControlFrameHeadersStart"; QUICHE_DCHECK(!header_block_started_); listener_adapter_.set_handler(handler); } @@ -41,8 +40,8 @@ void HpackDecoderAdapter::HandleControlFrameHeadersStart( bool HpackDecoderAdapter::HandleControlFrameHeadersData( const char* headers_data, size_t headers_data_length) { - SPDY_DVLOG(2) << "HpackDecoderAdapter::HandleControlFrameHeadersData: len=" - << headers_data_length; + QUICHE_DVLOG(2) << "HpackDecoderAdapter::HandleControlFrameHeadersData: len=" + << headers_data_length; if (!header_block_started_) { // Initialize the decoding process here rather than in // HandleControlFrameHeadersStart because that method is not always called. @@ -61,9 +60,9 @@ bool HpackDecoderAdapter::HandleControlFrameHeadersData( if (headers_data_length > 0) { QUICHE_DCHECK_NE(headers_data, nullptr); if (headers_data_length > max_decode_buffer_size_bytes_) { - SPDY_DVLOG(1) << "max_decode_buffer_size_bytes_ < headers_data_length: " - << max_decode_buffer_size_bytes_ << " < " - << headers_data_length; + QUICHE_DVLOG(1) << "max_decode_buffer_size_bytes_ < headers_data_length: " + << max_decode_buffer_size_bytes_ << " < " + << headers_data_length; error_ = http2::HpackDecodingError::kFragmentTooLong; detailed_error_ = ""; return false; @@ -89,12 +88,12 @@ bool HpackDecoderAdapter::HandleControlFrameHeadersData( bool HpackDecoderAdapter::HandleControlFrameHeadersComplete( size_t* compressed_len) { - SPDY_DVLOG(2) << "HpackDecoderAdapter::HandleControlFrameHeadersComplete"; + QUICHE_DVLOG(2) << "HpackDecoderAdapter::HandleControlFrameHeadersComplete"; if (compressed_len != nullptr) { *compressed_len = listener_adapter_.total_hpack_bytes(); } if (!hpack_decoder_.EndDecodingBlock()) { - SPDY_DVLOG(3) << "EndDecodingBlock returned false"; + QUICHE_DVLOG(3) << "EndDecodingBlock returned false"; error_ = hpack_decoder_.error(); detailed_error_ = hpack_decoder_.detailed_error(); return false; @@ -109,7 +108,7 @@ const SpdyHeaderBlock& HpackDecoderAdapter::decoded_block() const { void HpackDecoderAdapter::set_max_decode_buffer_size_bytes( size_t max_decode_buffer_size_bytes) { - SPDY_DVLOG(2) << "HpackDecoderAdapter::set_max_decode_buffer_size_bytes"; + QUICHE_DVLOG(2) << "HpackDecoderAdapter::set_max_decode_buffer_size_bytes"; max_decode_buffer_size_bytes_ = max_decode_buffer_size_bytes; hpack_decoder_.set_max_string_size_bytes(max_decode_buffer_size_bytes); } @@ -132,7 +131,7 @@ void HpackDecoderAdapter::ListenerAdapter::set_handler( } void HpackDecoderAdapter::ListenerAdapter::OnHeaderListStart() { - SPDY_DVLOG(2) << "HpackDecoderAdapter::ListenerAdapter::OnHeaderListStart"; + QUICHE_DVLOG(2) << "HpackDecoderAdapter::ListenerAdapter::OnHeaderListStart"; total_hpack_bytes_ = 0; total_uncompressed_bytes_ = 0; decoded_block_.clear(); @@ -143,20 +142,20 @@ void HpackDecoderAdapter::ListenerAdapter::OnHeaderListStart() { void HpackDecoderAdapter::ListenerAdapter::OnHeader(const std::string& name, const std::string& value) { - SPDY_DVLOG(2) << "HpackDecoderAdapter::ListenerAdapter::OnHeader:\n name: " - << name << "\n value: " << value; + QUICHE_DVLOG(2) << "HpackDecoderAdapter::ListenerAdapter::OnHeader:\n name: " + << name << "\n value: " << value; total_uncompressed_bytes_ += name.size() + value.size(); if (handler_ == nullptr) { - SPDY_DVLOG(3) << "Adding to decoded_block"; + QUICHE_DVLOG(3) << "Adding to decoded_block"; decoded_block_.AppendValueOrAddHeader(name, value); } else { - SPDY_DVLOG(3) << "Passing to handler"; + QUICHE_DVLOG(3) << "Passing to handler"; handler_->OnHeader(name, value); } } void HpackDecoderAdapter::ListenerAdapter::OnHeaderListEnd() { - SPDY_DVLOG(2) << "HpackDecoderAdapter::ListenerAdapter::OnHeaderListEnd"; + QUICHE_DVLOG(2) << "HpackDecoderAdapter::ListenerAdapter::OnHeaderListEnd"; // We don't clear the SpdyHeaderBlock here to allow access to it until the // next HPACK block is decoded. if (handler_ != nullptr) { @@ -167,7 +166,7 @@ void HpackDecoderAdapter::ListenerAdapter::OnHeaderListEnd() { void HpackDecoderAdapter::ListenerAdapter::OnHeaderErrorDetected( absl::string_view error_message) { - SPDY_VLOG(1) << error_message; + QUICHE_VLOG(1) << error_message; } } // 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 0a12fe49a21..d223ccf9f5a 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 @@ -14,17 +14,18 @@ #include <vector> #include "absl/base/macros.h" +#include "absl/strings/escaping.h" #include "http2/hpack/decoder/hpack_decoder_state.h" #include "http2/hpack/decoder/hpack_decoder_tables.h" #include "http2/hpack/tools/hpack_block_builder.h" #include "http2/test_tools/http2_random.h" +#include "common/platform/api/quiche_logging.h" #include "common/platform/api/quiche_test.h" #include "spdy/core/hpack/hpack_constants.h" #include "spdy/core/hpack/hpack_encoder.h" #include "spdy/core/hpack/hpack_output_stream.h" #include "spdy/core/recording_headers_handler.h" #include "spdy/core/spdy_test_utils.h" -#include "spdy/platform/api/spdy_logging.h" #include "spdy/platform/api/spdy_string_utils.h" using ::http2::HpackEntryType; @@ -134,7 +135,7 @@ class HpackDecoderAdapterTest } bool HandleControlFrameHeadersData(absl::string_view str) { - SPDY_VLOG(3) << "HandleControlFrameHeadersData:\n" << SpdyHexDump(str); + QUICHE_VLOG(3) << "HandleControlFrameHeadersData:\n" << SpdyHexDump(str); bytes_passed_in_ += str.size(); return decoder_.HandleControlFrameHeadersData(str.data(), str.size()); } @@ -680,7 +681,7 @@ TEST_P(HpackDecoderAdapterTest, TruncatedHuffmanLiteral) { // | www.example.com // | -> :authority: www.example.com - std::string first = SpdyHexDecode("418cf1e3c2e5f23a6ba0ab90f4ff"); + std::string first = absl::HexStringToBytes("418cf1e3c2e5f23a6ba0ab90f4ff"); EXPECT_TRUE(DecodeHeaderBlock(first)); first.pop_back(); EXPECT_FALSE(DecodeHeaderBlock(first)); @@ -700,9 +701,9 @@ TEST_P(HpackDecoderAdapterTest, HuffmanEOSError) { // | www.example.com // | -> :authority: www.example.com - std::string first = SpdyHexDecode("418cf1e3c2e5f23a6ba0ab90f4ff"); + std::string first = absl::HexStringToBytes("418cf1e3c2e5f23a6ba0ab90f4ff"); EXPECT_TRUE(DecodeHeaderBlock(first)); - first = SpdyHexDecode("418df1e3c2e5f23a6ba0ab90f4ffff"); + first = absl::HexStringToBytes("418df1e3c2e5f23a6ba0ab90f4ffff"); EXPECT_FALSE(DecodeHeaderBlock(first)); } @@ -749,7 +750,8 @@ TEST_P(HpackDecoderAdapterTest, SectionC4RequestHuffmanExamples) { // | Decoded: // | www.example.com // | -> :authority: www.example.com - std::string first = SpdyHexDecode("828684418cf1e3c2e5f23a6ba0ab90f4ff"); + std::string first = + absl::HexStringToBytes("828684418cf1e3c2e5f23a6ba0ab90f4ff"); const SpdyHeaderBlock& first_header_set = DecodeBlockExpectingSuccess(first); EXPECT_THAT(first_header_set, @@ -786,7 +788,7 @@ TEST_P(HpackDecoderAdapterTest, SectionC4RequestHuffmanExamples) { // | no-cache // | -> cache-control: no-cache - std::string second = SpdyHexDecode("828684be5886a8eb10649cbf"); + std::string second = absl::HexStringToBytes("828684be5886a8eb10649cbf"); const SpdyHeaderBlock& second_header_set = DecodeBlockExpectingSuccess(second); @@ -828,8 +830,8 @@ TEST_P(HpackDecoderAdapterTest, SectionC4RequestHuffmanExamples) { // | Decoded: // | custom-value // | -> custom-key: custom-value - std::string third = - SpdyHexDecode("828785bf408825a849e95ba97d7f8925a849e95bb8e8b4bf"); + std::string third = absl::HexStringToBytes( + "828785bf408825a849e95ba97d7f8925a849e95bb8e8b4bf"); const SpdyHeaderBlock& third_header_set = DecodeBlockExpectingSuccess(third); EXPECT_THAT( @@ -898,7 +900,7 @@ TEST_P(HpackDecoderAdapterTest, SectionC6ResponseHuffmanExamples) { // | -> location: https://www.e // | xample.com - std::string first = SpdyHexDecode( + std::string first = absl::HexStringToBytes( "488264025885aec3771a4b6196d07abe" "941054d444a8200595040b8166e082a6" "2d1bff6e919d29ad171863c78f0b97c8" @@ -941,7 +943,7 @@ TEST_P(HpackDecoderAdapterTest, SectionC6ResponseHuffmanExamples) { // | idx = 63 // | -> location: // | https://www.example.com - std::string second = SpdyHexDecode("4883640effc1c0bf"); + std::string second = absl::HexStringToBytes("4883640effc1c0bf"); const SpdyHeaderBlock& second_header_set = DecodeBlockExpectingSuccess(second); @@ -1013,7 +1015,7 @@ TEST_P(HpackDecoderAdapterTest, SectionC6ResponseHuffmanExamples) { // | -> set-cookie: foo=ASDJKHQ // | KBZXOQWEOPIUAXQWEOIU; // | max-age=3600; version=1 - std::string third = SpdyHexDecode( + std::string third = absl::HexStringToBytes( "88c16196d07abe941054d444a8200595" "040b8166e084a62d1bffc05a839bd9ab" "77ad94e7821dd7f2e6c7b335dfdfcd5b" @@ -1116,7 +1118,7 @@ TEST_P(HpackDecoderAdapterTest, Cookies) { SpdyHeaderBlock expected_header_set; expected_header_set["cookie"] = "foo; bar"; - EXPECT_TRUE(DecodeHeaderBlock(SpdyHexDecode("608294e76003626172"))); + EXPECT_TRUE(DecodeHeaderBlock(absl::HexStringToBytes("608294e76003626172"))); EXPECT_EQ(expected_header_set, decoded_block()); } diff --git a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_encoder.cc b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_encoder.cc index 6dc27b9ca7f..27f0444f274 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 @@ -9,13 +9,12 @@ #include <utility> #include "http2/hpack/huffman/hpack_huffman_encoder.h" +#include "common/platform/api/quiche_bug_tracker.h" +#include "common/platform/api/quiche_logging.h" #include "spdy/core/hpack/hpack_constants.h" #include "spdy/core/hpack/hpack_header_table.h" #include "spdy/core/hpack/hpack_output_stream.h" #include "spdy/platform/api/spdy_estimate_memory_usage.h" -#include "spdy/platform/api/spdy_flag_utils.h" -#include "spdy/platform/api/spdy_flags.h" -#include "spdy/platform/api/spdy_logging.h" namespace spdy { @@ -155,14 +154,14 @@ void HpackEncoder::EncodeRepresentations(RepresentationIterator* iter, } void HpackEncoder::EmitIndex(size_t index) { - SPDY_DVLOG(2) << "Emitting index " << index; + QUICHE_DVLOG(2) << "Emitting index " << index; output_stream_.AppendPrefix(kIndexedOpcode); output_stream_.AppendUint32(index); } void HpackEncoder::EmitIndexedLiteral(const Representation& representation) { - SPDY_DVLOG(2) << "Emitting indexed literal: (" << representation.first << ", " - << representation.second << ")"; + QUICHE_DVLOG(2) << "Emitting indexed literal: (" << representation.first + << ", " << representation.second << ")"; output_stream_.AppendPrefix(kLiteralIncrementalIndexOpcode); EmitLiteral(representation); header_table_.TryAddEntry(representation.first, representation.second); @@ -170,8 +169,8 @@ void HpackEncoder::EmitIndexedLiteral(const Representation& representation) { void HpackEncoder::EmitNonIndexedLiteral(const Representation& representation, bool enable_compression) { - SPDY_DVLOG(2) << "Emitting nonindexed literal: (" << representation.first - << ", " << representation.second << ")"; + QUICHE_DVLOG(2) << "Emitting nonindexed literal: (" << representation.first + << ", " << representation.second << ")"; output_stream_.AppendPrefix(kLiteralNoIndexOpcode); size_t name_index = header_table_.GetByName(representation.first); if (enable_compression && name_index != kHpackEntryNotFound) { @@ -198,13 +197,13 @@ void HpackEncoder::EmitString(absl::string_view str) { size_t encoded_size = enable_compression_ ? http2::HuffmanSize(str) : str.size(); if (encoded_size < str.size()) { - SPDY_DVLOG(2) << "Emitted Huffman-encoded string of length " - << encoded_size; + QUICHE_DVLOG(2) << "Emitted Huffman-encoded string of length " + << encoded_size; output_stream_.AppendPrefix(kStringLiteralHuffmanEncoded); output_stream_.AppendUint32(encoded_size); http2::HuffmanEncodeFast(str, encoded_size, output_stream_.MutableString()); } else { - SPDY_DVLOG(2) << "Emitted literal string of length " << str.size(); + QUICHE_DVLOG(2) << "Emitted literal string of length " << str.size(); output_stream_.AppendPrefix(kStringLiteralIdentityEncoded); output_stream_.AppendUint32(str.size()); output_stream_.AppendBytes(str); @@ -216,9 +215,9 @@ void HpackEncoder::MaybeEmitTableSize() { return; } const size_t current_size = CurrentHeaderTableSizeSetting(); - SPDY_DVLOG(1) << "MaybeEmitTableSize current_size=" << current_size; - SPDY_DVLOG(1) << "MaybeEmitTableSize min_table_size_setting_received_=" - << min_table_size_setting_received_; + QUICHE_DVLOG(1) << "MaybeEmitTableSize current_size=" << current_size; + QUICHE_DVLOG(1) << "MaybeEmitTableSize min_table_size_setting_received_=" + << min_table_size_setting_received_; if (min_table_size_setting_received_ < current_size) { output_stream_.AppendPrefix(kHeaderTableSizeUpdateOpcode); output_stream_.AppendUint32(min_table_size_setting_received_); @@ -347,7 +346,7 @@ HpackEncoder::Encoderator::Encoderator(const Representations& representations, void HpackEncoder::Encoderator::Next(size_t max_encoded_bytes, std::string* output) { - SPDY_BUG_IF(spdy_bug_61_1, !has_next_) + QUICHE_BUG_IF(spdy_bug_61_1, !has_next_) << "Encoderator::Next called with nothing left to encode."; const bool enable_compression = encoder_->enable_compression_; 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 85fa4fbc321..774a06e8129 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 @@ -12,7 +12,6 @@ #include "common/platform/api/quiche_test.h" #include "spdy/core/hpack/hpack_static_table.h" #include "spdy/core/spdy_simple_arena.h" -#include "spdy/platform/api/spdy_flags.h" namespace spdy { 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 b8350df4ff4..4deb0dfcc81 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 @@ -6,7 +6,6 @@ #include "absl/strings/str_cat.h" #include "spdy/platform/api/spdy_estimate_memory_usage.h" -#include "spdy/platform/api/spdy_logging.h" namespace spdy { diff --git a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_header_table.cc b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_header_table.cc index ec69d47b6ae..8536a8523fc 100644 --- a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_header_table.cc +++ b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_header_table.cc @@ -6,10 +6,10 @@ #include <algorithm> +#include "common/platform/api/quiche_logging.h" #include "spdy/core/hpack/hpack_constants.h" #include "spdy/core/hpack/hpack_static_table.h" #include "spdy/platform/api/spdy_estimate_memory_usage.h" -#include "spdy/platform/api/spdy_logging.h" namespace spdy { @@ -155,9 +155,9 @@ const HpackEntry* HpackHeaderTable::TryAddEntry(absl::string_view name, if (!index_result.second) { // An entry with the same name and value already exists in the dynamic // index. We should replace it with the newly added entry. - SPDY_DVLOG(1) << "Found existing entry at: " << index_result.first->second - << " replacing with: " << new_entry->GetDebugString() - << " at: " << index; + QUICHE_DVLOG(1) << "Found existing entry at: " << index_result.first->second + << " replacing with: " << new_entry->GetDebugString() + << " at: " << index; QUICHE_DCHECK_GT(index, index_result.first->second); dynamic_index_.erase(index_result.first); auto insert_result = dynamic_index_.insert(std::make_pair( @@ -170,9 +170,9 @@ const HpackEntry* HpackHeaderTable::TryAddEntry(absl::string_view name, if (!name_result.second) { // An entry with the same name already exists in the dynamic index. We // should replace it with the newly added entry. - SPDY_DVLOG(1) << "Found existing entry at: " << name_result.first->second - << " replacing with: " << new_entry->GetDebugString() - << " at: " << index; + QUICHE_DVLOG(1) << "Found existing entry at: " << name_result.first->second + << " replacing with: " << new_entry->GetDebugString() + << " at: " << index; QUICHE_DCHECK_GT(index, name_result.first->second); dynamic_name_index_.erase(name_result.first); auto insert_result = diff --git a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_header_table.h b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_header_table.h index 893aaa7bb21..49478cd35b2 100644 --- a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_header_table.h +++ b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_header_table.h @@ -43,11 +43,6 @@ class QUICHE_EXPORT_PRIVATE HpackHeaderTable { // HpackHeaderTable takes advantage of the deque property that references // remain valid, so long as insertions & deletions are at the head & tail. // This precludes the use of base::circular_deque. - // - // If this changes (we want to change to circular_deque or we start to drop - // entries from the middle of the table), this should to be a std::list, in - // which case |*_index_| can be trivially extended to map to list iterators. - // // TODO(b/182349990): Change to a more memory efficient container. using DynamicEntryTable = std::deque<HpackEntry>; 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 d2ec46c49c5..7b925680d4b 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 @@ -6,8 +6,8 @@ #include <utility> +#include "common/platform/api/quiche_logging.h" #include "spdy/platform/api/spdy_estimate_memory_usage.h" -#include "spdy/platform/api/spdy_logging.h" namespace spdy { diff --git a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_static_table.cc b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_static_table.cc index 8c8248c2343..7594943b43e 100644 --- a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_static_table.cc +++ b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_static_table.cc @@ -5,10 +5,10 @@ #include "spdy/core/hpack/hpack_static_table.h" #include "absl/strings/string_view.h" +#include "common/platform/api/quiche_logging.h" #include "spdy/core/hpack/hpack_constants.h" #include "spdy/core/hpack/hpack_entry.h" #include "spdy/platform/api/spdy_estimate_memory_usage.h" -#include "spdy/platform/api/spdy_logging.h" namespace spdy { 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 cb9c176090a..b20d0032aff 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 @@ -4,9 +4,9 @@ #include "spdy/core/http2_frame_decoder_adapter.h" -// Logging policy: If an error in the input is detected, SPDY_VLOG(n) is used so -// that the option exists to debug the situation. Otherwise, this code mostly -// uses SPDY_DVLOG so that the logging does not slow down production code when +// Logging policy: If an error in the input is detected, QUICHE_VLOG(n) is used +// so that the option exists to debug the situation. Otherwise, this code mostly +// uses QUICHE_DVLOG so that the logging does not slow down production code when // things are working OK. #include <stddef.h> @@ -21,6 +21,8 @@ #include "http2/decoder/http2_frame_decoder_listener.h" #include "http2/http2_constants.h" #include "http2/http2_structures.h" +#include "common/platform/api/quiche_bug_tracker.h" +#include "common/platform/api/quiche_logging.h" #include "common/quiche_endian.h" #include "spdy/core/hpack/hpack_decoder_adapter.h" #include "spdy/core/hpack/hpack_header_table.h" @@ -28,10 +30,7 @@ #include "spdy/core/spdy_header_block.h" #include "spdy/core/spdy_headers_handler_interface.h" #include "spdy/core/spdy_protocol.h" -#include "spdy/platform/api/spdy_bug_tracker.h" #include "spdy/platform/api/spdy_estimate_memory_usage.h" -#include "spdy/platform/api/spdy_flags.h" -#include "spdy/platform/api/spdy_logging.h" #include "spdy/platform/api/spdy_string_utils.h" using ::spdy::ExtensionVisitorInterface; @@ -257,7 +256,7 @@ const char* Http2DecoderAdapter::SpdyFramerErrorToString( } Http2DecoderAdapter::Http2DecoderAdapter() { - SPDY_DVLOG(1) << "Http2DecoderAdapter ctor"; + QUICHE_DVLOG(1) << "Http2DecoderAdapter ctor"; ResetInternal(); } @@ -335,7 +334,7 @@ size_t Http2DecoderAdapter::EstimateMemoryUsage() const { // This function is largely based on Http2DecoderAdapter::ValidateFrameHeader // and some parts of Http2DecoderAdapter::ProcessCommonHeader. bool Http2DecoderAdapter::OnFrameHeader(const Http2FrameHeader& header) { - SPDY_DVLOG(1) << "OnFrameHeader: " << header; + QUICHE_DVLOG(1) << "OnFrameHeader: " << header; decoded_frame_header_ = true; if (!latched_probable_http_response_) { latched_probable_http_response_ = header.IsProbableHttpResponse(); @@ -347,10 +346,10 @@ bool Http2DecoderAdapter::OnFrameHeader(const Http2FrameHeader& header) { // Report an unexpected frame error and close the connection if we // expect a known frame type (probably CONTINUATION) and receive an // unknown frame. - SPDY_VLOG(1) << "The framer was expecting to receive a " - << expected_frame_type_ - << " frame, but instead received an unknown frame of type " - << header.type; + QUICHE_VLOG(1) << "The framer was expecting to receive a " + << expected_frame_type_ + << " frame, but instead received an unknown frame of type " + << header.type; SetSpdyErrorAndNotify(SpdyFramerError::SPDY_UNEXPECTED_FRAME, ""); return false; } @@ -366,34 +365,35 @@ bool Http2DecoderAdapter::OnFrameHeader(const Http2FrameHeader& header) { visitor()->OnUnknownFrame(header.stream_id, raw_frame_type); if (!valid_stream) { // Report an invalid frame error if the stream_id is not valid. - SPDY_VLOG(1) << "Unknown control frame type " << header.type - << " received on invalid stream " << header.stream_id; + QUICHE_VLOG(1) << "Unknown control frame type " << header.type + << " received on invalid stream " << header.stream_id; SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_CONTROL_FRAME, ""); return false; } else { - SPDY_DVLOG(1) << "Ignoring unknown frame type " << header.type; + QUICHE_DVLOG(1) << "Ignoring unknown frame type " << header.type; return true; } } SpdyFrameType frame_type = ToSpdyFrameType(header.type); if (!IsValidHTTP2FrameStreamId(header.stream_id, frame_type)) { - SPDY_VLOG(1) << "The framer received an invalid streamID of " - << header.stream_id << " for a frame of type " << header.type; + QUICHE_VLOG(1) << "The framer received an invalid streamID of " + << header.stream_id << " for a frame of type " + << header.type; SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_STREAM_ID, ""); return false; } if (has_expected_frame_type_ && header.type != expected_frame_type_) { - SPDY_VLOG(1) << "Expected frame type " << expected_frame_type_ << ", not " - << header.type; + QUICHE_VLOG(1) << "Expected frame type " << expected_frame_type_ << ", not " + << header.type; SetSpdyErrorAndNotify(SpdyFramerError::SPDY_UNEXPECTED_FRAME, ""); return false; } if (!has_expected_frame_type_ && header.type == Http2FrameType::CONTINUATION) { - SPDY_VLOG(1) << "Got CONTINUATION frame when not expected."; + QUICHE_VLOG(1) << "Got CONTINUATION frame when not expected."; SetSpdyErrorAndNotify(SpdyFramerError::SPDY_UNEXPECTED_FRAME, ""); return false; } @@ -411,7 +411,7 @@ bool Http2DecoderAdapter::OnFrameHeader(const Http2FrameHeader& header) { } void Http2DecoderAdapter::OnDataStart(const Http2FrameHeader& header) { - SPDY_DVLOG(1) << "OnDataStart: " << header; + QUICHE_DVLOG(1) << "OnDataStart: " << header; if (IsOkToStartFrame(header) && HasRequiredStreamId(header)) { frame_header_ = header; @@ -422,14 +422,14 @@ void Http2DecoderAdapter::OnDataStart(const Http2FrameHeader& header) { } void Http2DecoderAdapter::OnDataPayload(const char* data, size_t len) { - SPDY_DVLOG(1) << "OnDataPayload: len=" << len; + QUICHE_DVLOG(1) << "OnDataPayload: len=" << len; QUICHE_DCHECK(has_frame_header_); QUICHE_DCHECK_EQ(frame_header_.type, Http2FrameType::DATA); visitor()->OnStreamFrameData(frame_header().stream_id, data, len); } void Http2DecoderAdapter::OnDataEnd() { - SPDY_DVLOG(1) << "OnDataEnd"; + QUICHE_DVLOG(1) << "OnDataEnd"; QUICHE_DCHECK(has_frame_header_); QUICHE_DCHECK_EQ(frame_header_.type, Http2FrameType::DATA); if (frame_header().IsEndStream()) { @@ -439,7 +439,7 @@ void Http2DecoderAdapter::OnDataEnd() { } void Http2DecoderAdapter::OnHeadersStart(const Http2FrameHeader& header) { - SPDY_DVLOG(1) << "OnHeadersStart: " << header; + QUICHE_DVLOG(1) << "OnHeadersStart: " << header; if (IsOkToStartFrame(header) && HasRequiredStreamId(header)) { frame_header_ = header; has_frame_header_ = true; @@ -462,7 +462,7 @@ void Http2DecoderAdapter::OnHeadersStart(const Http2FrameHeader& header) { void Http2DecoderAdapter::OnHeadersPriority( const Http2PriorityFields& priority) { - SPDY_DVLOG(1) << "OnHeadersPriority: " << priority; + QUICHE_DVLOG(1) << "OnHeadersPriority: " << priority; QUICHE_DCHECK(has_frame_header_); QUICHE_DCHECK_EQ(frame_type(), Http2FrameType::HEADERS) << frame_header_; QUICHE_DCHECK(frame_header_.HasPriority()); @@ -470,7 +470,7 @@ void Http2DecoderAdapter::OnHeadersPriority( on_headers_called_ = true; ReportReceiveCompressedFrame(frame_header_); if (!visitor()) { - SPDY_BUG(spdy_bug_1_1) + QUICHE_BUG(spdy_bug_1_1) << "Visitor is nullptr, handling priority in headers failed." << " priority:" << priority << " frame_header:" << frame_header_; return; @@ -483,7 +483,7 @@ void Http2DecoderAdapter::OnHeadersPriority( } void Http2DecoderAdapter::OnHpackFragment(const char* data, size_t len) { - SPDY_DVLOG(1) << "OnHpackFragment: len=" << len; + QUICHE_DVLOG(1) << "OnHpackFragment: len=" << len; on_hpack_fragment_called_ = true; auto* decoder = GetHpackDecoder(); if (!decoder->HandleControlFrameHeadersData(data, len)) { @@ -494,14 +494,15 @@ void Http2DecoderAdapter::OnHpackFragment(const char* data, size_t len) { } void Http2DecoderAdapter::OnHeadersEnd() { - SPDY_DVLOG(1) << "OnHeadersEnd"; + QUICHE_DVLOG(1) << "OnHeadersEnd"; CommonHpackFragmentEnd(); opt_pad_length_.reset(); } void Http2DecoderAdapter::OnPriorityFrame(const Http2FrameHeader& header, const Http2PriorityFields& priority) { - SPDY_DVLOG(1) << "OnPriorityFrame: " << header << "; priority: " << priority; + QUICHE_DVLOG(1) << "OnPriorityFrame: " << header + << "; priority: " << priority; if (IsOkToStartFrame(header) && HasRequiredStreamId(header)) { visitor()->OnPriority(header.stream_id, priority.stream_dependency, priority.weight, priority.is_exclusive); @@ -509,7 +510,7 @@ void Http2DecoderAdapter::OnPriorityFrame(const Http2FrameHeader& header, } void Http2DecoderAdapter::OnContinuationStart(const Http2FrameHeader& header) { - SPDY_DVLOG(1) << "OnContinuationStart: " << header; + QUICHE_DVLOG(1) << "OnContinuationStart: " << header; if (IsOkToStartFrame(header) && HasRequiredStreamId(header)) { QUICHE_DCHECK(has_hpack_first_frame_header_); if (header.stream_id != hpack_first_frame_header_.stream_id) { @@ -524,12 +525,12 @@ void Http2DecoderAdapter::OnContinuationStart(const Http2FrameHeader& header) { } void Http2DecoderAdapter::OnContinuationEnd() { - SPDY_DVLOG(1) << "OnContinuationEnd"; + QUICHE_DVLOG(1) << "OnContinuationEnd"; CommonHpackFragmentEnd(); } void Http2DecoderAdapter::OnPadLength(size_t trailing_length) { - SPDY_DVLOG(1) << "OnPadLength: " << trailing_length; + QUICHE_DVLOG(1) << "OnPadLength: " << trailing_length; opt_pad_length_ = trailing_length; QUICHE_DCHECK_LT(trailing_length, 256u); if (frame_header_.type == Http2FrameType::DATA) { @@ -539,7 +540,7 @@ void Http2DecoderAdapter::OnPadLength(size_t trailing_length) { void Http2DecoderAdapter::OnPadding(const char* /*padding*/, size_t skipped_length) { - SPDY_DVLOG(1) << "OnPadding: " << skipped_length; + QUICHE_DVLOG(1) << "OnPadding: " << skipped_length; if (frame_header_.type == Http2FrameType::DATA) { visitor()->OnStreamPadding(stream_id(), skipped_length); } else { @@ -549,7 +550,7 @@ void Http2DecoderAdapter::OnPadding(const char* /*padding*/, void Http2DecoderAdapter::OnRstStream(const Http2FrameHeader& header, Http2ErrorCode http2_error_code) { - SPDY_DVLOG(1) << "OnRstStream: " << header << "; code=" << http2_error_code; + QUICHE_DVLOG(1) << "OnRstStream: " << header << "; code=" << http2_error_code; if (IsOkToStartFrame(header) && HasRequiredStreamId(header)) { SpdyErrorCode error_code = ParseErrorCode(static_cast<uint32_t>(http2_error_code)); @@ -558,7 +559,7 @@ void Http2DecoderAdapter::OnRstStream(const Http2FrameHeader& header, } void Http2DecoderAdapter::OnSettingsStart(const Http2FrameHeader& header) { - SPDY_DVLOG(1) << "OnSettingsStart: " << header; + QUICHE_DVLOG(1) << "OnSettingsStart: " << header; if (IsOkToStartFrame(header) && HasRequiredStreamIdZero(header)) { frame_header_ = header; has_frame_header_ = true; @@ -567,7 +568,7 @@ void Http2DecoderAdapter::OnSettingsStart(const Http2FrameHeader& header) { } void Http2DecoderAdapter::OnSetting(const Http2SettingFields& setting_fields) { - SPDY_DVLOG(1) << "OnSetting: " << setting_fields; + QUICHE_DVLOG(1) << "OnSetting: " << setting_fields; const auto parameter = static_cast<SpdySettingsId>(setting_fields.parameter); visitor()->OnSetting(parameter, setting_fields.value); if (extension_ != nullptr) { @@ -576,12 +577,12 @@ void Http2DecoderAdapter::OnSetting(const Http2SettingFields& setting_fields) { } void Http2DecoderAdapter::OnSettingsEnd() { - SPDY_DVLOG(1) << "OnSettingsEnd"; + QUICHE_DVLOG(1) << "OnSettingsEnd"; visitor()->OnSettingsEnd(); } void Http2DecoderAdapter::OnSettingsAck(const Http2FrameHeader& header) { - SPDY_DVLOG(1) << "OnSettingsAck: " << header; + QUICHE_DVLOG(1) << "OnSettingsAck: " << header; if (IsOkToStartFrame(header) && HasRequiredStreamIdZero(header)) { visitor()->OnSettingsAck(); } @@ -591,8 +592,9 @@ void Http2DecoderAdapter::OnPushPromiseStart( const Http2FrameHeader& header, const Http2PushPromiseFields& promise, size_t total_padding_length) { - SPDY_DVLOG(1) << "OnPushPromiseStart: " << header << "; promise: " << promise - << "; total_padding_length: " << total_padding_length; + QUICHE_DVLOG(1) << "OnPushPromiseStart: " << header + << "; promise: " << promise + << "; total_padding_length: " << total_padding_length; if (IsOkToStartFrame(header) && HasRequiredStreamId(header)) { if (promise.promised_stream_id == 0) { SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_CONTROL_FRAME, ""); @@ -608,14 +610,14 @@ void Http2DecoderAdapter::OnPushPromiseStart( } void Http2DecoderAdapter::OnPushPromiseEnd() { - SPDY_DVLOG(1) << "OnPushPromiseEnd"; + QUICHE_DVLOG(1) << "OnPushPromiseEnd"; CommonHpackFragmentEnd(); opt_pad_length_.reset(); } void Http2DecoderAdapter::OnPing(const Http2FrameHeader& header, const Http2PingFields& ping) { - SPDY_DVLOG(1) << "OnPing: " << header << "; ping: " << ping; + QUICHE_DVLOG(1) << "OnPing: " << header << "; ping: " << ping; if (IsOkToStartFrame(header) && HasRequiredStreamIdZero(header)) { visitor()->OnPing(ToSpdyPingId(ping), false); } @@ -623,7 +625,7 @@ void Http2DecoderAdapter::OnPing(const Http2FrameHeader& header, void Http2DecoderAdapter::OnPingAck(const Http2FrameHeader& header, const Http2PingFields& ping) { - SPDY_DVLOG(1) << "OnPingAck: " << header << "; ping: " << ping; + QUICHE_DVLOG(1) << "OnPingAck: " << header << "; ping: " << ping; if (IsOkToStartFrame(header) && HasRequiredStreamIdZero(header)) { visitor()->OnPing(ToSpdyPingId(ping), true); } @@ -631,7 +633,7 @@ void Http2DecoderAdapter::OnPingAck(const Http2FrameHeader& header, void Http2DecoderAdapter::OnGoAwayStart(const Http2FrameHeader& header, const Http2GoAwayFields& goaway) { - SPDY_DVLOG(1) << "OnGoAwayStart: " << header << "; goaway: " << goaway; + QUICHE_DVLOG(1) << "OnGoAwayStart: " << header << "; goaway: " << goaway; if (IsOkToStartFrame(header) && HasRequiredStreamIdZero(header)) { frame_header_ = header; has_frame_header_ = true; @@ -642,18 +644,19 @@ void Http2DecoderAdapter::OnGoAwayStart(const Http2FrameHeader& header, } void Http2DecoderAdapter::OnGoAwayOpaqueData(const char* data, size_t len) { - SPDY_DVLOG(1) << "OnGoAwayOpaqueData: len=" << len; + QUICHE_DVLOG(1) << "OnGoAwayOpaqueData: len=" << len; visitor()->OnGoAwayFrameData(data, len); } void Http2DecoderAdapter::OnGoAwayEnd() { - SPDY_DVLOG(1) << "OnGoAwayEnd"; + QUICHE_DVLOG(1) << "OnGoAwayEnd"; visitor()->OnGoAwayFrameData(nullptr, 0); } void Http2DecoderAdapter::OnWindowUpdate(const Http2FrameHeader& header, uint32_t increment) { - SPDY_DVLOG(1) << "OnWindowUpdate: " << header << "; increment=" << increment; + QUICHE_DVLOG(1) << "OnWindowUpdate: " << header + << "; increment=" << increment; if (IsOkToStartFrame(header)) { visitor()->OnWindowUpdate(header.stream_id, increment); } @@ -666,9 +669,9 @@ void Http2DecoderAdapter::OnWindowUpdate(const Http2FrameHeader& header, void Http2DecoderAdapter::OnAltSvcStart(const Http2FrameHeader& header, size_t origin_length, size_t value_length) { - SPDY_DVLOG(1) << "OnAltSvcStart: " << header - << "; origin_length: " << origin_length - << "; value_length: " << value_length; + QUICHE_DVLOG(1) << "OnAltSvcStart: " << header + << "; origin_length: " << origin_length + << "; value_length: " << value_length; if (!IsOkToStartFrame(header)) { return; } @@ -679,24 +682,24 @@ void Http2DecoderAdapter::OnAltSvcStart(const Http2FrameHeader& header, } void Http2DecoderAdapter::OnAltSvcOriginData(const char* data, size_t len) { - SPDY_DVLOG(1) << "OnAltSvcOriginData: len=" << len; + QUICHE_DVLOG(1) << "OnAltSvcOriginData: len=" << len; alt_svc_origin_.append(data, len); } // Called when decoding the Alt-Svc-Field-Value of an ALTSVC; // the field is uninterpreted. void Http2DecoderAdapter::OnAltSvcValueData(const char* data, size_t len) { - SPDY_DVLOG(1) << "OnAltSvcValueData: len=" << len; + QUICHE_DVLOG(1) << "OnAltSvcValueData: len=" << len; alt_svc_value_.append(data, len); } void Http2DecoderAdapter::OnAltSvcEnd() { - SPDY_DVLOG(1) << "OnAltSvcEnd: origin.size(): " << alt_svc_origin_.size() - << "; value.size(): " << alt_svc_value_.size(); + QUICHE_DVLOG(1) << "OnAltSvcEnd: origin.size(): " << alt_svc_origin_.size() + << "; value.size(): " << alt_svc_value_.size(); SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector; if (!SpdyAltSvcWireFormat::ParseHeaderFieldValue(alt_svc_value_, &altsvc_vector)) { - SPDY_DLOG(ERROR) << "SpdyAltSvcWireFormat::ParseHeaderFieldValue failed."; + QUICHE_DLOG(ERROR) << "SpdyAltSvcWireFormat::ParseHeaderFieldValue failed."; SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_CONTROL_FRAME, ""); return; } @@ -711,9 +714,9 @@ void Http2DecoderAdapter::OnAltSvcEnd() { void Http2DecoderAdapter::OnPriorityUpdateStart( const Http2FrameHeader& header, const Http2PriorityUpdateFields& priority_update) { - SPDY_DVLOG(1) << "OnPriorityUpdateStart: " << header - << "; prioritized_stream_id: " - << priority_update.prioritized_stream_id; + QUICHE_DVLOG(1) << "OnPriorityUpdateStart: " << header + << "; prioritized_stream_id: " + << priority_update.prioritized_stream_id; if (IsOkToStartFrame(header) && HasRequiredStreamIdZero(header) && HasRequiredStreamId(priority_update.prioritized_stream_id)) { frame_header_ = header; @@ -724,13 +727,13 @@ void Http2DecoderAdapter::OnPriorityUpdateStart( void Http2DecoderAdapter::OnPriorityUpdatePayload(const char* data, size_t len) { - SPDY_DVLOG(1) << "OnPriorityUpdatePayload: len=" << len; + QUICHE_DVLOG(1) << "OnPriorityUpdatePayload: len=" << len; priority_field_value_.append(data, len); } void Http2DecoderAdapter::OnPriorityUpdateEnd() { - SPDY_DVLOG(1) << "OnPriorityUpdateEnd: priority_field_value.size(): " - << priority_field_value_.size(); + QUICHE_DVLOG(1) << "OnPriorityUpdateEnd: priority_field_value.size(): " + << priority_field_value_.size(); visitor()->OnPriorityUpdate(prioritized_stream_id_, priority_field_value_); priority_field_value_.clear(); } @@ -738,7 +741,7 @@ void Http2DecoderAdapter::OnPriorityUpdateEnd() { // Except for BLOCKED frames, all other unknown frames are either dropped or // passed to a registered extension. void Http2DecoderAdapter::OnUnknownStart(const Http2FrameHeader& header) { - SPDY_DVLOG(1) << "OnUnknownStart: " << header; + QUICHE_DVLOG(1) << "OnUnknownStart: " << header; if (IsOkToStartFrame(header)) { if (extension_ != nullptr) { const uint8_t type = static_cast<uint8_t>(header.type); @@ -753,19 +756,19 @@ void Http2DecoderAdapter::OnUnknownPayload(const char* data, size_t len) { if (handling_extension_payload_) { extension_->OnFramePayload(data, len); } else { - SPDY_DVLOG(1) << "OnUnknownPayload: len=" << len; + QUICHE_DVLOG(1) << "OnUnknownPayload: len=" << len; } } void Http2DecoderAdapter::OnUnknownEnd() { - SPDY_DVLOG(1) << "OnUnknownEnd"; + QUICHE_DVLOG(1) << "OnUnknownEnd"; handling_extension_payload_ = false; } void Http2DecoderAdapter::OnPaddingTooLong(const Http2FrameHeader& header, size_t missing_length) { - SPDY_DVLOG(1) << "OnPaddingTooLong: " << header - << "; missing_length: " << missing_length; + QUICHE_DVLOG(1) << "OnPaddingTooLong: " << header + << "; missing_length: " << missing_length; if (header.type == Http2FrameType::DATA) { if (header.payload_length == 0) { QUICHE_DCHECK_EQ(1u, missing_length); @@ -778,7 +781,7 @@ void Http2DecoderAdapter::OnPaddingTooLong(const Http2FrameHeader& header, } void Http2DecoderAdapter::OnFrameSizeError(const Http2FrameHeader& header) { - SPDY_DVLOG(1) << "OnFrameSizeError: " << header; + QUICHE_DVLOG(1) << "OnFrameSizeError: " << header; size_t recv_limit = recv_frame_size_limit_; if (header.payload_length > recv_limit) { SetSpdyErrorAndNotify(SpdyFramerError::SPDY_OVERSIZED_PAYLOAD, ""); @@ -809,8 +812,8 @@ size_t Http2DecoderAdapter::ProcessInputFrame(const char* data, size_t len) { if (spdy_state_ != SpdyState::SPDY_ERROR) { DetermineSpdyState(status); } else { - SPDY_VLOG(1) << "ProcessInputFrame spdy_framer_error_=" - << SpdyFramerErrorToString(spdy_framer_error_); + QUICHE_VLOG(1) << "ProcessInputFrame spdy_framer_error_=" + << SpdyFramerErrorToString(spdy_framer_error_); if (spdy_framer_error_ == SpdyFramerError::SPDY_INVALID_PADDING && has_frame_header_ && frame_type() != Http2FrameType::DATA) { // spdy_framer_test checks that all of the available frame payload @@ -818,11 +821,11 @@ size_t Http2DecoderAdapter::ProcessInputFrame(const char* data, size_t len) { size_t total = remaining_total_payload(); if (total <= frame_header().payload_length) { size_t avail = db.MinLengthRemaining(total); - SPDY_VLOG(1) << "Skipping past " << avail << " bytes, of " << total - << " total remaining in the frame's payload."; + QUICHE_VLOG(1) << "Skipping past " << avail << " bytes, of " << total + << " total remaining in the frame's payload."; db.AdvanceCursor(avail); } else { - SPDY_BUG(spdy_bug_1_2) + QUICHE_BUG(spdy_bug_1_2) << "Total remaining (" << total << ") should not be greater than the payload length; " << frame_header(); @@ -841,11 +844,11 @@ void Http2DecoderAdapter::DetermineSpdyState(DecodeStatus status) { QUICHE_DCHECK(!HasError()) << spdy_framer_error_; switch (status) { case DecodeStatus::kDecodeDone: - SPDY_DVLOG(1) << "ProcessInputFrame -> DecodeStatus::kDecodeDone"; + QUICHE_DVLOG(1) << "ProcessInputFrame -> DecodeStatus::kDecodeDone"; ResetBetweenFrames(); break; case DecodeStatus::kDecodeInProgress: - SPDY_DVLOG(1) << "ProcessInputFrame -> DecodeStatus::kDecodeInProgress"; + QUICHE_DVLOG(1) << "ProcessInputFrame -> DecodeStatus::kDecodeInProgress"; if (decoded_frame_header_) { if (IsDiscardingPayload()) { set_spdy_state(SpdyState::SPDY_IGNORE_REMAINING_PAYLOAD); @@ -865,7 +868,7 @@ void Http2DecoderAdapter::DetermineSpdyState(DecodeStatus status) { } break; case DecodeStatus::kDecodeError: - SPDY_VLOG(1) << "ProcessInputFrame -> DecodeStatus::kDecodeError"; + QUICHE_VLOG(1) << "ProcessInputFrame -> DecodeStatus::kDecodeError"; if (IsDiscardingPayload()) { if (remaining_total_payload() == 0) { // Push the Http2FrameDecoder out of state kDiscardPayload now @@ -873,11 +876,11 @@ void Http2DecoderAdapter::DetermineSpdyState(DecodeStatus status) { DecodeBuffer tmp("", 0); DecodeStatus status = frame_decoder_->DecodeFrame(&tmp); if (status != DecodeStatus::kDecodeDone) { - SPDY_BUG(spdy_bug_1_3) + QUICHE_BUG(spdy_bug_1_3) << "Expected to be done decoding the frame, not " << status; SetSpdyErrorAndNotify(SPDY_INTERNAL_FRAMER_ERROR, ""); } else if (spdy_framer_error_ != SPDY_NO_ERROR) { - SPDY_BUG(spdy_bug_1_4) + QUICHE_BUG(spdy_bug_1_4) << "Expected to have no error, not " << SpdyFramerErrorToString(spdy_framer_error_); } else { @@ -921,7 +924,7 @@ void Http2DecoderAdapter::ResetInternal() { } void Http2DecoderAdapter::set_spdy_state(SpdyState v) { - SPDY_DVLOG(2) << "set_spdy_state(" << StateToString(v) << ")"; + QUICHE_DVLOG(2) << "set_spdy_state(" << StateToString(v) << ")"; spdy_state_ = v; } @@ -930,8 +933,8 @@ void Http2DecoderAdapter::SetSpdyErrorAndNotify(SpdyFramerError error, if (HasError()) { QUICHE_DCHECK_EQ(spdy_state_, SpdyState::SPDY_ERROR); } else { - SPDY_VLOG(2) << "SetSpdyErrorAndNotify(" << SpdyFramerErrorToString(error) - << ")"; + QUICHE_VLOG(2) << "SetSpdyErrorAndNotify(" << SpdyFramerErrorToString(error) + << ")"; QUICHE_DCHECK_NE(error, SpdyFramerError::SPDY_NO_ERROR); spdy_framer_error_ = error; set_spdy_state(SpdyState::SPDY_ERROR); @@ -974,33 +977,33 @@ size_t Http2DecoderAdapter::remaining_total_payload() const { bool Http2DecoderAdapter::IsReadingPaddingLength() { bool result = frame_header_.IsPadded() && !opt_pad_length_; - SPDY_DVLOG(2) << "Http2DecoderAdapter::IsReadingPaddingLength: " << result; + QUICHE_DVLOG(2) << "Http2DecoderAdapter::IsReadingPaddingLength: " << result; return result; } bool Http2DecoderAdapter::IsSkippingPadding() { bool result = frame_header_.IsPadded() && opt_pad_length_ && frame_decoder_->remaining_payload() == 0 && frame_decoder_->remaining_padding() > 0; - SPDY_DVLOG(2) << "Http2DecoderAdapter::IsSkippingPadding: " << result; + QUICHE_DVLOG(2) << "Http2DecoderAdapter::IsSkippingPadding: " << result; return result; } bool Http2DecoderAdapter::IsDiscardingPayload() { bool result = decoded_frame_header_ && frame_decoder_->IsDiscardingPayload(); - SPDY_DVLOG(2) << "Http2DecoderAdapter::IsDiscardingPayload: " << result; + QUICHE_DVLOG(2) << "Http2DecoderAdapter::IsDiscardingPayload: " << result; return result; } // Called from OnXyz or OnXyzStart methods to decide whether it is OK to // handle the callback. bool Http2DecoderAdapter::IsOkToStartFrame(const Http2FrameHeader& header) { - SPDY_DVLOG(3) << "IsOkToStartFrame"; + QUICHE_DVLOG(3) << "IsOkToStartFrame"; if (HasError()) { - SPDY_VLOG(2) << "HasError()"; + QUICHE_VLOG(2) << "HasError()"; return false; } QUICHE_DCHECK(!has_frame_header_); if (has_expected_frame_type_ && header.type != expected_frame_type_) { - SPDY_VLOG(1) << "Expected frame type " << expected_frame_type_ << ", not " - << header.type; + QUICHE_VLOG(1) << "Expected frame type " << expected_frame_type_ << ", not " + << header.type; SetSpdyErrorAndNotify(SpdyFramerError::SPDY_UNEXPECTED_FRAME, ""); return false; } @@ -1009,15 +1012,15 @@ bool Http2DecoderAdapter::IsOkToStartFrame(const Http2FrameHeader& header) { } bool Http2DecoderAdapter::HasRequiredStreamId(uint32_t stream_id) { - SPDY_DVLOG(3) << "HasRequiredStreamId: " << stream_id; + QUICHE_DVLOG(3) << "HasRequiredStreamId: " << stream_id; if (HasError()) { - SPDY_VLOG(2) << "HasError()"; + QUICHE_VLOG(2) << "HasError()"; return false; } if (stream_id != 0) { return true; } - SPDY_VLOG(1) << "Stream Id is required, but zero provided"; + QUICHE_VLOG(1) << "Stream Id is required, but zero provided"; SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_STREAM_ID, ""); return false; } @@ -1027,15 +1030,15 @@ bool Http2DecoderAdapter::HasRequiredStreamId(const Http2FrameHeader& header) { } bool Http2DecoderAdapter::HasRequiredStreamIdZero(uint32_t stream_id) { - SPDY_DVLOG(3) << "HasRequiredStreamIdZero: " << stream_id; + QUICHE_DVLOG(3) << "HasRequiredStreamIdZero: " << stream_id; if (HasError()) { - SPDY_VLOG(2) << "HasError()"; + QUICHE_VLOG(2) << "HasError()"; return false; } if (stream_id == 0) { return true; } - SPDY_VLOG(1) << "Stream Id was not zero, as required: " << stream_id; + QUICHE_VLOG(1) << "Stream Id was not zero, as required: " << stream_id; SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_STREAM_ID, ""); return false; } @@ -1062,7 +1065,7 @@ HpackDecoderAdapter* Http2DecoderAdapter::GetHpackDecoder() { } void Http2DecoderAdapter::CommonStartHpackBlock() { - SPDY_DVLOG(1) << "CommonStartHpackBlock"; + QUICHE_DVLOG(1) << "CommonStartHpackBlock"; QUICHE_DCHECK(!has_hpack_first_frame_header_); if (!frame_header_.IsEndHeaders()) { hpack_first_frame_header_ = frame_header_; @@ -1074,7 +1077,7 @@ void Http2DecoderAdapter::CommonStartHpackBlock() { SpdyHeadersHandlerInterface* handler = visitor()->OnHeaderFrameStart(stream_id()); if (handler == nullptr) { - SPDY_BUG(spdy_bug_1_5) << "visitor_->OnHeaderFrameStart returned nullptr"; + QUICHE_BUG(spdy_bug_1_5) << "visitor_->OnHeaderFrameStart returned nullptr"; SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INTERNAL_FRAMER_ERROR, ""); return; } @@ -1091,9 +1094,9 @@ void Http2DecoderAdapter::MaybeAnnounceEmptyFirstHpackFragment() { } void Http2DecoderAdapter::CommonHpackFragmentEnd() { - SPDY_DVLOG(1) << "CommonHpackFragmentEnd: stream_id=" << stream_id(); + QUICHE_DVLOG(1) << "CommonHpackFragmentEnd: stream_id=" << stream_id(); if (HasError()) { - SPDY_VLOG(1) << "HasError(), returning"; + QUICHE_VLOG(1) << "HasError(), returning"; return; } QUICHE_DCHECK(has_frame_header_); 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 5b6af98a9ac..94218f697da 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 @@ -9,7 +9,8 @@ #include <limits> #include "absl/strings/str_cat.h" -#include "spdy/platform/api/spdy_logging.h" + +#include "common/platform/api/quiche_logging.h" #include "spdy/platform/api/spdy_string_utils.h" namespace spdy { @@ -195,9 +196,9 @@ bool SpdyAltSvcWireFormat::ParseHeaderFieldValue( // hq=":443";quic=51303338 // ... will be stored in |versions| as 0x51303338. uint32_t quic_version; - if (!SpdyHexDecodeToUInt32(absl::string_view(&*parameter_value_begin, - c - parameter_value_begin), - &quic_version) || + if (!HexDecodeToUInt32(absl::string_view(&*parameter_value_begin, + c - parameter_value_begin), + &quic_version) || quic_version == 0) { return false; } @@ -314,12 +315,12 @@ bool SpdyAltSvcWireFormat::PercentDecode(absl::string_view::const_iterator c, return false; } // Network byte order is big-endian. - char decoded = SpdyHexDigitToInt(*c) << 4; + char decoded = HexDigitToInt(*c) << 4; ++c; if (c == end || !std::isxdigit(*c)) { return false; } - decoded += SpdyHexDigitToInt(*c); + decoded += HexDigitToInt(*c); output->push_back(decoded); } return true; @@ -388,4 +389,41 @@ bool SpdyAltSvcWireFormat::ParsePositiveInteger32( return ParsePositiveIntegerImpl<uint32_t>(c, end, value); } +// static +char SpdyAltSvcWireFormat::HexDigitToInt(char c) { + QUICHE_DCHECK(std::isxdigit(c)); + + if (std::isdigit(c)) { + return c - '0'; + } + if (c >= 'A' && c <= 'F') { + return c - 'A' + 10; + } + if (c >= 'a' && c <= 'f') { + return c - 'a' + 10; + } + + return 0; +} + +// static +bool SpdyAltSvcWireFormat::HexDecodeToUInt32(absl::string_view data, + uint32_t* value) { + if (data.empty() || data.length() > 8u) { + return false; + } + + *value = 0; + for (char c : data) { + if (!std::isxdigit(c)) { + return false; + } + + *value <<= 4; + *value += HexDigitToInt(c); + } + + return true; +} + } // namespace spdy 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 fccda75ac6e..a8e10948a8c 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 @@ -66,21 +66,40 @@ class QUICHE_EXPORT_PRIVATE SpdyAltSvcWireFormat { const AlternativeServiceVector& altsvc_vector); private: + // Forward |*c| over space and tab or until |end| is reached. static void SkipWhiteSpace(absl::string_view::const_iterator* c, absl::string_view::const_iterator end); + // Decode percent-decoded string between |c| and |end| into |*output|. + // Return true on success, false if input is invalid. static bool PercentDecode(absl::string_view::const_iterator c, absl::string_view::const_iterator end, std::string* output); + // Parse the authority part of Alt-Svc between |c| and |end| into |*host| and + // |*port|. Return true on success, false if input is invalid. static bool ParseAltAuthority(absl::string_view::const_iterator c, absl::string_view::const_iterator end, std::string* host, uint16_t* port); + // Parse a positive integer between |c| and |end| into |*value|. + // Return true on success, false if input is not a positive integer or it + // cannot be represented on uint16_t. static bool ParsePositiveInteger16(absl::string_view::const_iterator c, absl::string_view::const_iterator end, uint16_t* value); + // Parse a positive integer between |c| and |end| into |*value|. + // Return true on success, false if input is not a positive integer or it + // cannot be represented on uint32_t. static bool ParsePositiveInteger32(absl::string_view::const_iterator c, absl::string_view::const_iterator end, uint32_t* value); + // Parse |c| as hexadecimal digit, case insensitive. |c| must be [0-9a-fA-F]. + // Output is between 0 and 15. + static char HexDigitToInt(char c); + // Parse |data| as hexadecimal number into |*value|. |data| must only contain + // hexadecimal digits, no "0x" prefix. + // Return true on success, false if input is empty, not valid hexadecimal + // number, or cannot be represented on uint32_t. + static bool HexDecodeToUInt32(absl::string_view data, uint32_t* value); }; } // namespace spdy 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 e698c2f690b..497f19dad86 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 @@ -5,7 +5,6 @@ #include "spdy/core/spdy_alt_svc_wire_format.h" #include "common/platform/api/quiche_test.h" -#include "spdy/platform/api/spdy_logging.h" namespace spdy { @@ -39,10 +38,14 @@ class SpdyAltSvcWireFormatPeer { uint32_t* max_age) { return SpdyAltSvcWireFormat::ParsePositiveInteger32(c, end, max_age); } + static char HexDigitToInt(char c) { + return SpdyAltSvcWireFormat::HexDigitToInt(c); + } + static bool HexDecodeToUInt32(absl::string_view data, uint32_t* value) { + return SpdyAltSvcWireFormat::HexDecodeToUInt32(data, value); + } }; -} // namespace test - namespace { // Generate header field values, possibly with multiply defined parameters and @@ -389,13 +392,13 @@ TEST(SpdyAltSvcWireFormatTest, ParseTruncatedHeaderFieldValue) { TEST(SpdyAltSvcWireFormatTest, SkipWhiteSpace) { absl::string_view input("a \tb "); absl::string_view::const_iterator c = input.begin(); - test::SpdyAltSvcWireFormatPeer::SkipWhiteSpace(&c, input.end()); + SpdyAltSvcWireFormatPeer::SkipWhiteSpace(&c, input.end()); ASSERT_EQ(input.begin(), c); ++c; - test::SpdyAltSvcWireFormatPeer::SkipWhiteSpace(&c, input.end()); + SpdyAltSvcWireFormatPeer::SkipWhiteSpace(&c, input.end()); ASSERT_EQ(input.begin() + 3, c); ++c; - test::SpdyAltSvcWireFormatPeer::SkipWhiteSpace(&c, input.end()); + SpdyAltSvcWireFormatPeer::SkipWhiteSpace(&c, input.end()); ASSERT_EQ(input.end(), c); } @@ -403,20 +406,20 @@ TEST(SpdyAltSvcWireFormatTest, SkipWhiteSpace) { TEST(SpdyAltSvcWireFormatTest, PercentDecodeValid) { absl::string_view input(""); std::string output; - ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::PercentDecode( - input.begin(), input.end(), &output)); + ASSERT_TRUE(SpdyAltSvcWireFormatPeer::PercentDecode(input.begin(), + input.end(), &output)); EXPECT_EQ("", output); input = absl::string_view("foo"); output.clear(); - ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::PercentDecode( - input.begin(), input.end(), &output)); + ASSERT_TRUE(SpdyAltSvcWireFormatPeer::PercentDecode(input.begin(), + input.end(), &output)); EXPECT_EQ("foo", output); input = absl::string_view("%2ca%5Cb"); output.clear(); - ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::PercentDecode( - input.begin(), input.end(), &output)); + ASSERT_TRUE(SpdyAltSvcWireFormatPeer::PercentDecode(input.begin(), + input.end(), &output)); EXPECT_EQ(",a\\b", output); } @@ -426,8 +429,8 @@ TEST(SpdyAltSvcWireFormatTest, PercentDecodeInvalid) { for (const char* invalid_input : invalid_input_array) { absl::string_view input(invalid_input); std::string output; - EXPECT_FALSE(test::SpdyAltSvcWireFormatPeer::PercentDecode( - input.begin(), input.end(), &output)) + EXPECT_FALSE(SpdyAltSvcWireFormatPeer::PercentDecode(input.begin(), + input.end(), &output)) << input; } } @@ -437,19 +440,19 @@ TEST(SpdyAltSvcWireFormatTest, ParseAltAuthorityValid) { absl::string_view input(":42"); std::string host; uint16_t port; - ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::ParseAltAuthority( + ASSERT_TRUE(SpdyAltSvcWireFormatPeer::ParseAltAuthority( input.begin(), input.end(), &host, &port)); EXPECT_TRUE(host.empty()); EXPECT_EQ(42, port); input = absl::string_view("foo:137"); - ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::ParseAltAuthority( + ASSERT_TRUE(SpdyAltSvcWireFormatPeer::ParseAltAuthority( input.begin(), input.end(), &host, &port)); EXPECT_EQ("foo", host); EXPECT_EQ(137, port); input = absl::string_view("[2003:8:0:16::509d:9615]:443"); - ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::ParseAltAuthority( + ASSERT_TRUE(SpdyAltSvcWireFormatPeer::ParseAltAuthority( input.begin(), input.end(), &host, &port)); EXPECT_EQ("[2003:8:0:16::509d:9615]", host); EXPECT_EQ(443, port); @@ -478,7 +481,7 @@ TEST(SpdyAltSvcWireFormatTest, ParseAltAuthorityInvalid) { absl::string_view input(invalid_input); std::string host; uint16_t port; - EXPECT_FALSE(test::SpdyAltSvcWireFormatPeer::ParseAltAuthority( + EXPECT_FALSE(SpdyAltSvcWireFormatPeer::ParseAltAuthority( input.begin(), input.end(), &host, &port)) << input; } @@ -488,12 +491,12 @@ TEST(SpdyAltSvcWireFormatTest, ParseAltAuthorityInvalid) { TEST(SpdyAltSvcWireFormatTest, ParseIntegerValid) { absl::string_view input("3"); uint16_t value; - ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::ParsePositiveInteger16( + ASSERT_TRUE(SpdyAltSvcWireFormatPeer::ParsePositiveInteger16( input.begin(), input.end(), &value)); EXPECT_EQ(3, value); input = absl::string_view("1337"); - ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::ParsePositiveInteger16( + ASSERT_TRUE(SpdyAltSvcWireFormatPeer::ParsePositiveInteger16( input.begin(), input.end(), &value)); EXPECT_EQ(1337, value); } @@ -505,7 +508,7 @@ TEST(SpdyAltSvcWireFormatTest, ParseIntegerInvalid) { for (const char* invalid_input : invalid_input_array) { absl::string_view input(invalid_input); uint16_t value; - EXPECT_FALSE(test::SpdyAltSvcWireFormatPeer::ParsePositiveInteger16( + EXPECT_FALSE(SpdyAltSvcWireFormatPeer::ParsePositiveInteger16( input.begin(), input.end(), &value)) << input; } @@ -516,38 +519,38 @@ TEST(SpdyAltSvcWireFormatTest, ParseIntegerOverflow) { // Largest possible uint16_t value. absl::string_view input("65535"); uint16_t value16; - ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::ParsePositiveInteger16( + ASSERT_TRUE(SpdyAltSvcWireFormatPeer::ParsePositiveInteger16( input.begin(), input.end(), &value16)); EXPECT_EQ(65535, value16); // Overflow uint16_t, ParsePositiveInteger16() should return false. input = absl::string_view("65536"); - ASSERT_FALSE(test::SpdyAltSvcWireFormatPeer::ParsePositiveInteger16( + ASSERT_FALSE(SpdyAltSvcWireFormatPeer::ParsePositiveInteger16( input.begin(), input.end(), &value16)); // However, even if overflow is not checked for, 65536 overflows to 0, which // returns false anyway. Check for a larger number which overflows to 1. input = absl::string_view("65537"); - ASSERT_FALSE(test::SpdyAltSvcWireFormatPeer::ParsePositiveInteger16( + ASSERT_FALSE(SpdyAltSvcWireFormatPeer::ParsePositiveInteger16( input.begin(), input.end(), &value16)); // Largest possible uint32_t value. input = absl::string_view("4294967295"); uint32_t value32; - ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::ParsePositiveInteger32( + ASSERT_TRUE(SpdyAltSvcWireFormatPeer::ParsePositiveInteger32( input.begin(), input.end(), &value32)); EXPECT_EQ(4294967295, value32); // Overflow uint32_t, ParsePositiveInteger32() should return false. input = absl::string_view("4294967296"); - ASSERT_FALSE(test::SpdyAltSvcWireFormatPeer::ParsePositiveInteger32( + ASSERT_FALSE(SpdyAltSvcWireFormatPeer::ParsePositiveInteger32( input.begin(), input.end(), &value32)); // However, even if overflow is not checked for, 4294967296 overflows to 0, // which returns false anyway. Check for a larger number which overflows to // 1. input = absl::string_view("4294967297"); - ASSERT_FALSE(test::SpdyAltSvcWireFormatPeer::ParsePositiveInteger32( + ASSERT_FALSE(SpdyAltSvcWireFormatPeer::ParsePositiveInteger32( input.begin(), input.end(), &value32)); } @@ -567,6 +570,64 @@ TEST(SpdyAltSvcWireFormatTest, ParseIPLiteral) { EXPECT_THAT(altsvc_vector[0].version, ::testing::ElementsAre(36, 35)); } +TEST(SpdyAltSvcWireFormatTest, HexDigitToInt) { + EXPECT_EQ(0, SpdyAltSvcWireFormatPeer::HexDigitToInt('0')); + EXPECT_EQ(1, SpdyAltSvcWireFormatPeer::HexDigitToInt('1')); + EXPECT_EQ(2, SpdyAltSvcWireFormatPeer::HexDigitToInt('2')); + EXPECT_EQ(3, SpdyAltSvcWireFormatPeer::HexDigitToInt('3')); + EXPECT_EQ(4, SpdyAltSvcWireFormatPeer::HexDigitToInt('4')); + EXPECT_EQ(5, SpdyAltSvcWireFormatPeer::HexDigitToInt('5')); + EXPECT_EQ(6, SpdyAltSvcWireFormatPeer::HexDigitToInt('6')); + EXPECT_EQ(7, SpdyAltSvcWireFormatPeer::HexDigitToInt('7')); + EXPECT_EQ(8, SpdyAltSvcWireFormatPeer::HexDigitToInt('8')); + EXPECT_EQ(9, SpdyAltSvcWireFormatPeer::HexDigitToInt('9')); + + EXPECT_EQ(10, SpdyAltSvcWireFormatPeer::HexDigitToInt('a')); + EXPECT_EQ(11, SpdyAltSvcWireFormatPeer::HexDigitToInt('b')); + EXPECT_EQ(12, SpdyAltSvcWireFormatPeer::HexDigitToInt('c')); + EXPECT_EQ(13, SpdyAltSvcWireFormatPeer::HexDigitToInt('d')); + EXPECT_EQ(14, SpdyAltSvcWireFormatPeer::HexDigitToInt('e')); + EXPECT_EQ(15, SpdyAltSvcWireFormatPeer::HexDigitToInt('f')); + + EXPECT_EQ(10, SpdyAltSvcWireFormatPeer::HexDigitToInt('A')); + EXPECT_EQ(11, SpdyAltSvcWireFormatPeer::HexDigitToInt('B')); + EXPECT_EQ(12, SpdyAltSvcWireFormatPeer::HexDigitToInt('C')); + EXPECT_EQ(13, SpdyAltSvcWireFormatPeer::HexDigitToInt('D')); + EXPECT_EQ(14, SpdyAltSvcWireFormatPeer::HexDigitToInt('E')); + EXPECT_EQ(15, SpdyAltSvcWireFormatPeer::HexDigitToInt('F')); +} + +TEST(SpdyAltSvcWireFormatTest, HexDecodeToUInt32) { + uint32_t out; + EXPECT_TRUE(SpdyAltSvcWireFormatPeer::HexDecodeToUInt32("0", &out)); + EXPECT_EQ(0u, out); + EXPECT_TRUE(SpdyAltSvcWireFormatPeer::HexDecodeToUInt32("00", &out)); + EXPECT_EQ(0u, out); + EXPECT_TRUE(SpdyAltSvcWireFormatPeer::HexDecodeToUInt32("0000000", &out)); + EXPECT_EQ(0u, out); + EXPECT_TRUE(SpdyAltSvcWireFormatPeer::HexDecodeToUInt32("00000000", &out)); + EXPECT_EQ(0u, out); + EXPECT_TRUE(SpdyAltSvcWireFormatPeer::HexDecodeToUInt32("1", &out)); + EXPECT_EQ(1u, out); + EXPECT_TRUE(SpdyAltSvcWireFormatPeer::HexDecodeToUInt32("ffffFFF", &out)); + EXPECT_EQ(0xFFFFFFFu, out); + EXPECT_TRUE(SpdyAltSvcWireFormatPeer::HexDecodeToUInt32("fFfFffFf", &out)); + EXPECT_EQ(0xFFFFFFFFu, out); + EXPECT_TRUE(SpdyAltSvcWireFormatPeer::HexDecodeToUInt32("01AEF", &out)); + EXPECT_EQ(0x1AEFu, out); + EXPECT_TRUE(SpdyAltSvcWireFormatPeer::HexDecodeToUInt32("abcde", &out)); + EXPECT_EQ(0xABCDEu, out); + EXPECT_TRUE(SpdyAltSvcWireFormatPeer::HexDecodeToUInt32("1234abcd", &out)); + EXPECT_EQ(0x1234ABCDu, out); + + EXPECT_FALSE(SpdyAltSvcWireFormatPeer::HexDecodeToUInt32("", &out)); + EXPECT_FALSE(SpdyAltSvcWireFormatPeer::HexDecodeToUInt32("111111111", &out)); + EXPECT_FALSE(SpdyAltSvcWireFormatPeer::HexDecodeToUInt32("1111111111", &out)); + EXPECT_FALSE(SpdyAltSvcWireFormatPeer::HexDecodeToUInt32("0x1111", &out)); +} + } // namespace +} // namespace test + } // namespace spdy diff --git a/chromium/net/third_party/quiche/src/spdy/core/spdy_frame_builder.cc b/chromium/net/third_party/quiche/src/spdy/core/spdy_frame_builder.cc index ee63594ca6c..0b75271bf44 100644 --- a/chromium/net/third_party/quiche/src/spdy/core/spdy_frame_builder.cc +++ b/chromium/net/third_party/quiche/src/spdy/core/spdy_frame_builder.cc @@ -9,10 +9,10 @@ #include <limits> #include <new> +#include "common/platform/api/quiche_bug_tracker.h" +#include "common/platform/api/quiche_logging.h" #include "spdy/core/spdy_protocol.h" #include "spdy/core/zero_copy_output_buffer.h" -#include "spdy/platform/api/spdy_bug_tracker.h" -#include "spdy/platform/api/spdy_logging.h" namespace spdy { @@ -69,7 +69,7 @@ bool SpdyFrameBuilder::BeginNewFrame(SpdyFrameType type, QUICHE_DCHECK_EQ(0u, stream_id & ~kStreamIdMask); bool success = true; if (length_ > 0) { - SPDY_BUG(spdy_bug_73_1) + QUICHE_BUG(spdy_bug_73_1) << "SpdyFrameBuilder doesn't have a clean state when BeginNewFrame" << "is called. Leftover length_ is " << length_; offset_ += length_; @@ -91,7 +91,7 @@ bool SpdyFrameBuilder::BeginNewFrame(SpdyFrameType type, uint8_t raw_frame_type = SerializeFrameType(type); QUICHE_DCHECK(IsDefinedFrameType(raw_frame_type)); QUICHE_DCHECK_EQ(0u, stream_id & ~kStreamIdMask); - SPDY_BUG_IF(spdy_bug_73_2, length > kHttp2DefaultFramePayloadLimit) + QUICHE_BUG_IF(spdy_bug_73_2, length > kHttp2DefaultFramePayloadLimit) << "Frame length " << length_ << " is longer than frame size limit."; return BeginNewFrameInternal(raw_frame_type, flags, stream_id, length); } @@ -168,8 +168,9 @@ bool SpdyFrameBuilder::CanWrite(size_t length) const { if (output_ == nullptr) { if (offset_ + length_ + length > capacity_) { - SPDY_DLOG(FATAL) << "Requested: " << length << " capacity: " << capacity_ - << " used: " << offset_ + length_; + QUICHE_DLOG(FATAL) << "Requested: " << length + << " capacity: " << capacity_ + << " used: " << offset_ + length_; return false; } } else { diff --git a/chromium/net/third_party/quiche/src/spdy/core/spdy_frame_builder.h b/chromium/net/third_party/quiche/src/spdy/core/spdy_frame_builder.h index 01fce6be819..4625aa18a41 100644 --- a/chromium/net/third_party/quiche/src/spdy/core/spdy_frame_builder.h +++ b/chromium/net/third_party/quiche/src/spdy/core/spdy_frame_builder.h @@ -10,11 +10,11 @@ #include <memory> #include "absl/strings/string_view.h" +#include "common/platform/api/quiche_bug_tracker.h" #include "common/platform/api/quiche_export.h" #include "common/quiche_endian.h" #include "spdy/core/spdy_protocol.h" #include "spdy/core/zero_copy_output_buffer.h" -#include "spdy/platform/api/spdy_bug_tracker.h" namespace spdy { @@ -66,10 +66,10 @@ class QUICHE_EXPORT_PRIVATE SpdyFrameBuilder { // Takes the buffer from the SpdyFrameBuilder. SpdySerializedFrame take() { - SPDY_BUG_IF(spdy_bug_39_1, output_ != nullptr) + QUICHE_BUG_IF(spdy_bug_39_1, output_ != nullptr) << "ZeroCopyOutputBuffer is used to build " << "frames. take() shouldn't be called"; - SPDY_BUG_IF(spdy_bug_39_2, kMaxFrameSizeLimit < length_) + QUICHE_BUG_IF(spdy_bug_39_2, kMaxFrameSizeLimit < length_) << "Frame length " << length_ << " is longer than the maximum possible allowed length."; SpdySerializedFrame rv(buffer_.release(), length(), true); 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 bc7cd1767a0..d6f0f889876 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 @@ -13,12 +13,12 @@ #include "absl/memory/memory.h" #include "http2/platform/api/http2_macros.h" +#include "common/platform/api/quiche_bug_tracker.h" +#include "common/platform/api/quiche_logging.h" #include "spdy/core/spdy_bitmasks.h" #include "spdy/core/spdy_frame_builder.h" #include "spdy/core/spdy_frame_reader.h" -#include "spdy/platform/api/spdy_bug_tracker.h" #include "spdy/platform/api/spdy_estimate_memory_usage.h" -#include "spdy/platform/api/spdy_logging.h" #include "spdy/platform/api/spdy_string_utils.h" namespace spdy { @@ -129,7 +129,8 @@ bool SerializeHeadersGivenEncoding(const SpdyHeadersIR& headers, } if (!ret) { - SPDY_DLOG(WARNING) << "Failed to build HEADERS. Not enough space in output"; + QUICHE_DLOG(WARNING) + << "Failed to build HEADERS. Not enough space in output"; } return ret; } @@ -159,7 +160,7 @@ bool SerializePushPromiseGivenEncoding(const SpdyPushPromiseIR& push_promise, ok = builder.WriteBytes(padding.data(), padding.length()); } - SPDY_DLOG_IF(ERROR, !ok) + QUICHE_DLOG_IF(ERROR, !ok) << "Failed to write PUSH_PROMISE encoding, not enough " << "space in output"; return ok; @@ -177,8 +178,8 @@ bool WritePayloadWithContinuation(SpdyFrameBuilder* builder, } else if (type == SpdyFrameType::PUSH_PROMISE) { end_flag = PUSH_PROMISE_FLAG_END_PUSH_PROMISE; } else { - SPDY_DLOG(FATAL) << "CONTINUATION frames cannot be used with frame type " - << FrameTypeToString(type); + QUICHE_DLOG(FATAL) << "CONTINUATION frames cannot be used with frame type " + << FrameTypeToString(type); } // Write all the padding payload and as much of the data payload as possible @@ -294,7 +295,7 @@ SpdyFramer::SpdyFrameIterator::~SpdyFrameIterator() = default; size_t SpdyFramer::SpdyFrameIterator::NextFrame(ZeroCopyOutputBuffer* output) { const SpdyFrameIR& frame_ir = GetIR(); if (!has_next_frame_) { - SPDY_BUG(spdy_bug_75_1) + QUICHE_BUG(spdy_bug_75_1) << "SpdyFramer::SpdyFrameIterator::NextFrame called without " << "a next frame."; return false; @@ -422,7 +423,7 @@ std::unique_ptr<SpdyFrameSequence> SpdyFramer::CreateIterator( frame_ir.release()))); } case SpdyFrameType::DATA: { - SPDY_DVLOG(1) << "Serialize a stream end DATA frame for VTL"; + QUICHE_DVLOG(1) << "Serialize a stream end DATA frame for VTL"; HTTP2_FALLTHROUGH; } default: { 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 d7fb6a7a332..c4b5979a874 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 @@ -14,6 +14,7 @@ #include <vector> #include "absl/base/macros.h" +#include "common/platform/api/quiche_logging.h" #include "common/platform/api/quiche_test.h" #include "spdy/core/array_output_buffer.h" #include "spdy/core/mock_spdy_framer_visitor.h" @@ -23,8 +24,6 @@ #include "spdy/core/spdy_frame_reader.h" #include "spdy/core/spdy_protocol.h" #include "spdy/core/spdy_test_utils.h" -#include "spdy/platform/api/spdy_flags.h" -#include "spdy/platform/api/spdy_logging.h" #include "spdy/platform/api/spdy_string_utils.h" using ::http2::Http2DecoderAdapter; @@ -62,7 +61,7 @@ MATCHER_P(IsFrameUnionOf, frame_list, "") { size_t size_verified = 0; for (const auto& frame : *frame_list) { if (arg.size() < size_verified + frame.size()) { - SPDY_LOG(FATAL) + QUICHE_LOG(FATAL) << "Incremental header serialization should not lead to a " << "higher total frame length than non-incremental method."; return false; @@ -268,16 +267,16 @@ class TestSpdyVisitor : public SpdyFramerVisitorInterface, void OnError(Http2DecoderAdapter::SpdyFramerError error, std::string /*detailed_error*/) override { - SPDY_VLOG(1) << "SpdyFramer Error: " - << Http2DecoderAdapter::SpdyFramerErrorToString(error); + QUICHE_VLOG(1) << "SpdyFramer Error: " + << Http2DecoderAdapter::SpdyFramerErrorToString(error); ++error_count_; } void OnDataFrameHeader(SpdyStreamId stream_id, size_t length, bool fin) override { - SPDY_VLOG(1) << "OnDataFrameHeader(" << stream_id << ", " << length << ", " - << fin << ")"; + QUICHE_VLOG(1) << "OnDataFrameHeader(" << stream_id << ", " << length + << ", " << fin << ")"; ++data_frame_count_; header_stream_id_ = stream_id; } @@ -285,30 +284,30 @@ class TestSpdyVisitor : public SpdyFramerVisitorInterface, void OnStreamFrameData(SpdyStreamId stream_id, const char* data, size_t len) override { - SPDY_VLOG(1) << "OnStreamFrameData(" << stream_id << ", data, " << len - << ", " - << ") data:\n" - << SpdyHexDump(absl::string_view(data, len)); + QUICHE_VLOG(1) << "OnStreamFrameData(" << stream_id << ", data, " << len + << ", " + << ") data:\n" + << SpdyHexDump(absl::string_view(data, len)); EXPECT_EQ(header_stream_id_, stream_id); data_bytes_ += len; } void OnStreamEnd(SpdyStreamId stream_id) override { - SPDY_VLOG(1) << "OnStreamEnd(" << stream_id << ")"; + QUICHE_VLOG(1) << "OnStreamEnd(" << stream_id << ")"; EXPECT_EQ(header_stream_id_, stream_id); ++end_of_stream_count_; } void OnStreamPadLength(SpdyStreamId stream_id, size_t value) override { - SPDY_VLOG(1) << "OnStreamPadding(" << stream_id << ", " << value << ")\n"; + QUICHE_VLOG(1) << "OnStreamPadding(" << stream_id << ", " << value << ")\n"; EXPECT_EQ(header_stream_id_, stream_id); // Count the padding length field byte against total data bytes. data_bytes_ += 1; } void OnStreamPadding(SpdyStreamId stream_id, size_t len) override { - SPDY_VLOG(1) << "OnStreamPadding(" << stream_id << ", " << len << ")\n"; + QUICHE_VLOG(1) << "OnStreamPadding(" << stream_id << ", " << len << ")\n"; EXPECT_EQ(header_stream_id_, stream_id); data_bytes_ += len; } @@ -329,34 +328,34 @@ class TestSpdyVisitor : public SpdyFramerVisitorInterface, } void OnRstStream(SpdyStreamId stream_id, SpdyErrorCode error_code) override { - SPDY_VLOG(1) << "OnRstStream(" << stream_id << ", " << error_code << ")"; + QUICHE_VLOG(1) << "OnRstStream(" << stream_id << ", " << error_code << ")"; ++fin_frame_count_; } void OnSetting(SpdySettingsId id, uint32_t value) override { - SPDY_VLOG(1) << "OnSetting(" << id << ", " << std::hex << value << ")"; + QUICHE_VLOG(1) << "OnSetting(" << id << ", " << std::hex << value << ")"; ++setting_count_; } void OnSettingsAck() override { - SPDY_VLOG(1) << "OnSettingsAck"; + QUICHE_VLOG(1) << "OnSettingsAck"; ++settings_ack_received_; } void OnSettingsEnd() override { - SPDY_VLOG(1) << "OnSettingsEnd"; + QUICHE_VLOG(1) << "OnSettingsEnd"; ++settings_ack_sent_; } void OnPing(SpdyPingId unique_id, bool is_ack) override { - SPDY_LOG(DFATAL) << "OnPing(" << unique_id << ", " << (is_ack ? 1 : 0) - << ")"; + QUICHE_LOG(DFATAL) << "OnPing(" << unique_id << ", " << (is_ack ? 1 : 0) + << ")"; } void OnGoAway(SpdyStreamId last_accepted_stream_id, SpdyErrorCode error_code) override { - SPDY_VLOG(1) << "OnGoAway(" << last_accepted_stream_id << ", " << error_code - << ")"; + QUICHE_VLOG(1) << "OnGoAway(" << last_accepted_stream_id << ", " + << error_code << ")"; ++goaway_count_; } @@ -367,9 +366,9 @@ class TestSpdyVisitor : public SpdyFramerVisitorInterface, bool exclusive, bool fin, bool end) override { - SPDY_VLOG(1) << "OnHeaders(" << stream_id << ", " << has_priority << ", " - << weight << ", " << parent_stream_id << ", " << exclusive - << ", " << fin << ", " << end << ")"; + QUICHE_VLOG(1) << "OnHeaders(" << stream_id << ", " << has_priority << ", " + << weight << ", " << parent_stream_id << ", " << exclusive + << ", " << fin << ", " << end << ")"; ++headers_frame_count_; InitHeaderStreaming(SpdyFrameType::HEADERS, stream_id); if (fin) { @@ -381,8 +380,8 @@ class TestSpdyVisitor : public SpdyFramerVisitorInterface, } void OnWindowUpdate(SpdyStreamId stream_id, int delta_window_size) override { - SPDY_VLOG(1) << "OnWindowUpdate(" << stream_id << ", " << delta_window_size - << ")"; + QUICHE_VLOG(1) << "OnWindowUpdate(" << stream_id << ", " + << delta_window_size << ")"; last_window_update_stream_ = stream_id; last_window_update_delta_ = delta_window_size; } @@ -390,8 +389,8 @@ class TestSpdyVisitor : public SpdyFramerVisitorInterface, void OnPushPromise(SpdyStreamId stream_id, SpdyStreamId promised_stream_id, bool end) override { - SPDY_VLOG(1) << "OnPushPromise(" << stream_id << ", " << promised_stream_id - << ", " << end << ")"; + QUICHE_VLOG(1) << "OnPushPromise(" << stream_id << ", " + << promised_stream_id << ", " << end << ")"; ++push_promise_frame_count_; InitHeaderStreaming(SpdyFrameType::PUSH_PROMISE, stream_id); last_push_promise_stream_ = stream_id; @@ -399,7 +398,7 @@ class TestSpdyVisitor : public SpdyFramerVisitorInterface, } void OnContinuation(SpdyStreamId stream_id, bool end) override { - SPDY_VLOG(1) << "OnContinuation(" << stream_id << ", " << end << ")"; + QUICHE_VLOG(1) << "OnContinuation(" << stream_id << ", " << end << ")"; ++continuation_count_; } @@ -407,8 +406,8 @@ class TestSpdyVisitor : public SpdyFramerVisitorInterface, absl::string_view origin, const SpdyAltSvcWireFormat::AlternativeServiceVector& altsvc_vector) override { - SPDY_VLOG(1) << "OnAltSvc(" << stream_id << ", \"" << origin - << "\", altsvc_vector)"; + QUICHE_VLOG(1) << "OnAltSvc(" << stream_id << ", \"" << origin + << "\", altsvc_vector)"; test_altsvc_ir_ = std::make_unique<SpdyAltSvcIR>(stream_id); if (origin.length() > 0) { test_altsvc_ir_->set_origin(std::string(origin)); @@ -423,19 +422,20 @@ class TestSpdyVisitor : public SpdyFramerVisitorInterface, SpdyStreamId parent_stream_id, int weight, bool exclusive) override { - SPDY_VLOG(1) << "OnPriority(" << stream_id << ", " << parent_stream_id - << ", " << weight << ", " << (exclusive ? 1 : 0) << ")"; + QUICHE_VLOG(1) << "OnPriority(" << stream_id << ", " << parent_stream_id + << ", " << weight << ", " << (exclusive ? 1 : 0) << ")"; ++priority_count_; } void OnPriorityUpdate(SpdyStreamId prioritized_stream_id, absl::string_view priority_field_value) override { - SPDY_VLOG(1) << "OnPriorityUpdate(" << prioritized_stream_id << ", " - << priority_field_value << ")"; + QUICHE_VLOG(1) << "OnPriorityUpdate(" << prioritized_stream_id << ", " + << priority_field_value << ")"; } bool OnUnknownFrame(SpdyStreamId stream_id, uint8_t frame_type) override { - SPDY_VLOG(1) << "OnUnknownFrame(" << stream_id << ", " << frame_type << ")"; + QUICHE_VLOG(1) << "OnUnknownFrame(" << stream_id << ", " << frame_type + << ")"; return on_unknown_frame_result_; } @@ -443,8 +443,8 @@ class TestSpdyVisitor : public SpdyFramerVisitorInterface, SpdyFrameType type, size_t payload_len, size_t frame_len) override { - SPDY_VLOG(1) << "OnSendCompressedFrame(" << stream_id << ", " << type - << ", " << payload_len << ", " << frame_len << ")"; + QUICHE_VLOG(1) << "OnSendCompressedFrame(" << stream_id << ", " << type + << ", " << payload_len << ", " << frame_len << ")"; last_payload_len_ = payload_len; last_frame_len_ = frame_len; } @@ -452,8 +452,8 @@ class TestSpdyVisitor : public SpdyFramerVisitorInterface, void OnReceiveCompressedFrame(SpdyStreamId stream_id, SpdyFrameType type, size_t frame_len) override { - SPDY_VLOG(1) << "OnReceiveCompressedFrame(" << stream_id << ", " << type - << ", " << frame_len << ")"; + QUICHE_VLOG(1) << "OnReceiveCompressedFrame(" << stream_id << ", " << type + << ", " << frame_len << ")"; last_frame_len_ = frame_len; } @@ -479,8 +479,9 @@ class TestSpdyVisitor : public SpdyFramerVisitorInterface, void InitHeaderStreaming(SpdyFrameType header_control_type, SpdyStreamId stream_id) { if (!IsDefinedFrameType(SerializeFrameType(header_control_type))) { - SPDY_DLOG(FATAL) << "Attempted to init header streaming with " - << "invalid control frame type: " << header_control_type; + QUICHE_DLOG(FATAL) << "Attempted to init header streaming with " + << "invalid control frame type: " + << header_control_type; } memset(header_buffer_.get(), 0, header_buffer_size_); header_buffer_length_ = 0; @@ -4817,8 +4818,8 @@ TEST_P(SpdyFramerTest, ProcessAllInput) { const size_t frame1_size = frame1.size(); const size_t frame2_size = frame2.size(); - SPDY_VLOG(1) << "frame1_size = " << frame1_size; - SPDY_VLOG(1) << "frame2_size = " << frame2_size; + QUICHE_VLOG(1) << "frame1_size = " << frame1_size; + QUICHE_VLOG(1) << "frame2_size = " << frame2_size; std::string input_buffer; input_buffer.append(frame1.data(), frame1_size); @@ -4827,7 +4828,7 @@ TEST_P(SpdyFramerTest, ProcessAllInput) { const char* buf = input_buffer.data(); const size_t buf_size = input_buffer.size(); - SPDY_VLOG(1) << "buf_size = " << buf_size; + QUICHE_VLOG(1) << "buf_size = " << buf_size; size_t processed = deframer_.ProcessInput(buf, buf_size); EXPECT_EQ(buf_size, processed); 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 59a9069a220..b5790470e02 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 @@ -10,8 +10,8 @@ #include <utility> #include "absl/strings/str_cat.h" +#include "common/platform/api/quiche_logging.h" #include "spdy/platform/api/spdy_estimate_memory_usage.h" -#include "spdy/platform/api/spdy_logging.h" namespace spdy { namespace { @@ -144,14 +144,14 @@ Http2HeaderBlock::ValueProxy& Http2HeaderBlock::ValueProxy::operator=( *spdy_header_block_value_size_ += value.size(); SpdyHeaderStorage* storage = &block_->storage_; if (lookup_result_ == block_->map_.end()) { - SPDY_DVLOG(1) << "Inserting: (" << key_ << ", " << value << ")"; + QUICHE_DVLOG(1) << "Inserting: (" << key_ << ", " << value << ")"; lookup_result_ = block_->map_ .emplace(std::make_pair( key_, HeaderValue(storage, key_, storage->Write(value)))) .first; } else { - SPDY_DVLOG(1) << "Updating key: " << key_ << " with value: " << value; + QUICHE_DVLOG(1) << "Updating key: " << key_ << " with value: " << value; *spdy_header_block_value_size_ -= lookup_result_->second.SizeEstimate(); lookup_result_->second = HeaderValue(storage, key_, storage->Write(value)); } @@ -232,7 +232,7 @@ std::string Http2HeaderBlock::DebugString() const { void Http2HeaderBlock::erase(absl::string_view key) { auto iter = map_.find(key); if (iter != map_.end()) { - SPDY_DVLOG(1) << "Erasing header with name: " << key; + QUICHE_DVLOG(1) << "Erasing header with name: " << key; key_size_ -= key.size(); value_size_ -= iter->second.SizeEstimate(); map_.erase(iter); @@ -252,12 +252,12 @@ void Http2HeaderBlock::insert(const Http2HeaderBlock::value_type& value) { auto iter = map_.find(value.first); if (iter == map_.end()) { - SPDY_DVLOG(1) << "Inserting: (" << value.first << ", " << value.second - << ")"; + QUICHE_DVLOG(1) << "Inserting: (" << value.first << ", " << value.second + << ")"; AppendHeader(value.first, value.second); } else { - SPDY_DVLOG(1) << "Updating key: " << iter->first - << " with value: " << value.second; + QUICHE_DVLOG(1) << "Updating key: " << iter->first + << " with value: " << value.second; value_size_ -= iter->second.SizeEstimate(); iter->second = HeaderValue(&storage_, iter->first, storage_.Write(value.second)); @@ -266,16 +266,16 @@ void Http2HeaderBlock::insert(const Http2HeaderBlock::value_type& value) { Http2HeaderBlock::ValueProxy Http2HeaderBlock::operator[]( const absl::string_view key) { - SPDY_DVLOG(2) << "Operator[] saw key: " << key; + QUICHE_DVLOG(2) << "Operator[] saw key: " << key; absl::string_view out_key; auto iter = map_.find(key); if (iter == map_.end()) { // We write the key first, to assure that the ValueProxy has a // reference to a valid absl::string_view in its operator=. out_key = WriteKey(key); - SPDY_DVLOG(2) << "Key written as: " << std::hex - << static_cast<const void*>(key.data()) << ", " << std::dec - << key.size(); + QUICHE_DVLOG(2) << "Key written as: " << std::hex + << static_cast<const void*>(key.data()) << ", " << std::dec + << key.size(); } else { out_key = iter->first; } @@ -288,13 +288,13 @@ void Http2HeaderBlock::AppendValueOrAddHeader(const absl::string_view key, auto iter = map_.find(key); if (iter == map_.end()) { - SPDY_DVLOG(1) << "Inserting: (" << key << ", " << value << ")"; + QUICHE_DVLOG(1) << "Inserting: (" << key << ", " << value << ")"; AppendHeader(key, value); return; } - SPDY_DVLOG(1) << "Updating key: " << iter->first - << "; appending value: " << value; + QUICHE_DVLOG(1) << "Updating key: " << iter->first + << "; appending value: " << value; value_size_ += SeparatorForKey(key).size(); iter->second.Append(storage_.Write(value)); } diff --git a/chromium/net/third_party/quiche/src/spdy/core/spdy_header_storage.cc b/chromium/net/third_party/quiche/src/spdy/core/spdy_header_storage.cc index 207a3be6e00..e99590568b9 100644 --- a/chromium/net/third_party/quiche/src/spdy/core/spdy_header_storage.cc +++ b/chromium/net/third_party/quiche/src/spdy/core/spdy_header_storage.cc @@ -2,7 +2,7 @@ #include <cstring> -#include "spdy/platform/api/spdy_logging.h" +#include "common/platform/api/quiche_logging.h" namespace spdy { namespace { diff --git a/chromium/net/third_party/quiche/src/spdy/core/spdy_prefixed_buffer_reader.cc b/chromium/net/third_party/quiche/src/spdy/core/spdy_prefixed_buffer_reader.cc index 0cb07cf48b0..767dea36074 100644 --- a/chromium/net/third_party/quiche/src/spdy/core/spdy_prefixed_buffer_reader.cc +++ b/chromium/net/third_party/quiche/src/spdy/core/spdy_prefixed_buffer_reader.cc @@ -6,7 +6,7 @@ #include <new> -#include "spdy/platform/api/spdy_logging.h" +#include "common/platform/api/quiche_logging.h" namespace spdy { 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 ea90b6500ed..4bde56a29d7 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 @@ -8,7 +8,7 @@ #include <ostream> #include "absl/strings/str_cat.h" -#include "spdy/platform/api/spdy_bug_tracker.h" +#include "common/platform/api/quiche_bug_tracker.h" namespace spdy { @@ -28,7 +28,7 @@ SpdyPriority ClampSpdy3Priority(SpdyPriority priority) { "The value of given priority shouldn't be smaller than highest " "priority. Check this invariant explicitly."); if (priority > kV3LowestPriority) { - SPDY_BUG(spdy_bug_22_1) + QUICHE_BUG(spdy_bug_22_1) << "Invalid priority: " << static_cast<int>(priority); return kV3LowestPriority; } @@ -37,11 +37,11 @@ SpdyPriority ClampSpdy3Priority(SpdyPriority priority) { int ClampHttp2Weight(int weight) { if (weight < kHttp2MinStreamWeight) { - SPDY_BUG(spdy_bug_22_2) << "Invalid weight: " << weight; + QUICHE_BUG(spdy_bug_22_2) << "Invalid weight: " << weight; return kHttp2MinStreamWeight; } if (weight > kHttp2MaxStreamWeight) { - SPDY_BUG(spdy_bug_22_3) << "Invalid weight: " << weight; + QUICHE_BUG(spdy_bug_22_3) << "Invalid weight: " << weight; return kHttp2MaxStreamWeight; } return weight; @@ -92,7 +92,7 @@ bool IsDefinedFrameType(uint8_t frame_type_field) { } SpdyFrameType ParseFrameType(uint8_t frame_type_field) { - SPDY_BUG_IF(spdy_bug_22_4, !IsDefinedFrameType(frame_type_field)) + QUICHE_BUG_IF(spdy_bug_22_4, !IsDefinedFrameType(frame_type_field)) << "Frame type not defined: " << static_cast<int>(frame_type_field); return static_cast<SpdyFrameType>(frame_type_field); } @@ -462,7 +462,7 @@ SpdyFrameType SpdyContinuationIR::frame_type() const { size_t SpdyContinuationIR::size() const { // We don't need to get the size of CONTINUATION frame directly. It is // calculated in HEADERS or PUSH_PROMISE frame. - SPDY_DLOG(WARNING) << "Shouldn't not call size() for CONTINUATION frame."; + QUICHE_DLOG(WARNING) << "Shouldn't not call size() for CONTINUATION frame."; return 0; } 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 d4a671b8933..16d6b9a7ecd 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 @@ -21,11 +21,10 @@ #include "absl/strings/string_view.h" #include "common/platform/api/quiche_export.h" +#include "common/platform/api/quiche_logging.h" #include "spdy/core/spdy_alt_svc_wire_format.h" #include "spdy/core/spdy_bitmasks.h" #include "spdy/core/spdy_header_block.h" -#include "spdy/platform/api/spdy_bug_tracker.h" -#include "spdy/platform/api/spdy_logging.h" namespace spdy { 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 966c4716c75..dbea0e328ca 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 @@ -9,9 +9,9 @@ #include <memory> #include "common/platform/api/quiche_test.h" +#include "common/platform/api/quiche_test_helpers.h" #include "spdy/core/spdy_bitmasks.h" #include "spdy/core/spdy_test_utils.h" -#include "spdy/platform/api/spdy_test_helpers.h" namespace spdy { @@ -31,16 +31,16 @@ std::ostream& operator<<(std::ostream& os, namespace test { TEST(SpdyProtocolTest, ClampSpdy3Priority) { - EXPECT_SPDY_BUG(EXPECT_EQ(7, ClampSpdy3Priority(8)), "Invalid priority: 8"); + EXPECT_QUICHE_BUG(EXPECT_EQ(7, ClampSpdy3Priority(8)), "Invalid priority: 8"); EXPECT_EQ(kV3LowestPriority, ClampSpdy3Priority(kV3LowestPriority)); EXPECT_EQ(kV3HighestPriority, ClampSpdy3Priority(kV3HighestPriority)); } TEST(SpdyProtocolTest, ClampHttp2Weight) { - EXPECT_SPDY_BUG(EXPECT_EQ(kHttp2MinStreamWeight, ClampHttp2Weight(0)), - "Invalid weight: 0"); - EXPECT_SPDY_BUG(EXPECT_EQ(kHttp2MaxStreamWeight, ClampHttp2Weight(300)), - "Invalid weight: 300"); + EXPECT_QUICHE_BUG(EXPECT_EQ(kHttp2MinStreamWeight, ClampHttp2Weight(0)), + "Invalid weight: 0"); + EXPECT_QUICHE_BUG(EXPECT_EQ(kHttp2MaxStreamWeight, ClampHttp2Weight(300)), + "Invalid weight: 300"); EXPECT_EQ(kHttp2MinStreamWeight, ClampHttp2Weight(kHttp2MinStreamWeight)); EXPECT_EQ(kHttp2MaxStreamWeight, ClampHttp2Weight(kHttp2MaxStreamWeight)); } @@ -175,14 +175,14 @@ TEST(SpdyStreamPrecedenceTest, Basic) { } TEST(SpdyStreamPrecedenceTest, Clamping) { - EXPECT_SPDY_BUG(EXPECT_EQ(7, SpdyStreamPrecedence(8).spdy3_priority()), - "Invalid priority: 8"); - EXPECT_SPDY_BUG(EXPECT_EQ(kHttp2MinStreamWeight, - SpdyStreamPrecedence(3, 0, false).weight()), - "Invalid weight: 0"); - EXPECT_SPDY_BUG(EXPECT_EQ(kHttp2MaxStreamWeight, - SpdyStreamPrecedence(3, 300, false).weight()), - "Invalid weight: 300"); + EXPECT_QUICHE_BUG(EXPECT_EQ(7, SpdyStreamPrecedence(8).spdy3_priority()), + "Invalid priority: 8"); + EXPECT_QUICHE_BUG(EXPECT_EQ(kHttp2MinStreamWeight, + SpdyStreamPrecedence(3, 0, false).weight()), + "Invalid weight: 0"); + EXPECT_QUICHE_BUG(EXPECT_EQ(kHttp2MaxStreamWeight, + SpdyStreamPrecedence(3, 300, false).weight()), + "Invalid weight: 300"); } TEST(SpdyStreamPrecedenceTest, Copying) { diff --git a/chromium/net/third_party/quiche/src/spdy/core/spdy_protocol_test_utils.cc b/chromium/net/third_party/quiche/src/spdy/core/spdy_protocol_test_utils.cc index 63917499eb9..1888176d673 100644 --- a/chromium/net/third_party/quiche/src/spdy/core/spdy_protocol_test_utils.cc +++ b/chromium/net/third_party/quiche/src/spdy/core/spdy_protocol_test_utils.cc @@ -17,7 +17,7 @@ namespace test { ::testing::AssertionResult VerifySpdyFrameWithHeaderBlockIREquals( const SpdyFrameWithHeaderBlockIR& expected, const SpdyFrameWithHeaderBlockIR& actual) { - SPDY_VLOG(1) << "VerifySpdyFrameWithHeaderBlockIREquals"; + QUICHE_VLOG(1) << "VerifySpdyFrameWithHeaderBlockIREquals"; VERIFY_TRUE(actual.header_block() == expected.header_block()); return ::testing::AssertionSuccess(); } @@ -40,7 +40,7 @@ namespace test { ::testing::AssertionResult VerifySpdyFrameIREquals(const SpdyDataIR& expected, const SpdyDataIR& actual) { - SPDY_VLOG(1) << "VerifySpdyFrameIREquals SpdyDataIR"; + QUICHE_VLOG(1) << "VerifySpdyFrameIREquals SpdyDataIR"; VERIFY_EQ(expected.stream_id(), actual.stream_id()); VERIFY_EQ(expected.fin(), actual.fin()); VERIFY_EQ(expected.data_len(), actual.data_len()); @@ -56,7 +56,7 @@ namespace test { ::testing::AssertionResult VerifySpdyFrameIREquals(const SpdyGoAwayIR& expected, const SpdyGoAwayIR& actual) { - SPDY_VLOG(1) << "VerifySpdyFrameIREquals SpdyGoAwayIR"; + QUICHE_VLOG(1) << "VerifySpdyFrameIREquals SpdyGoAwayIR"; VERIFY_EQ(expected.last_good_stream_id(), actual.last_good_stream_id()); VERIFY_EQ(expected.error_code(), actual.error_code()); VERIFY_EQ(expected.description(), actual.description()); @@ -66,7 +66,7 @@ namespace test { ::testing::AssertionResult VerifySpdyFrameIREquals( const SpdyHeadersIR& expected, const SpdyHeadersIR& actual) { - SPDY_VLOG(1) << "VerifySpdyFrameIREquals SpdyHeadersIR"; + QUICHE_VLOG(1) << "VerifySpdyFrameIREquals SpdyHeadersIR"; VERIFY_EQ(expected.stream_id(), actual.stream_id()); VERIFY_EQ(expected.fin(), actual.fin()); VERIFY_SUCCESS(VerifySpdyFrameWithHeaderBlockIREquals(expected, actual)); @@ -80,7 +80,7 @@ namespace test { ::testing::AssertionResult VerifySpdyFrameIREquals(const SpdyPingIR& expected, const SpdyPingIR& actual) { - SPDY_VLOG(1) << "VerifySpdyFrameIREquals SpdyPingIR"; + QUICHE_VLOG(1) << "VerifySpdyFrameIREquals SpdyPingIR"; VERIFY_EQ(expected.id(), actual.id()); VERIFY_EQ(expected.is_ack(), actual.is_ack()); return ::testing::AssertionSuccess(); @@ -89,7 +89,7 @@ namespace test { ::testing::AssertionResult VerifySpdyFrameIREquals( const SpdyPriorityIR& expected, const SpdyPriorityIR& actual) { - SPDY_VLOG(1) << "VerifySpdyFrameIREquals SpdyPriorityIR"; + QUICHE_VLOG(1) << "VerifySpdyFrameIREquals SpdyPriorityIR"; VERIFY_EQ(expected.stream_id(), actual.stream_id()); VERIFY_SUCCESS(VerifySpdyFrameWithPriorityIREquals(expected, actual)); return ::testing::AssertionSuccess(); @@ -98,7 +98,7 @@ namespace test { ::testing::AssertionResult VerifySpdyFrameIREquals( const SpdyPushPromiseIR& expected, const SpdyPushPromiseIR& actual) { - SPDY_VLOG(1) << "VerifySpdyFrameIREquals SpdyPushPromiseIR"; + QUICHE_VLOG(1) << "VerifySpdyFrameIREquals SpdyPushPromiseIR"; VERIFY_EQ(expected.stream_id(), actual.stream_id()); VERIFY_SUCCESS(VerifySpdyFrameWithPaddingIREquals(expected, actual)); VERIFY_EQ(expected.promised_stream_id(), actual.promised_stream_id()); @@ -109,7 +109,7 @@ namespace test { ::testing::AssertionResult VerifySpdyFrameIREquals( const SpdyRstStreamIR& expected, const SpdyRstStreamIR& actual) { - SPDY_VLOG(1) << "VerifySpdyFrameIREquals SpdyRstStreamIR"; + QUICHE_VLOG(1) << "VerifySpdyFrameIREquals SpdyRstStreamIR"; VERIFY_EQ(expected.stream_id(), actual.stream_id()); VERIFY_EQ(expected.error_code(), actual.error_code()); return ::testing::AssertionSuccess(); @@ -118,7 +118,7 @@ namespace test { ::testing::AssertionResult VerifySpdyFrameIREquals( const SpdySettingsIR& expected, const SpdySettingsIR& actual) { - SPDY_VLOG(1) << "VerifySpdyFrameIREquals SpdySettingsIR"; + QUICHE_VLOG(1) << "VerifySpdyFrameIREquals SpdySettingsIR"; // Note, ignoring non-HTTP/2 fields such as clear_settings. VERIFY_EQ(expected.is_ack(), actual.is_ack()); @@ -145,7 +145,7 @@ namespace test { ::testing::AssertionResult VerifySpdyFrameIREquals( const SpdyWindowUpdateIR& expected, const SpdyWindowUpdateIR& actual) { - SPDY_VLOG(1) << "VerifySpdyFrameIREquals SpdyWindowUpdateIR"; + QUICHE_VLOG(1) << "VerifySpdyFrameIREquals SpdyWindowUpdateIR"; VERIFY_EQ(expected.stream_id(), actual.stream_id()); VERIFY_EQ(expected.delta(), actual.delta()); return ::testing::AssertionSuccess(); diff --git a/chromium/net/third_party/quiche/src/spdy/core/spdy_protocol_test_utils.h b/chromium/net/third_party/quiche/src/spdy/core/spdy_protocol_test_utils.h index daccebb06a4..de716d50984 100644 --- a/chromium/net/third_party/quiche/src/spdy/core/spdy_protocol_test_utils.h +++ b/chromium/net/third_party/quiche/src/spdy/core/spdy_protocol_test_utils.h @@ -20,10 +20,10 @@ #include <typeinfo> #include "http2/platform/api/http2_test_helpers.h" +#include "common/platform/api/quiche_logging.h" #include "common/platform/api/quiche_test.h" #include "spdy/core/spdy_protocol.h" #include "spdy/core/spdy_test_utils.h" -#include "spdy/platform/api/spdy_logging.h" namespace spdy { namespace test { @@ -38,7 +38,7 @@ namespace test { template <class T> ::testing::AssertionResult VerifySpdyFrameWithPaddingIREquals(const T& expected, const T& actual) { - SPDY_VLOG(1) << "VerifySpdyFrameWithPaddingIREquals"; + QUICHE_VLOG(1) << "VerifySpdyFrameWithPaddingIREquals"; VERIFY_EQ(expected.padded(), actual.padded()); if (expected.padded()) { VERIFY_EQ(expected.padding_payload_len(), actual.padding_payload_len()); @@ -52,7 +52,7 @@ template <class T> ::testing::AssertionResult VerifySpdyFrameWithPriorityIREquals( const T& expected, const T& actual) { - SPDY_VLOG(1) << "VerifySpdyFrameWithPriorityIREquals"; + QUICHE_VLOG(1) << "VerifySpdyFrameWithPriorityIREquals"; VERIFY_EQ(expected.parent_stream_id(), actual.parent_stream_id()); VERIFY_EQ(expected.weight(), actual.weight()); VERIFY_EQ(expected.exclusive(), actual.exclusive()); @@ -123,12 +123,12 @@ template <class E> ::testing::AssertionResult VerifySpdyFrameIREquals(const E* expected, const SpdyFrameIR* actual) { if (expected == nullptr || actual == nullptr) { - SPDY_VLOG(1) << "VerifySpdyFrameIREquals one null"; + QUICHE_VLOG(1) << "VerifySpdyFrameIREquals one null"; VERIFY_EQ(expected, nullptr); VERIFY_EQ(actual, nullptr); return ::testing::AssertionSuccess(); } - SPDY_VLOG(1) << "VerifySpdyFrameIREquals not null"; + QUICHE_VLOG(1) << "VerifySpdyFrameIREquals not null"; VERIFY_EQ(actual->frame_type(), expected->frame_type()); const E* actual2 = static_cast<const E*>(actual); return VerifySpdyFrameIREquals(*expected, *actual2); @@ -139,7 +139,7 @@ template <class E> template <class E> ::testing::AssertionResult VerifySpdyFrameIREquals(const E& expected, const SpdyFrameIR* actual) { - SPDY_VLOG(1) << "VerifySpdyFrameIREquals"; + QUICHE_VLOG(1) << "VerifySpdyFrameIREquals"; return VerifySpdyFrameIREquals(&expected, actual); } diff --git a/chromium/net/third_party/quiche/src/spdy/core/spdy_simple_arena.cc b/chromium/net/third_party/quiche/src/spdy/core/spdy_simple_arena.cc index 15c8fea2614..4df224629c6 100644 --- a/chromium/net/third_party/quiche/src/spdy/core/spdy_simple_arena.cc +++ b/chromium/net/third_party/quiche/src/spdy/core/spdy_simple_arena.cc @@ -7,7 +7,7 @@ #include <algorithm> #include <cstring> -#include "spdy/platform/api/spdy_logging.h" +#include "common/platform/api/quiche_logging.h" namespace spdy { 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 482d8e24263..4ea1ce82895 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 @@ -11,9 +11,9 @@ #include <utility> #include <vector> +#include "common/platform/api/quiche_logging.h" #include "common/platform/api/quiche_test.h" #include "common/quiche_endian.h" -#include "spdy/platform/api/spdy_logging.h" namespace spdy { namespace test { @@ -27,7 +27,7 @@ std::string HexDumpWithMarks(const unsigned char* data, const int kSizeLimit = 1024; if (length > kSizeLimit || mark_length > kSizeLimit) { - SPDY_LOG(ERROR) << "Only dumping first " << kSizeLimit << " bytes."; + QUICHE_LOG(ERROR) << "Only dumping first " << kSizeLimit << " bytes."; length = std::min(length, kSizeLimit); mark_length = std::min(mark_length, kSizeLimit); } diff --git a/chromium/net/third_party/quiche/src/spdy/platform/api/spdy_bug_tracker.h b/chromium/net/third_party/quiche/src/spdy/platform/api/spdy_bug_tracker.h deleted file mode 100644 index f00bbc8b376..00000000000 --- a/chromium/net/third_party/quiche/src/spdy/platform/api/spdy_bug_tracker.h +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef QUICHE_SPDY_PLATFORM_API_SPDY_BUG_TRACKER_H_ -#define QUICHE_SPDY_PLATFORM_API_SPDY_BUG_TRACKER_H_ - -#include "net/spdy/platform/impl/spdy_bug_tracker_impl.h" - -#define SPDY_BUG SPDY_BUG_IMPL -#define SPDY_BUG_IF(bug_id, condition) SPDY_BUG_IF_IMPL(bug_id, condition) - -#define FLAGS_spdy_always_log_bugs_for_tests \ - FLAGS_spdy_always_log_bugs_for_tests_impl - -#endif // QUICHE_SPDY_PLATFORM_API_SPDY_BUG_TRACKER_H_ diff --git a/chromium/net/third_party/quiche/src/spdy/platform/api/spdy_containers.h b/chromium/net/third_party/quiche/src/spdy/platform/api/spdy_containers.h index 9e3813f5b42..2adf3f4b87a 100644 --- a/chromium/net/third_party/quiche/src/spdy/platform/api/spdy_containers.h +++ b/chromium/net/third_party/quiche/src/spdy/platform/api/spdy_containers.h @@ -13,12 +13,6 @@ namespace spdy { template <typename Key, typename Value, typename Hash, typename Eq> using SpdyLinkedHashMap = SpdyLinkedHashMapImpl<Key, Value, Hash, Eq>; -// Used for maps that are typically small, then it is faster than (for example) -// hash_map which is optimized for large data sets. SpdySmallMap upgrades itself -// automatically to a SpdySmallMapImpl-specified map when it runs out of space. -template <typename Key, typename Value, int Size> -using SpdySmallMap = SpdySmallMapImpl<Key, Value, Size>; - } // namespace spdy #endif // QUICHE_SPDY_PLATFORM_API_SPDY_CONTAINERS_H_ diff --git a/chromium/net/third_party/quiche/src/spdy/platform/api/spdy_flag_utils.h b/chromium/net/third_party/quiche/src/spdy/platform/api/spdy_flag_utils.h deleted file mode 100644 index 07c97fbc343..00000000000 --- a/chromium/net/third_party/quiche/src/spdy/platform/api/spdy_flag_utils.h +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef QUICHE_SPDY_PLATFORM_API_SPDY_FLAG_UTILS_H_ -#define QUICHE_SPDY_PLATFORM_API_SPDY_FLAG_UTILS_H_ - -#include "common/platform/api/quiche_flag_utils.h" - -#define SPDY_RELOADABLE_FLAG_COUNT QUICHE_RELOADABLE_FLAG_COUNT -#define SPDY_RELOADABLE_FLAG_COUNT_N QUICHE_RELOADABLE_FLAG_COUNT_N - -#define SPDY_RESTART_FLAG_COUNT QUICHE_RESTART_FLAG_COUNT -#define SPDY_RESTART_FLAG_COUNT_N QUICHE_RESTART_FLAG_COUNT_N - -#define SPDY_CODE_COUNT QUICHE_CODE_COUNT -#define SPDY_CODE_COUNT_N QUICHE_CODE_COUNT_N - -#endif // QUICHE_SPDY_PLATFORM_API_SPDY_FLAG_UTILS_H_ diff --git a/chromium/net/third_party/quiche/src/spdy/platform/api/spdy_flags.h b/chromium/net/third_party/quiche/src/spdy/platform/api/spdy_flags.h deleted file mode 100644 index f8cb5a60d5b..00000000000 --- a/chromium/net/third_party/quiche/src/spdy/platform/api/spdy_flags.h +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef QUICHE_SPDY_PLATFORM_API_SPDY_FLAGS_H_ -#define QUICHE_SPDY_PLATFORM_API_SPDY_FLAGS_H_ - -#include "common/platform/api/quiche_flags.h" - -#define GetSpdyReloadableFlag(flag) GetQuicheReloadableFlag(spdy, flag) -#define SetSpdyReloadableFlag(flag, value) \ - SetQuicheReloadableFlag(spdy, flag, value) -#define GetSpdyRestartFlag(flag) GetQuicheRestartFlag(spdy, flag) -#define SetSpdyRestartFlag(flag, value) SetQuicheRestartFlag(spdy, flag, value) -#define GetSpdyFlag(flag) GetQuicheFlag(flag) -#define SetSpdyFlag(flag, value) SetQuicheFlag(flag, value) - -#endif // QUICHE_SPDY_PLATFORM_API_SPDY_FLAGS_H_ diff --git a/chromium/net/third_party/quiche/src/spdy/platform/api/spdy_logging.h b/chromium/net/third_party/quiche/src/spdy/platform/api/spdy_logging.h deleted file mode 100644 index c1f5268e287..00000000000 --- a/chromium/net/third_party/quiche/src/spdy/platform/api/spdy_logging.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 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_PLATFORM_API_SPDY_LOGGING_H_ -#define QUICHE_SPDY_PLATFORM_API_SPDY_LOGGING_H_ - -#include "common/platform/api/quiche_logging.h" - -#define SPDY_LOG(severity) QUICHE_LOG(severity) - -#define SPDY_VLOG(verbose_level) QUICHE_VLOG(verbose_level) - -#define SPDY_DLOG(severity) QUICHE_DLOG(severity) - -#define SPDY_DLOG_IF(severity, condition) QUICHE_DLOG_IF(severity, condition) - -#define SPDY_DVLOG(verbose_level) QUICHE_DVLOG(verbose_level) - -#define SPDY_DVLOG_IF(verbose_level, condition) \ - QUICHE_DVLOG_IF(verbose_level, condition) - -#endif // QUICHE_SPDY_PLATFORM_API_SPDY_LOGGING_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 178415b0ed6..83660bab06f 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 @@ -6,29 +6,12 @@ #define QUICHE_SPDY_PLATFORM_API_SPDY_STRING_UTILS_H_ #include <string> -#include <utility> #include "absl/strings/string_view.h" #include "net/spdy/platform/impl/spdy_string_utils_impl.h" namespace spdy { -inline char SpdyHexDigitToInt(char c) { - return SpdyHexDigitToIntImpl(c); -} - -inline std::string SpdyHexDecode(absl::string_view data) { - return SpdyHexDecodeImpl(data); -} - -inline bool SpdyHexDecodeToUInt32(absl::string_view data, uint32_t* out) { - return SpdyHexDecodeToUInt32Impl(data, out); -} - -inline std::string SpdyHexEncode(const char* bytes, size_t size) { - return SpdyHexEncodeImpl(bytes, size); -} - inline std::string SpdyHexDump(absl::string_view 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 deleted file mode 100644 index cb73a9b2ece..00000000000 --- a/chromium/net/third_party/quiche/src/spdy/platform/api/spdy_string_utils_test.cc +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "spdy/platform/api/spdy_string_utils.h" - -#include <cstdint> - -#include "absl/strings/string_view.h" -#include "common/platform/api/quiche_test.h" - -namespace spdy { -namespace test { -namespace { - -TEST(SpdyStringUtilsTest, SpdyHexDigitToInt) { - EXPECT_EQ(0, SpdyHexDigitToInt('0')); - EXPECT_EQ(1, SpdyHexDigitToInt('1')); - EXPECT_EQ(2, SpdyHexDigitToInt('2')); - EXPECT_EQ(3, SpdyHexDigitToInt('3')); - EXPECT_EQ(4, SpdyHexDigitToInt('4')); - EXPECT_EQ(5, SpdyHexDigitToInt('5')); - EXPECT_EQ(6, SpdyHexDigitToInt('6')); - EXPECT_EQ(7, SpdyHexDigitToInt('7')); - EXPECT_EQ(8, SpdyHexDigitToInt('8')); - EXPECT_EQ(9, SpdyHexDigitToInt('9')); - - EXPECT_EQ(10, SpdyHexDigitToInt('a')); - EXPECT_EQ(11, SpdyHexDigitToInt('b')); - EXPECT_EQ(12, SpdyHexDigitToInt('c')); - EXPECT_EQ(13, SpdyHexDigitToInt('d')); - EXPECT_EQ(14, SpdyHexDigitToInt('e')); - EXPECT_EQ(15, SpdyHexDigitToInt('f')); - - EXPECT_EQ(10, SpdyHexDigitToInt('A')); - EXPECT_EQ(11, SpdyHexDigitToInt('B')); - EXPECT_EQ(12, SpdyHexDigitToInt('C')); - EXPECT_EQ(13, SpdyHexDigitToInt('D')); - EXPECT_EQ(14, SpdyHexDigitToInt('E')); - EXPECT_EQ(15, SpdyHexDigitToInt('F')); -} - -TEST(SpdyStringUtilsTest, SpdyHexDecodeToUInt32) { - uint32_t out; - EXPECT_TRUE(SpdyHexDecodeToUInt32("0", &out)); - EXPECT_EQ(0u, out); - EXPECT_TRUE(SpdyHexDecodeToUInt32("00", &out)); - EXPECT_EQ(0u, out); - EXPECT_TRUE(SpdyHexDecodeToUInt32("0000000", &out)); - EXPECT_EQ(0u, out); - EXPECT_TRUE(SpdyHexDecodeToUInt32("00000000", &out)); - EXPECT_EQ(0u, out); - EXPECT_TRUE(SpdyHexDecodeToUInt32("1", &out)); - EXPECT_EQ(1u, out); - EXPECT_TRUE(SpdyHexDecodeToUInt32("ffffFFF", &out)); - EXPECT_EQ(0xFFFFFFFu, out); - EXPECT_TRUE(SpdyHexDecodeToUInt32("fFfFffFf", &out)); - EXPECT_EQ(0xFFFFFFFFu, out); - EXPECT_TRUE(SpdyHexDecodeToUInt32("01AEF", &out)); - EXPECT_EQ(0x1AEFu, out); - EXPECT_TRUE(SpdyHexDecodeToUInt32("abcde", &out)); - EXPECT_EQ(0xABCDEu, out); - - EXPECT_FALSE(SpdyHexDecodeToUInt32("", &out)); - EXPECT_FALSE(SpdyHexDecodeToUInt32("111111111", &out)); - EXPECT_FALSE(SpdyHexDecodeToUInt32("1111111111", &out)); - EXPECT_FALSE(SpdyHexDecodeToUInt32("0x1111", &out)); -} - -TEST(SpdyStringUtilsTest, SpdyHexEncode) { - unsigned char bytes[] = {0x01, 0xff, 0x02, 0xfe, 0x03, 0x80, 0x81}; - EXPECT_EQ("01ff02fe038081", - SpdyHexEncode(reinterpret_cast<char*>(bytes), sizeof(bytes))); -} - -} // namespace -} // namespace test -} // namespace spdy diff --git a/chromium/net/third_party/quiche/src/spdy/platform/api/spdy_test_helpers.h b/chromium/net/third_party/quiche/src/spdy/platform/api/spdy_test_helpers.h deleted file mode 100644 index 367d330b6c9..00000000000 --- a/chromium/net/third_party/quiche/src/spdy/platform/api/spdy_test_helpers.h +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef QUICHE_SPDY_PLATFORM_API_SPDY_TEST_HELPERS_H_ -#define QUICHE_SPDY_PLATFORM_API_SPDY_TEST_HELPERS_H_ - -#include "net/spdy/platform/impl/spdy_test_helpers_impl.h" - -#define EXPECT_SPDY_BUG EXPECT_SPDY_BUG_IMPL - -#endif // QUICHE_SPDY_PLATFORM_API_SPDY_TEST_HELPERS_H_ diff --git a/chromium/net/third_party/uri_template/DIR_METADATA b/chromium/net/third_party/uri_template/DIR_METADATA index 23af0ebe901..c56cf205cc7 100644 --- a/chromium/net/third_party/uri_template/DIR_METADATA +++ b/chromium/net/third_party/uri_template/DIR_METADATA @@ -1,10 +1,10 @@ # Metadata information for this directory. # # For more information on DIR_METADATA files, see: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md # # For the schema of this file, see Metadata message: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto monorail { component: "Internals>Network>DNS" |